From: John Linn <John.Linn@xilinx.com>
To: "Richard Röjfors" <richard.rojfors@mocean-labs.com>
Cc: spi-devel-general@lists.sourceforge.net,
Andrew Morton <akpm@linux-foundation.org>,
dbrownell@users.sourceforge.net, linuxppc-dev@ozlabs.org
Subject: RE: [PATCH v3] xilinx_spi: Splitted into generic, of and platform driver, added support for DS570
Date: Wed, 23 Sep 2009 16:44:56 -0600 [thread overview]
Message-ID: <20090923224452.EAAFEB48046@mail109-sin.bigfish.com> (raw)
In-Reply-To: <4AB948AB.8080002@mocean-labs.com>
> -----Original Message-----
> From: Richard R=F6jfors [mailto:richard.rojfors@mocean-labs.com]
> Sent: Tuesday, September 22, 2009 3:59 PM
> To: John Linn
> Cc: spi-devel-general@lists.sourceforge.net; linuxppc-dev@ozlabs.org; And=
rew Morton;
> dbrownell@users.sourceforge.net
> Subject: Re: [PATCH v3] xilinx_spi: Splitted into generic, of and platfor=
m driver, added support for
> DS570
> =
> John Linn wrote:
> >> -----Original Message-----
> >> From: linuxppc-dev-bounces+john.linn=3Dxilinx.com@lists.ozlabs.org [ma=
ilto:linuxppc-dev-
> >> bounces+john.linn=3Dxilinx.com@lists.ozlabs.org] On Behalf Of Richard =
R=F6jfors
> >> Sent: Tuesday, September 22, 2009 6:55 AM
> >> To: spi-devel-general@lists.sourceforge.net
> >> Cc: linuxppc-dev@ozlabs.org; Andrew Morton; dbrownell@users.sourceforg=
e.net
> >> Subject: [PATCH v3] xilinx_spi: Splitted into generic, of and platform=
driver, added support for
> >> DS570
> >>
> >> This patch splits xilinx_spi into three parts, an OF and a platform
> >> driver and generic part.
> >>
> >> The generic part now also works on X86 and also supports the Xilinx
> >> SPI IP DS570
> >
> > Hi Richard,
> =
> Hi John,
> =
> >
> > The current driver (without this change) works for the newer XPS SPI de=
vice already as I run tests
> on it each day using an SPI EEPROM.
> =
> I'm not an expert of the Xilinx SPI blocks, I have only used one, the DS5=
70.
> =
> I don't think you use the DS570. I don't have the datasheet of the older =
one, but the register
> offsets of the DS570 don't match the driver you are using. All the regist=
ers of the DS570 are at 4
> bytes boundries.
> =
I just verified that I am using the same IP block as you are, the DS570. Bu=
t I'm not testing on the other IP you mention, the DS464.
> For instance the Status register of the code (DS464 is at offset 0x67), w=
hile the "Xilinx DS570 XPS
> Serial Peripheral Interface (SPI) (v2.00b), Data Sheet", clearly specifie=
s that the Status register
> offset of the DS570 is 0x64, which also matches the FPGA IP we run.
> =
> >
> > Do you think that's not the case, or it doesn't work for some other typ=
e of devices that I'm not
> testing with?
Did you test with some SPI device that didn't work as I'm using it with an =
SPI EEPROM?
> =
> I think you use some other IP block. Could that be the case?
> =
> >
> > I'll hold off commenting on the rest of the code changes for a bit.
> >
> > Thanks,
> > John
> >
> >> Signed-off-by: Richard R=F6jfors <richard.rojfors.ext@mocean-labs.com>=
> >> ---
> >> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> >> index 2c733c2..eca491b 100644
> >> --- a/drivers/spi/Kconfig
> >> +++ b/drivers/spi/Kconfig
> >> @@ -218,8 +218,8 @@ config SPI_TXX9
> >> SPI driver for Toshiba TXx9 MIPS SoCs
> >>
> >> config SPI_XILINX
> >> - tristate "Xilinx SPI controller"
> >> - depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
> >> + tristate "Xilinx SPI controller common module"
> >> + depends on (XILINX_VIRTEX || MICROBLAZE || HAS_IOMEM) && EXPERIMENTA=
L
> >> select SPI_BITBANG
> >> help
> >> This exposes the SPI controller IP from the Xilinx EDK.
> >> @@ -227,6 +227,22 @@ config SPI_XILINX
> >> See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
> >> Product Specification document (DS464) for hardware details.
> >>
> >> + Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.0=
0b)"
> >> +
> >> +
> >> +config SPI_XILINX_OF
> >> + tristate "Xilinx SPI controller OF device"
> >> + depends on SPI_XILINX && XILINX_VIRTEX
> >> + help
> >> + This is the OF driver for the SPI controller IP from the Xilinx ED=
K.
> >> +
> >> +config SPI_XILINX_PLTFM
> >> + tristate "Xilinx SPI controller platform device"
> >> + depends on SPI_XILINX
> >> + help
> >> + This is the platform driver for the SPI controller IP
> >> + from the Xilinx EDK.
> >> +
> >> #
> >> # Add new SPI master controllers in alphabetical order above this lin=
e
> >> #
> >> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> >> index 3de408d..5a91cf5 100644
> >> --- a/drivers/spi/Makefile
> >> +++ b/drivers/spi/Makefile
> >> @@ -30,6 +30,8 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) +=3D spi_s3c24xx_gpi=
o.o
> >> obj-$(CONFIG_SPI_S3C24XX) +=3D spi_s3c24xx.o
> >> obj-$(CONFIG_SPI_TXX9) +=3D spi_txx9.o
> >> obj-$(CONFIG_SPI_XILINX) +=3D xilinx_spi.o
> >> +obj-$(CONFIG_SPI_XILINX_OF) +=3D xilinx_spi_of.o
> >> +obj-$(CONFIG_SPI_XILINX_PLTFM) +=3D xilinx_spi_pltfm.o
> >> obj-$(CONFIG_SPI_SH_SCI) +=3D spi_sh_sci.o
> >> # ... add above this line ...
> >>
> >> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
> >> index 46b8c5c..0490820 100644
> >> --- a/drivers/spi/xilinx_spi.c
> >> +++ b/drivers/spi/xilinx_spi.c
> >> @@ -14,22 +14,103 @@
> >> #include <linux/module.h>
> >> #include <linux/init.h>
> >> #include <linux/interrupt.h>
> >> -#include <linux/platform_device.h>
> >> -
> >> -#include <linux/of_platform.h>
> >> -#include <linux/of_device.h>
> >> -#include <linux/of_spi.h>
> >>
> >> #include <linux/spi/spi.h>
> >> #include <linux/spi/spi_bitbang.h>
> >> #include <linux/io.h>
> >>
> >> -#define XILINX_SPI_NAME "xilinx_spi"
> >> +#include "xilinx_spi.h"
> >> +
> >> +struct xilinx_spi {
> >> + /* bitbang has to be first */
> >> + struct spi_bitbang bitbang;
> >> + struct completion done;
> >> + struct resource mem; /* phys mem */
> >> + void __iomem *regs; /* virt. address of the control registers */
> >> + u32 irq;
> >> + u8 *rx_ptr; /* pointer in the Tx buffer */
> >> + const u8 *tx_ptr; /* pointer in the Rx buffer */
> >> + int remaining_bytes; /* the number of bytes left to transfer */
> >> + /* offset to the XSPI regs, these might vary... */
> >> + u8 cr_offset;
> >> + u8 sr_offset;
> >> + u8 txd_offset;
> >> + u8 rxd_offset;
> >> + u8 ssr_offset;
> >> + u8 bits_per_word;
> >> + u8 model;
> >> +};
> >> +
> >> +#ifdef CONFIG_X86
> >> +/* on X86 the block often resides behind a PCI(e) interface which fli=
ps the
> >> + * endian from little to big
> >> + */
> >> +#define xspi_in8(addr) ioread8(addr)
> >> +#define xspi_in16(addr) ioread16(addr)
> >> +#define xspi_in32(addr) ioread32(addr)
> >> +
> >> +#define xspi_out8(addr, b) iowrite8(b, addr)
> >> +#define xspi_out16(addr, w) iowrite16(w, addr)
> >> +#define xspi_out32(addr, l) iowrite32(l, addr)
> >> +#else
> >> +/* While on for instance PPC we use big endian */
> >> +#define xspi_in8(addr) in_8(addr)
> >> +#define xspi_in16(addr) in_be16(addr)
> >> +#define xspi_in32(addr) in_be32(addr)
> >> +
> >> +#define xspi_out8(addr, b) out_8(addr, b)
> >> +#define xspi_out16(addr, w) out_be16(addr, w)
> >> +#define xspi_out32(addr, l) out_be32(addr, l)
> >> +#endif
> >> +
> >> +
> >> +static inline void xspi_write8(struct xilinx_spi *xspi, u32 offs, u8 =
val)
> >> +{
> >> + if (xspi->model =3D=3D XILINX_SPI_MODEL_DS464)
> >> + xspi_out8(xspi->regs + offs, val & 0xff);
> >> + else
> >> + xspi_out32(xspi->regs + offs, val);
> >> +}
> >> +
> >> +static inline void xspi_write16(struct xilinx_spi *xspi, u32 offs, u1=
6 val)
> >> +{
> >> + if (xspi->model =3D=3D XILINX_SPI_MODEL_DS464)
> >> + xspi_out16(xspi->regs + offs, val & 0xffff);
> >> + else
> >> + xspi_out32(xspi->regs + offs, val);
> >> +}
> >> +
> >> +static inline void xspi_write32(struct xilinx_spi *xspi, u32 offs, u3=
2 val)
> >> +{
> >> + xspi_out32(xspi->regs + offs, val);
> >> +}
> >> +
> >> +static inline u8 xspi_read8(struct xilinx_spi *xspi, u32 offs)
> >> +{
> >> + if (xspi->model =3D=3D XILINX_SPI_MODEL_DS464)
> >> + return xspi_in8(xspi->regs + offs);
> >> + else
> >> + return xspi_in32(xspi->regs + offs);
> >> +}
> >> +
> >> +static inline u16 xspi_read16(struct xilinx_spi *xspi, u32 offs)
> >> +{
> >> + if (xspi->model =3D=3D XILINX_SPI_MODEL_DS464)
> >> + return xspi_in16(xspi->regs + offs);
> >> + else
> >> + return xspi_in32(xspi->regs + offs);
> >> +}
> >> +
> >> +static inline u32 xspi_read32(struct xilinx_spi *xspi, u32 offs)
> >> +{
> >> + return xspi_in32(xspi->regs + offs);
> >> +}
> >>
> >> /* Register definitions as per "OPB Serial Peripheral Interface (SPI)=
(v1.00e)
> >> * Product Specification", DS464
> >> */
> >> -#define XSPI_CR_OFFSET 0x62 /* 16-bit Control Register */
> >> +#define XSPI_CR_OFFSET_DS464 0x62 /* 16-bit Control Register */
> >> +#define XSPI_CR_OFFSET_DS570 0x60
> >>
> >> #define XSPI_CR_ENABLE 0x02
> >> #define XSPI_CR_MASTER_MODE 0x04
> >> @@ -40,8 +121,10 @@
> >> #define XSPI_CR_RXFIFO_RESET 0x40
> >> #define XSPI_CR_MANUAL_SSELECT 0x80
> >> #define XSPI_CR_TRANS_INHIBIT 0x100
> >> +#define XSPI_CR_LSB_FIRST 0x200
> >>
> >> -#define XSPI_SR_OFFSET 0x67 /* 8-bit Status Register */
> >> +#define XSPI_SR_OFFSET_DS464 0x67 /* 8-bit Status Register */
> >> +#define XSPI_SR_OFFSET_DS570 0x64
> >>
> >> #define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
> >> #define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
> >> @@ -49,10 +132,13 @@
> >> #define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */
> >> #define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */
> >>
> >> -#define XSPI_TXD_OFFSET 0x6b /* 8-bit Data Transmit Register */
> >> -#define XSPI_RXD_OFFSET 0x6f /* 8-bit Data Receive Register */
> >> +#define XSPI_TXD_OFFSET_DS464 0x6b /* 8-bit Data Transmit Register */=
> >> +#define XSPI_TXD_OFFSET_DS570 0x68
> >> +#define XSPI_RXD_OFFSET_DS464 0x6f /* 8-bit Data Receive Register */
> >> +#define XSPI_RXD_OFFSET_DS570 0x6C
> >>
> >> -#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
> >> +#define XSPI_SSR_OFFSET_DS464 0x70 /* 32-bit Slave Select Register */=
> >> +#define XSPI_SSR_OFFSET_DS570 0x70
> >>
> >> /* Register definitions as per "OPB IPIF (v3.01c) Product Specificati=
on", DS414
> >> * IPIF registers are 32 bit
> >> @@ -70,43 +156,27 @@
> >> #define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */
> >> #define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */
> >> #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_RESET_MASK 0x0a /* the value to write */
> >>
> >> -struct xilinx_spi {
> >> - /* bitbang has to be first */
> >> - struct spi_bitbang bitbang;
> >> - struct completion done;
> >> -
> >> - void __iomem *regs; /* virt. address of the control registers */
> >> -
> >> - u32 irq;
> >> -
> >> - u32 speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
> >> -
> >> - u8 *rx_ptr; /* pointer in the Tx buffer */
> >> - const u8 *tx_ptr; /* pointer in the Rx buffer */
> >> - int remaining_bytes; /* the number of bytes left to transfer */
> >> -};
> >> -
> >> -static void xspi_init_hw(void __iomem *regs_base)
> >> +static void xspi_init_hw(struct xilinx_spi *xspi)
> >> {
> >> /* Reset the SPI device */
> >> - out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
> >> - XIPIF_V123B_RESET_MASK);
> >> + xspi_write32(xspi, XIPIF_V123B_RESETR_OFFSET, XIPIF_V123B_RESET_MASK=
);
> >> /* Disable all the interrupts just in case */
> >> - out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
> >> + xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET, 0);
> >> /* Enable the global IPIF interrupt */
> >> - out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
> >> - XIPIF_V123B_GINTR_ENABLE);
> >> + xspi_write32(xspi, XIPIF_V123B_DGIER_OFFSET, XIPIF_V123B_GINTR_ENABL=
E);
> >> /* Deselect the slave on the SPI bus */
> >> - out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
> >> + xspi_write32(xspi, xspi->ssr_offset, 0xffff);
> >> /* Disable the transmitter, enable Manual Slave Select Assertion,
> >> * put SPI controller into master mode, and enable it */
> >> - out_be16(regs_base + XSPI_CR_OFFSET,
> >> - XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
> >> - | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
> >> + xspi_write16(xspi, xspi->cr_offset,
> >> + XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
> >> + XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |
> >> + XSPI_CR_RXFIFO_RESET);
> >> }
> >>
> >> static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
> >> @@ -115,16 +185,16 @@ static void xilinx_spi_chipselect(struct spi_dev=
ice *spi, int is_on)
> >>
> >> if (is_on =3D=3D BITBANG_CS_INACTIVE) {
> >> /* Deselect the slave on the SPI bus */
> >> - out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
> >> + xspi_write32(xspi, xspi->ssr_offset, 0xffff);
> >> } else if (is_on =3D=3D BITBANG_CS_ACTIVE) {
> >> /* Set the SPI clock phase and polarity */
> >> - u16 cr =3D in_be16(xspi->regs + XSPI_CR_OFFSET)
> >> + u32 cr =3D xspi_read16(xspi, xspi->cr_offset)
> >> & ~XSPI_CR_MODE_MASK;
> >> if (spi->mode & SPI_CPHA)
> >> cr |=3D XSPI_CR_CPHA;
> >> if (spi->mode & SPI_CPOL)
> >> cr |=3D XSPI_CR_CPOL;
> >> - out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
> >> + xspi_write16(xspi, xspi->cr_offset, cr);
> >>
> >> /* We do not check spi->max_speed_hz here as the SPI clock
> >> * frequency is not software programmable (the IP block design
> >> @@ -132,24 +202,27 @@ static void xilinx_spi_chipselect(struct spi_dev=
ice *spi, int is_on)
> >> */
> >>
> >> /* Activate the chip select */
> >> - out_be32(xspi->regs + XSPI_SSR_OFFSET,
> >> + xspi_write32(xspi, xspi->ssr_offset,
> >> ~(0x0001 << spi->chip_select));
> >> }
> >> }
> >>
> >> /* spi_bitbang requires custom setup_transfer() to be defined if ther=
e is a
> >> * custom txrx_bufs(). We have nothing to setup here as the SPI IP bl=
ock
> >> - * supports just 8 bits per word, and SPI clock can't be changed in s=
oftware.
> >> - * Check for 8 bits per word. Chip select delay calculations could be=
> >> + * supports 8 or 16 bits per word, which can not be changed in softwa=
re.
> >> + * SPI clock can't be changed in software.
> >> + * Check for correct bits per word. Chip select delay calculations co=
uld be
> >> * added here as soon as bitbang_work() can be made aware of the dela=
y value.
> >> */
> >> static int xilinx_spi_setup_transfer(struct spi_device *spi,
> >> - struct spi_transfer *t)
> >> + struct spi_transfer *t)
> >> {
> >> u8 bits_per_word;
> >> + struct xilinx_spi *xspi =3D spi_master_get_devdata(spi->master);
> >>
> >> - bits_per_word =3D (t) ? t->bits_per_word : spi->bits_per_word;
> >> - if (bits_per_word !=3D 8) {
> >> + bits_per_word =3D (t->bits_per_word) ? t->bits_per_word :
> >> + spi->bits_per_word;
> >> + if (bits_per_word !=3D xspi->bits_per_word) {
> >> dev_err(&spi->dev, "%s, unsupported bits_per_word=3D%d\n",
> >> __func__, bits_per_word);
> >> return -EINVAL;
> >> @@ -160,34 +233,50 @@ static int xilinx_spi_setup_transfer(struct spi_=
device *spi,
> >>
> >> static int xilinx_spi_setup(struct spi_device *spi)
> >> {
> >> - struct spi_bitbang *bitbang;
> >> - struct xilinx_spi *xspi;
> >> - int retval;
> >> -
> >> - xspi =3D spi_master_get_devdata(spi->master);
> >> - bitbang =3D &xspi->bitbang;
> >> -
> >> - retval =3D xilinx_spi_setup_transfer(spi, NULL);
> >> - if (retval < 0)
> >> - return retval;
> >> -
> >> + /* always return 0, we can not check the number of bits.
> >> + * There are cases when SPI setup is called before any driver is
> >> + * 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
> >> + * SPI device would not be registered and no driver can get hold of =
it
> >> + * When the driver is there, it will call SPI setup again with the
> >> + * correct number of bits per transfer.
> >> + * If a driver setups with the wrong bit number, it will fail when
> >> + * it tries to do a transfer
> >> + */
> >> return 0;
> >> }
> >>
> >> static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
> >> {
> >> - u8 sr;
> >> + u32 sr;
> >> + u8 wsize;
> >> + if (xspi->bits_per_word =3D=3D 8)
> >> + wsize =3D 1;
> >> + else if (xspi->bits_per_word =3D=3D 16)
> >> + wsize =3D 2;
> >> + else
> >> + wsize =3D 4;
> >>
> >> /* Fill the Tx FIFO with as many bytes as possible */
> >> - sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> >> - while ((sr & XSPI_SR_TX_FULL_MASK) =3D=3D 0 && xspi->remaining_bytes=
> 0) {
> >> + sr =3D xspi_read8(xspi, xspi->sr_offset);
> >> + while ((sr & XSPI_SR_TX_FULL_MASK) =3D=3D 0 &&
> >> + xspi->remaining_bytes > 0) {
> >> if (xspi->tx_ptr) {
> >> - out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
> >> - } else {
> >> - out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
> >> - }
> >> - xspi->remaining_bytes--;
> >> - sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> >> + if (wsize =3D=3D 1)
> >> + xspi_write8(xspi, xspi->txd_offset,
> >> + *xspi->tx_ptr);
> >> + else if (wsize =3D=3D 2)
> >> + xspi_write16(xspi, xspi->txd_offset,
> >> + *(u16 *)(xspi->tx_ptr));
> >> + else if (wsize =3D=3D 4)
> >> + xspi_write32(xspi, xspi->txd_offset,
> >> + *(u32 *)(xspi->tx_ptr));
> >> +
> >> + xspi->tx_ptr +=3D wsize;
> >> + } else
> >> + xspi_write8(xspi, xspi->txd_offset, 0);
> >> + xspi->remaining_bytes -=3D wsize;
> >> + sr =3D xspi_read8(xspi, xspi->sr_offset);
> >> }
> >> }
> >>
> >> @@ -195,7 +284,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device =
*spi, struct spi_transfer
> *t)
> >> {
> >> struct xilinx_spi *xspi =3D spi_master_get_devdata(spi->master);
> >> u32 ipif_ier;
> >> - u16 cr;
> >> + u32 cr;
> >>
> >> /* We get here with transmitter inhibited */
> >>
> >> @@ -209,23 +298,22 @@ static int xilinx_spi_txrx_bufs(struct spi_devic=
e *spi, struct spi_transfer
> *t)
> >> /* Enable the transmit empty interrupt, which we use to determine
> >> * progress on the transmission.
> >> */
> >> - ipif_ier =3D in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
> >> - out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
> >> + ipif_ier =3D xspi_read32(xspi, XIPIF_V123B_IIER_OFFSET);
> >> + xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET,
> >> ipif_ier | XSPI_INTR_TX_EMPTY);
> >>
> >> /* Start the transfer by not inhibiting the transmitter any longer *=
/
> >> - cr =3D in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT=
;
> >> - out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
> >> + cr =3D xspi_read16(xspi, xspi->cr_offset) & ~XSPI_CR_TRANS_INHIBIT;
> >> + xspi_write16(xspi, xspi->cr_offset, cr);
> >>
> >> wait_for_completion(&xspi->done);
> >>
> >> /* Disable the transmit empty interrupt */
> >> - out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
> >> + xspi_write32(xspi, XIPIF_V123B_IIER_OFFSET, ipif_ier);
> >>
> >> return t->len - xspi->remaining_bytes;
> >> }
> >>
> >> -
> >> /* This driver supports single master mode only. Hence Tx FIFO Empty
> >> * is the only interrupt we care about.
> >> * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slav=
e Mode
> >> @@ -237,32 +325,50 @@ static irqreturn_t xilinx_spi_irq(int irq, void =
*dev_id)
> >> u32 ipif_isr;
> >>
> >> /* Get the IPIF interrupts, and clear them immediately */
> >> - ipif_isr =3D in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
> >> - out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
> >> + ipif_isr =3D xspi_read32(xspi, XIPIF_V123B_IISR_OFFSET);
> >> + xspi_write32(xspi, XIPIF_V123B_IISR_OFFSET, ipif_isr);
> >>
> >> if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
> >> - u16 cr;
> >> - u8 sr;
> >> + u32 cr;
> >> + u32 sr;
> >> + u8 rsize;
> >> + if (xspi->bits_per_word =3D=3D 8)
> >> + rsize =3D 1;
> >> + else if (xspi->bits_per_word =3D=3D 16)
> >> + rsize =3D 2;
> >> + else
> >> + rsize =3D 4;
> >>
> >> /* A transmit has just completed. Process received data and
> >> * check for more data to transmit. Always inhibit the
> >> * transmitter while the Isr refills the transmit register/FIFO,
> >> * or make sure it is stopped if we're done.
> >> */
> >> - cr =3D in_be16(xspi->regs + XSPI_CR_OFFSET);
> >> - out_be16(xspi->regs + XSPI_CR_OFFSET,
> >> - cr | XSPI_CR_TRANS_INHIBIT);
> >> + cr =3D xspi_read16(xspi, xspi->cr_offset);
> >> + xspi_write16(xspi, xspi->cr_offset, cr | XSPI_CR_TRANS_INHIBIT);
> >>
> >> /* Read out all the data from the Rx FIFO */
> >> - sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> >> + sr =3D xspi_read8(xspi, xspi->sr_offset);
> >> while ((sr & XSPI_SR_RX_EMPTY_MASK) =3D=3D 0) {
> >> - u8 data;
> >> + u32 data;
> >> + if (rsize =3D=3D 1)
> >> + data =3D xspi_read8(xspi, xspi->rxd_offset);
> >> + else if (rsize =3D=3D 2)
> >> + data =3D xspi_read16(xspi, xspi->rxd_offset);
> >> + else
> >> + data =3D xspi_read32(xspi, xspi->rxd_offset);
> >>
> >> - data =3D in_8(xspi->regs + XSPI_RXD_OFFSET);
> >> if (xspi->rx_ptr) {
> >> - *xspi->rx_ptr++ =3D data;
> >> + if (rsize =3D=3D 1)
> >> + *xspi->rx_ptr =3D data & 0xff;
> >> + else if (rsize =3D=3D 2)
> >> + *(u16 *)(xspi->rx_ptr) =3D data & 0xffff;
> >> + else
> >> + *((u32 *)(xspi->rx_ptr)) =3D data;
> >> + xspi->rx_ptr +=3D rsize;
> >> }
> >> - sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> >> +
> >> + sr =3D xspi_read8(xspi, xspi->sr_offset);
> >> }
> >>
> >> /* See if there is more data to send */
> >> @@ -271,7 +377,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *d=
ev_id)
> >> /* Start the transfer by not inhibiting the
> >> * transmitter any longer
> >> */
> >> - out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
> >> + xspi_write16(xspi, xspi->cr_offset, cr);
> >> } else {
> >> /* No more data to send.
> >> * Indicate the transfer is completed.
> >> @@ -279,44 +385,20 @@ static irqreturn_t xilinx_spi_irq(int irq, void =
*dev_id)
> >> complete(&xspi->done);
> >> }
> >> }
> >> -
> >> return IRQ_HANDLED;
> >> }
> >>
> >> -static int __init xilinx_spi_of_probe(struct of_device *ofdev,
> >> - const struct of_device_id *match)
> >> +struct spi_master *xilinx_spi_init(struct device *dev, struct resourc=
e *mem,
> >> + u32 irq, u8 model, s16 bus_num, u16 num_chipselect, u8 bits_per_word=
)
> >> {
> >> struct spi_master *master;
> >> struct xilinx_spi *xspi;
> >> - struct resource r_irq_struct;
> >> - struct resource r_mem_struct;
> >> + int ret =3D 0;
> >>
> >> - struct resource *r_irq =3D &r_irq_struct;
> >> - struct resource *r_mem =3D &r_mem_struct;
> >> - int rc =3D 0;
> >> - const u32 *prop;
> >> - int len;
> >> + master =3D spi_alloc_master(dev, sizeof(struct xilinx_spi));
> >>
> >> - /* Get resources(memory, IRQ) associated with the device */
> >> - master =3D spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi));=
> >> -
> >> - if (master =3D=3D NULL) {
> >> - return -ENOMEM;
> >> - }
> >> -
> >> - dev_set_drvdata(&ofdev->dev, master);
> >> -
> >> - rc =3D of_address_to_resource(ofdev->node, 0, r_mem);
> >> - if (rc) {
> >> - dev_warn(&ofdev->dev, "invalid address\n");
> >> - goto put_master;
> >> - }
> >> -
> >> - rc =3D of_irq_to_resource(ofdev->node, 0, r_irq);
> >> - if (rc =3D=3D NO_IRQ) {
> >> - dev_warn(&ofdev->dev, "no IRQ found\n");
> >> - goto put_master;
> >> - }
> >> + if (master =3D=3D NULL)
> >> + return ERR_PTR(-ENOMEM);
> >>
> >> /* the spi->mode bits understood by this driver: */
> >> master->mode_bits =3D SPI_CPOL | SPI_CPHA;
> >> @@ -329,128 +411,87 @@ static int __init xilinx_spi_of_probe(struct of=
_device *ofdev,
> >> xspi->bitbang.master->setup =3D xilinx_spi_setup;
> >> init_completion(&xspi->done);
> >>
> >> - xspi->irq =3D r_irq->start;
> >> -
> >> - if (!request_mem_region(r_mem->start,
> >> - r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) {
> >> - rc =3D -ENXIO;
> >> - dev_warn(&ofdev->dev, "memory request failure\n");
> >> + if (!request_mem_region(mem->start, resource_size(mem),
> >> + XILINX_SPI_NAME)) {
> >> + ret =3D -ENXIO;
> >> goto put_master;
> >> }
> >>
> >> - xspi->regs =3D ioremap(r_mem->start, r_mem->end - r_mem->start + 1);=
> >> + xspi->regs =3D ioremap(mem->start, resource_size(mem));
> >> if (xspi->regs =3D=3D NULL) {
> >> - rc =3D -ENOMEM;
> >> - dev_warn(&ofdev->dev, "ioremap failure\n");
> >> - goto release_mem;
> >> + ret =3D -ENOMEM;
> >> + dev_warn(dev, "ioremap failure\n");
> >> + goto map_failed;
> >> }
> >> - xspi->irq =3D r_irq->start;
> >> -
> >> - /* dynamic bus assignment */
> >> - master->bus_num =3D -1;
> >>
> >> - /* number of slave select bits is required */
> >> - prop =3D of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
> >> - if (!prop || len < sizeof(*prop)) {
> >> - dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
> >> - goto unmap_io;
> >> + master->bus_num =3D bus_num;
> >> + master->num_chipselect =3D num_chipselect;
> >> +
> >> + xspi->mem =3D *mem;
> >> + xspi->irq =3D irq;
> >> + xspi->bits_per_word =3D bits_per_word;
> >> + xspi->model =3D model;
> >> +
> >> + if (model =3D=3D XILINX_SPI_MODEL_DS464) {
> >> + xspi->cr_offset =3D XSPI_CR_OFFSET_DS464;
> >> + xspi->sr_offset =3D XSPI_SR_OFFSET_DS464;
> >> + xspi->txd_offset =3D XSPI_TXD_OFFSET_DS464;
> >> + xspi->rxd_offset =3D XSPI_RXD_OFFSET_DS464;
> >> + xspi->ssr_offset =3D XSPI_SSR_OFFSET_DS464;
> >> + } else {
> >> + xspi->cr_offset =3D XSPI_CR_OFFSET_DS570;
> >> + xspi->sr_offset =3D XSPI_SR_OFFSET_DS570;
> >> + xspi->txd_offset =3D XSPI_TXD_OFFSET_DS570;
> >> + xspi->rxd_offset =3D XSPI_RXD_OFFSET_DS570;
> >> + xspi->ssr_offset =3D XSPI_SSR_OFFSET_DS570;
> >> }
> >> - master->num_chipselect =3D *prop;
> >>
> >> /* SPI controller initializations */
> >> - xspi_init_hw(xspi->regs);
> >> + xspi_init_hw(xspi);
> >>
> >> /* Register for SPI Interrupt */
> >> - rc =3D request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xs=
pi);
> >> - if (rc !=3D 0) {
> >> - dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq);
> >> + ret =3D request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, x=
spi);
> >> + if (ret !=3D 0)
> >> goto unmap_io;
> >> - }
> >>
> >> - rc =3D spi_bitbang_start(&xspi->bitbang);
> >> - if (rc !=3D 0) {
> >> - dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n");
> >> + ret =3D spi_bitbang_start(&xspi->bitbang);
> >> + if (ret !=3D 0) {
> >> + dev_err(dev, "spi_bitbang_start FAILED\n");
> >> goto free_irq;
> >> }
> >>
> >> - dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=3D%d\n",
> >> - (unsigned int)r_mem->start, (u32)xspi->regs, xspi->irq);
> >> -
> >> - /* Add any subnodes on the SPI bus */
> >> - of_register_spi_devices(master, ofdev->node);
> >> -
> >> - return rc;
> >> + dev_info(dev, "at 0x%08X mapped to 0x%08X, irq=3D%d\n",
> >> + (u32)mem->start, (u32)xspi->regs, xspi->irq);
> >> + return master;
> >>
> >> free_irq:
> >> free_irq(xspi->irq, xspi);
> >> unmap_io:
> >> iounmap(xspi->regs);
> >> -release_mem:
> >> - release_mem_region(r_mem->start, resource_size(r_mem));
> >> +map_failed:
> >> + release_mem_region(mem->start, resource_size(mem));
> >> put_master:
> >> spi_master_put(master);
> >> - return rc;
> >> + return ERR_PTR(ret);
> >> }
> >> +EXPORT_SYMBOL(xilinx_spi_init);
> >>
> >> -static int __devexit xilinx_spi_remove(struct of_device *ofdev)
> >> +void xilinx_spi_deinit(struct spi_master *master)
> >> {
> >> struct xilinx_spi *xspi;
> >> - struct spi_master *master;
> >> - struct resource r_mem;
> >>
> >> - master =3D platform_get_drvdata(ofdev);
> >> xspi =3D spi_master_get_devdata(master);
> >>
> >> spi_bitbang_stop(&xspi->bitbang);
> >> free_irq(xspi->irq, xspi);
> >> iounmap(xspi->regs);
> >> - if (!of_address_to_resource(ofdev->node, 0, &r_mem))
> >> - release_mem_region(r_mem.start, resource_size(&r_mem));
> >> - dev_set_drvdata(&ofdev->dev, 0);
> >> - spi_master_put(xspi->bitbang.master);
> >> -
> >> - return 0;
> >> -}
> >> -
> >> -/* work with hotplug and coldplug */
> >> -MODULE_ALIAS("platform:" XILINX_SPI_NAME);
> >> -
> >> -static int __exit xilinx_spi_of_remove(struct of_device *op)
> >> -{
> >> - return xilinx_spi_remove(op);
> >> -}
> >> -
> >> -static struct of_device_id xilinx_spi_of_match[] =3D {
> >> - { .compatible =3D "xlnx,xps-spi-2.00.a", },
> >> - { .compatible =3D "xlnx,xps-spi-2.00.b", },
> >> - {}
> >> -};
> >> -
> >> -MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
> >> -
> >> -static struct of_platform_driver xilinx_spi_of_driver =3D {
> >> - .owner =3D THIS_MODULE,
> >> - .name =3D "xilinx-xps-spi",
> >> - .match_table =3D xilinx_spi_of_match,
> >> - .probe =3D xilinx_spi_of_probe,
> >> - .remove =3D __exit_p(xilinx_spi_of_remove),
> >> - .driver =3D {
> >> - .name =3D "xilinx-xps-spi",
> >> - .owner =3D THIS_MODULE,
> >> - },
> >> -};
> >>
> >> -static int __init xilinx_spi_init(void)
> >> -{
> >> - return of_register_platform_driver(&xilinx_spi_of_driver);
> >> + release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
> >> + spi_master_put(xspi->bitbang.master);
> >> }
> >> -module_init(xilinx_spi_init);
> >> +EXPORT_SYMBOL(xilinx_spi_deinit);
> >>
> >> -static void __exit xilinx_spi_exit(void)
> >> -{
> >> - of_unregister_platform_driver(&xilinx_spi_of_driver);
> >> -}
> >> -module_exit(xilinx_spi_exit);
> >> MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
> >> MODULE_DESCRIPTION("Xilinx SPI driver");
> >> MODULE_LICENSE("GPL");
> >> +
> >> diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
> >> new file mode 100644
> >> index 0000000..d951b11
> >> --- /dev/null
> >> +++ b/drivers/spi/xilinx_spi.h
> >> @@ -0,0 +1,32 @@
> >> +/*
> >> + * xilinx_spi.h
> >> + * Copyright (c) 2009 Intel Corporation
> >> + *
> >> + * This program is free software; you can redistribute it and/or modi=
fy
> >> + * 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.
> >> + */
> >> +
> >> +#ifndef _XILINX_SPI_H_
> >> +#define _XILINX_SPI_H_ 1
> >> +
> >> +#include <linux/spi/spi.h>
> >> +#include <linux/spi/spi_bitbang.h>
> >> +#include <linux/spi/xilinx_spi.h>
> >> +
> >> +#define XILINX_SPI_NAME "xilinx_spi"
> >> +
> >> +struct spi_master *xilinx_spi_init(struct device *dev, struct resourc=
e *mem,
> >> + u32 irq, u8 model, s16 bus_num, u16 num_chipselect, u8 bits_per_word=
);
> >> +
> >> +void xilinx_spi_deinit(struct spi_master *master);
> >> +#endif
> >> diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c=
> >> new file mode 100644
> >> index 0000000..4f54ddd
> >> --- /dev/null
> >> +++ b/drivers/spi/xilinx_spi_of.c
> >> @@ -0,0 +1,120 @@
> >> +/*
> >> + * xilinx_spi_of.c
> >> + *
> >> + * Xilinx SPI controller driver (master mode only)
> >> + *
> >> + * Author: MontaVista Software, Inc.
> >> + * source@mvista.com
> >> + *
> >> + * 2002-2007 (c) MontaVista Software, Inc. This file is licensed und=
er the
> >> + * terms of the GNU General Public License version 2. This program i=
s licensed
> >> + * "as is" without any warranty of any kind, whether express or impli=
ed.
> >> + */
> >> +
> >> +#include <linux/module.h>
> >> +#include <linux/init.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/io.h>
> >> +#include <linux/platform_device.h>
> >> +
> >> +#include <linux/of_platform.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/of_spi.h>
> >> +
> >> +#include <linux/spi/spi.h>
> >> +#include <linux/spi/spi_bitbang.h>
> >> +
> >> +#include "xilinx_spi.h"
> >> +
> >> +
> >> +static int __init xilinx_spi_of_probe(struct of_device *ofdev,
> >> + const struct of_device_id *match)
> >> +{
> >> + struct resource r_irq_struct;
> >> + struct resource r_mem_struct;
> >> + struct spi_master *master;
> >> +
> >> + struct resource *r_irq =3D &r_irq_struct;
> >> + struct resource *r_mem =3D &r_mem_struct;
> >> + int rc =3D 0;
> >> + const u32 *prop;
> >> + int len;
> >> +
> >> + rc =3D of_address_to_resource(ofdev->node, 0, r_mem);
> >> + if (rc) {
> >> + dev_warn(&ofdev->dev, "invalid address\n");
> >> + return rc;
> >> + }
> >> +
> >> + rc =3D of_irq_to_resource(ofdev->node, 0, r_irq);
> >> + if (rc =3D=3D NO_IRQ) {
> >> + dev_warn(&ofdev->dev, "no IRQ found\n");
> >> + return -ENODEV;
> >> + }
> >> +
> >> + /* number of slave select bits is required */
> >> + prop =3D of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
> >> + if (!prop || len < sizeof(*prop)) {
> >> + dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
> >> + return -EINVAL;
> >> + }
> >> + master =3D xilinx_spi_init(&ofdev->dev, r_mem, r_irq->start,
> >> + XILINX_SPI_MODEL_DS464, -1, *prop, 8);
> >> + if (IS_ERR(master))
> >> + return PTR_ERR(master);
> >> +
> >> + dev_set_drvdata(&ofdev->dev, master);
> >> +
> >> + /* Add any subnodes on the SPI bus */
> >> + of_register_spi_devices(master, ofdev->node);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int __devexit xilinx_spi_remove(struct of_device *ofdev)
> >> +{
> >> + xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
> >> + dev_set_drvdata(&ofdev->dev, 0);
> >> + return 0;
> >> +}
> >> +
> >> +static int __exit xilinx_spi_of_remove(struct of_device *op)
> >> +{
> >> + return xilinx_spi_remove(op);
> >> +}
> >> +
> >> +static struct of_device_id xilinx_spi_of_match[] =3D {
> >> + { .compatible =3D "xlnx,xps-spi-2.00.a", },
> >> + { .compatible =3D "xlnx,xps-spi-2.00.b", },
> >> + {}
> >> +};
> >> +
> >> +MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
> >> +
> >> +static struct of_platform_driver xilinx_spi_of_driver =3D {
> >> + .owner =3D THIS_MODULE,
> >> + .name =3D "xilinx-xps-spi",
> >> + .match_table =3D xilinx_spi_of_match,
> >> + .probe =3D xilinx_spi_of_probe,
> >> + .remove =3D __exit_p(xilinx_spi_of_remove),
> >> + .driver =3D {
> >> + .name =3D "xilinx-xps-spi",
> >> + .owner =3D THIS_MODULE,
> >> + },
> >> +};
> >> +
> >> +static int __init xilinx_spi_of_init(void)
> >> +{
> >> + return of_register_platform_driver(&xilinx_spi_of_driver);
> >> +}
> >> +module_init(xilinx_spi_of_init);
> >> +
> >> +static void __exit xilinx_spi_of_exit(void)
> >> +{
> >> + of_unregister_platform_driver(&xilinx_spi_of_driver);
> >> +}
> >> +module_exit(xilinx_spi_of_exit);
> >> +MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
> >> +MODULE_DESCRIPTION("Xilinx SPI driver");
> >> +MODULE_LICENSE("GPL");
> >> +
> >> diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_p=
ltfm.c
> >> new file mode 100644
> >> index 0000000..d59d509
> >> --- /dev/null
> >> +++ b/drivers/spi/xilinx_spi_pltfm.c
> >> @@ -0,0 +1,104 @@
> >> +/*
> >> + * xilinx_spi_pltfm.c Support for Xilinx SPI platform devices
> >> + * Copyright (c) 2009 Intel Corporation
> >> + *
> >> + * This program is free software; you can redistribute it and/or modi=
fy
> >> + * 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.
> >> + */
> >> +
> >> +/* Supports:
> >> + * Xilinx SPI devices as platform devices
> >> + *
> >> + * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
> >> + */
> >> +
> >> +#include <linux/module.h>
> >> +#include <linux/init.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/io.h>
> >> +#include <linux/platform_device.h>
> >> +
> >> +#include <linux/spi/spi.h>
> >> +#include <linux/spi/spi_bitbang.h>
> >> +#include <linux/spi/xilinx_spi.h>
> >> +
> >> +#include "xilinx_spi.h"
> >> +
> >> +static int __devinit xilinx_spi_probe(struct platform_device *dev)
> >> +{
> >> + struct xspi_platform_data *pdata;
> >> + struct resource *r;
> >> + int irq;
> >> + struct spi_master *master;
> >> + u8 i;
> >> +
> >> + pdata =3D dev->dev.platform_data;
> >> + if (pdata =3D=3D NULL)
> >> + return -ENODEV;
> >> +
> >> + r =3D platform_get_resource(dev, IORESOURCE_MEM, 0);
> >> + if (r =3D=3D NULL)
> >> + return -ENODEV;
> >> +
> >> + irq =3D platform_get_irq(dev, 0);
> >> + if (irq < 0)
> >> + return -ENXIO;
> >> +
> >> + master =3D xilinx_spi_init(&dev->dev, r, irq, pdata->model,
> >> + dev->id, pdata->num_chipselect, pdata->bits_per_word);
> >> + if (IS_ERR(master))
> >> + return PTR_ERR(master);
> >> +
> >> + for (i =3D 0; i < pdata->num_devices; i++)
> >> + spi_new_device(master, pdata->devices + i);
> >> +
> >> + platform_set_drvdata(dev, master);
> >> + return 0;
> >> +}
> >> +
> >> +static int __devexit xilinx_spi_remove(struct platform_device *dev)
> >> +{
> >> + xilinx_spi_deinit(platform_get_drvdata(dev));
> >> + platform_set_drvdata(dev, 0);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +/* work with hotplug and coldplug */
> >> +MODULE_ALIAS("platform:" XILINX_SPI_NAME);
> >> +
> >> +static struct platform_driver xilinx_spi_driver =3D {
> >> + .probe =3D xilinx_spi_probe,
> >> + .remove =3D __devexit_p(xilinx_spi_remove),
> >> + .driver =3D {
> >> + .name =3D XILINX_SPI_NAME,
> >> + .owner =3D THIS_MODULE,
> >> + },
> >> +};
> >> +
> >> +static int __init xilinx_spi_pltfm_init(void)
> >> +{
> >> + return platform_driver_register(&xilinx_spi_driver);
> >> +}
> >> +module_init(xilinx_spi_pltfm_init);
> >> +
> >> +static void __exit xilinx_spi_pltfm_exit(void)
> >> +{
> >> + platform_driver_unregister(&xilinx_spi_driver);
> >> +}
> >> +module_exit(xilinx_spi_pltfm_exit);
> >> +
> >> +MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
> >> +MODULE_DESCRIPTION("Xilinx SPI platform driver");
> >> +MODULE_LICENSE("GPL v2");
> >> +
> >> diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx=
_spi.h
> >> new file mode 100644
> >> index 0000000..e9e6a84
> >> --- /dev/null
> >> +++ b/include/linux/spi/xilinx_spi.h
> >> @@ -0,0 +1,18 @@
> >> +#ifndef __LINUX_SPI_XILINX_SPI_H
> >> +#define __LINUX_SPI_XILINX_SPI_H
> >> +
> >> +#define XILINX_SPI_MODEL_DS464 0
> >> +#define XILINX_SPI_MODEL_DS570 1
> >> +
> >> +/* SPI Controller IP */
> >> +struct xspi_platform_data {
> >> + u16 num_chipselect;
> >> + u8 model;
> >> + u8 bits_per_word;
> >> + /* devices to add to the bus when the host is up */
> >> + struct spi_board_info *devices;
> >> + u8 num_devices;
> >> +};
> >> +
> >> +#endif /* __LINUX_SPI_XILINX_SPI_H */
> >> +
> >> _______________________________________________
> >> Linuxppc-dev mailing list
> >> Linuxppc-dev@lists.ozlabs.org
> >> https://lists.ozlabs.org/listinfo/linuxppc-dev
> >
> >
> > This email and any attachments are intended for the sole use of the nam=
ed recipient(s) and
> contain(s) confidential information that may be proprietary, privileged o=
r copyrighted under
> applicable law. If you are not the intended recipient, do not read, copy,=
or forward this email
> message or any attachments. Delete this email message and any attachments=
immediately.
> >
> >
> =
This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.
next prev parent reply other threads:[~2009-09-23 22:45 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-22 12:55 [PATCH v3] xilinx_spi: Splitted into generic, of and platform driver, added support for DS570 Richard Röjfors
2009-09-22 16:00 ` John Linn
2009-09-22 21:59 ` Richard Röjfors
2009-09-23 22:44 ` John Linn [this message]
2009-09-24 7:36 ` Richard Röjfors
2009-09-24 13:42 ` John Linn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090923224452.EAAFEB48046@mail109-sin.bigfish.com \
--to=john.linn@xilinx.com \
--cc=akpm@linux-foundation.org \
--cc=dbrownell@users.sourceforge.net \
--cc=linuxppc-dev@ozlabs.org \
--cc=richard.rojfors@mocean-labs.com \
--cc=spi-devel-general@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).