From mboxrd@z Thu Jan 1 00:00:00 1970 From: John Linn Subject: RE: [PATCH v3] xilinx_spi: Splitted into generic, of and platform driver, added support for DS570 Date: Tue, 22 Sep 2009 10:00:05 -0600 Message-ID: <20090922155952.8171518B8046@mail30-sin.bigfish.com> References: <4AB8C936.5090409@mocean-labs.com> Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Cc: linuxppc-dev@ozlabs.org, Andrew Morton , dbrownell@users.sourceforge.net To: =?iso-8859-1?Q?Richard_R=F6jfors?= , Return-path: Content-Class: urn:content-classes:message In-Reply-To: <4AB8C936.5090409@mocean-labs.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linuxppc-dev-bounces+glppd-linuxppc64-dev=m.gmane.org@lists.ozlabs.org Errors-To: linuxppc-dev-bounces+glppd-linuxppc64-dev=m.gmane.org@lists.ozlabs.org List-Id: linux-spi.vger.kernel.org > -----Original Message----- > From: linuxppc-dev-bounces+john.linn=3Dxilinx.com@lists.ozlabs.org [mailt= o: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.sourceforge.n= et > Subject: [PATCH v3] xilinx_spi: Splitted into generic, of and platform dr= iver, 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, The current driver (without this change) works for the newer XPS SPI device= already as I run tests on it each day using an SPI EEPROM. = Do you think that's not the case, or it doesn't work for some other type of= devices that I'm not testing with? I'll hold off commenting on the rest of the code changes for a bit. Thanks, John > = > Signed-off-by: Richard R=F6jfors > --- > 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) && EXPERIMENTAL > 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.00b)" > + > + > +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 EDK. > + > +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 line > # > 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_gpio.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 > #include > #include > -#include > - > -#include > -#include > -#include > = > #include > #include > #include > = > -#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 flips = 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, u16 v= al) > +{ > + 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, u32 v= al) > +{ > + 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) (v= 1.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 Specification"= , 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_ENABLE); > /* 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_device= *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_device= *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 there i= s a > * 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 soft= ware. > - * 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 software. > + * SPI clock can't be changed in software. > + * 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 v= alue. > */ > 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_dev= ice *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 *sp= i, 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_device *= 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 Slave M= ode > @@ -237,32 +325,50 @@ static irqreturn_t xilinx_spi_irq(int irq, void *de= v_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 *dev_= 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 *de= v_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 resource *= 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_de= vice *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, xspi); > - 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, xspi= ); > + 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. "); > 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 modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > + */ > + > +#ifndef _XILINX_SPI_H_ > +#define _XILINX_SPI_H_ 1 > + > +#include > +#include > +#include > + > +#define XILINX_SPI_NAME "xilinx_spi" > + > +struct spi_master *xilinx_spi_init(struct device *dev, struct resource *= 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 under = the > + * terms of the GNU General Public License version 2. This program is l= icensed > + * "as is" without any warranty of any kind, whether express or implied. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include > +#include > + > +#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. "); > +MODULE_DESCRIPTION("Xilinx SPI driver"); > +MODULE_LICENSE("GPL"); > + > diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_pltf= m.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 modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. > + */ > + > +/* Supports: > + * Xilinx SPI devices as platform devices > + * > + * Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#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 "); > +MODULE_DESCRIPTION("Xilinx SPI platform driver"); > +MODULE_LICENSE("GPL v2"); > + > diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_sp= i.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 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.