* RE: [PATCH 2/4] xilinx_spi: Switch to iomem functions and support little endian.
From: John Linn @ 2009-11-11 22:19 UTC (permalink / raw)
To: Richard Röjfors, spi-devel-general
Cc: linuxppc-dev, Andrew Morton, dbrownell
In-Reply-To: <4AFACC6A.304@mocean-labs.com>
> -----Original Message-----
> From: Richard R=F6jfors [mailto:richard.rojfors@mocean-labs.com]
> Sent: Wednesday, November 11, 2009 7:39 AM
> To: spi-devel-general@lists.sourceforge.net
> Cc: linuxppc-dev@ozlabs.org; Andrew Morton; dbrownell@users.sourceforge.n=
et; John Linn;
> grant.likely@secretlab.ca
> Subject: [PATCH 2/4] xilinx_spi: Switch to iomem functions and support li=
ttle endian.
> =
> This patch changes the out_(be)(8|16|32) and in_(be)(8|16|32) calls to io=
write(8|16|32)
> and ioread(8|16|32). This to be able to build on platforms not supporting=
the in/out calls
> for instance x86.
> =
> Support is also added for little endian writes. In some systems the regis=
ters should be
> accessed little endian rather than big endian.
> =
> Signed-off-by: Richard R=F6jfors <richard.rojfors@mocean-labs.com>
> ---
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index e60b264..9667650 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -236,7 +236,7 @@ config SPI_TXX9
> =
> config SPI_XILINX
> tristate "Xilinx SPI controller"
> - depends on EXPERIMENTAL
> + depends on HAS_IOMEM && EXPERIMENTAL
> select SPI_BITBANG
> help
> This exposes the SPI controller IP from the Xilinx EDK.
> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
> index 1562e9b..b00dabc 100644
> --- a/drivers/spi/xilinx_spi.c
> +++ b/drivers/spi/xilinx_spi.c
> @@ -19,12 +19,12 @@
> #include <linux/spi/spi_bitbang.h>
> #include <linux/io.h>
> =
> -#define XILINX_SPI_NAME "xilinx_spi"
> +#include "xilinx_spi.h"
> =
> /* 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 0x60 /* 16-bit Control Register */
> =
> #define XSPI_CR_ENABLE 0x02
> #define XSPI_CR_MASTER_MODE 0x04
> @@ -36,7 +36,7 @@
> #define XSPI_CR_MANUAL_SSELECT 0x80
> #define XSPI_CR_TRANS_INHIBIT 0x100
> =
> -#define XSPI_SR_OFFSET 0x67 /* 8-bit Status Register */
> +#define XSPI_SR_OFFSET 0x64 /* 8-bit Status Register */
> =
> #define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
> #define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
> @@ -44,8 +44,8 @@
> #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 0x68 /* 8-bit Data Transmit Register */
> +#define XSPI_RXD_OFFSET 0x6c /* 8-bit Data Receive Register */
> =
> #define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
> =
> @@ -83,23 +83,69 @@ struct xilinx_spi {
> 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 */
> + bool big_endian; /* The device could be accessed big or little
> + * endian
> + */
> };
> =
> -static void xspi_init_hw(void __iomem *regs_base)
> +/* to follow are some functions that does little of big endian read and
> + * write depending on the config of the device.
> + */
> +static inline void xspi_write8(struct xilinx_spi *xspi, u32 offs, u8 val=
)
> +{
> + iowrite8(val, xspi->regs + offs + ((xspi->big_endian) ? 3 : 0));
> +}
> +
> +static inline void xspi_write16(struct xilinx_spi *xspi, u32 offs, u16 v=
al)
> +{
> + if (xspi->big_endian)
> + iowrite16be(val, xspi->regs + offs + 2);
> + else
> + iowrite16(val, xspi->regs + offs);
> +}
> +
> +static inline void xspi_write32(struct xilinx_spi *xspi, u32 offs, u32 v=
al)
> +{
> + if (xspi->big_endian)
> + iowrite32be(val, xspi->regs + offs);
> + else
> + iowrite32(val, xspi->regs + offs);
> +}
> +
> +static inline u8 xspi_read8(struct xilinx_spi *xspi, u32 offs)
> +{
> + return ioread8(xspi->regs + offs + ((xspi->big_endian) ? 3 : 0));
> +}
> +
> +static inline u16 xspi_read16(struct xilinx_spi *xspi, u32 offs)
> +{
> + if (xspi->big_endian)
> + return ioread16be(xspi->regs + offs + 2);
> + else
> + return ioread16(xspi->regs + offs);
> +}
> +
> +static inline u32 xspi_read32(struct xilinx_spi *xspi, u32 offs)
> +{
> + if (xspi->big_endian)
> + return ioread32be(xspi->regs + offs);
> + else
> + return ioread32(xspi->regs + offs);
> +}
> +
Hi Richard,
The registers of the device should all be accessible as 32 bit operations.
It seems like it would be simpler to do that.
Thanks,
John
> +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_write16(xspi, XSPI_CR_OFFSET,
> XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
> | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
> }
> @@ -110,16 +156,15 @@ 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)
> - & ~XSPI_CR_MODE_MASK;
> + u16 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
> @@ -127,7 +172,7 @@ 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));
> }
> }
> @@ -174,15 +219,15 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_s=
pi *xspi)
> u8 sr;
> =
> /* Fill the Tx FIFO with as many bytes as possible */
> - sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> + 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++);
> + xspi_write8(xspi, XSPI_TXD_OFFSET, *xspi->tx_ptr++);
> } else {
> - out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
> + xspi_write8(xspi, XSPI_TXD_OFFSET, 0);
> }
> xspi->remaining_bytes--;
> - sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> + sr =3D xspi_read8(xspi, XSPI_SR_OFFSET);
> }
> }
> =
> @@ -204,18 +249,18 @@ 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;
> }
> @@ -232,8 +277,8 @@ 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;
> @@ -244,20 +289,19 @@ static irqreturn_t xilinx_spi_irq(int irq, void *de=
v_id)
> * 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;
> =
> - data =3D in_8(xspi->regs + XSPI_RXD_OFFSET);
> + data =3D xspi_read8(xspi, XSPI_RXD_OFFSET);
> if (xspi->rx_ptr) {
> *xspi->rx_ptr++ =3D data;
> }
> - 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 */
> @@ -266,7 +310,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,7 +323,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_=
id)
> }
> =
> struct spi_master *xilinx_spi_init(struct device *dev, struct resource *=
mem,
> - u32 irq, s16 bus_num, u16 num_chipselect)
> + u32 irq, s16 bus_num, u16 num_chipselect, bool big_endian)
> {
> struct spi_master *master;
> struct xilinx_spi *xspi;
> @@ -319,9 +363,10 @@ struct spi_master *xilinx_spi_init(struct device *de=
v, struct resource *mem,
> =
> xspi->mem =3D *mem;
> xspi->irq =3D irq;
> + xspi->big_endian =3D big_endian;
> =
> /* SPI controller initializations */
> - xspi_init_hw(xspi->regs);
> + xspi_init_hw(xspi);
> =
> /* Register for SPI Interrupt */
> ret =3D request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi=
);
> diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
> index 84c98ee..c381c4a 100644
> --- a/drivers/spi/xilinx_spi.h
> +++ b/drivers/spi/xilinx_spi.h
> @@ -25,7 +25,7 @@
> #define XILINX_SPI_NAME "xilinx_spi"
> =
> struct spi_master *xilinx_spi_init(struct device *dev, struct resource *=
mem,
> - u32 irq, s16 bus_num, u16 num_chipselect);
> + u32 irq, s16 bus_num, u16 num_chipselect, bool big_endian);
> =
> 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
> index 5440253..83f23be 100644
> --- a/drivers/spi/xilinx_spi_of.c
> +++ b/drivers/spi/xilinx_spi_of.c
> @@ -65,7 +65,8 @@ static int __init xilinx_spi_of_probe(struct of_device =
*ofdev,
> 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, -1, *prop)=
;
> + master =3D xilinx_spi_init(&ofdev->dev, r_mem, r_irq->start, -1, *prop,=
> + true);
> if (IS_ERR(master))
> return PTR_ERR(master);
> =
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.
^ permalink raw reply
* Re: [alsa-devel] [PATCH 2/6] ASoC/mpc5200: get rid of the appl_ptr tracking nonsense
From: Jon Smirl @ 2009-11-11 23:13 UTC (permalink / raw)
To: Grant Likely; +Cc: John Bonesio, alsa-devel, Mark Brown, linuxppc-dev, lrg
In-Reply-To: <fa686aa40911111357q22f57728va1b4bc8b5bc0425f@mail.gmail.com>
On Wed, Nov 11, 2009 at 4:57 PM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> On Wed, Nov 11, 2009 at 2:34 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
>> On Wed, Nov 11, 2009 at 2:24 PM, Grant Likely <grant.likely@secretlab.ca=
> wrote:
>>> On Wed, Nov 11, 2009 at 11:37 AM, Mark Brown
>>> <broonie@opensource.wolfsonmicro.com> wrote:
>>>> On Wed, Nov 11, 2009 at 11:38:06AM -0500, Jon Smirl wrote:
>>>>> > Providing a final valid data point to the driver would possibly eve=
n
>>>>> > make things worse since if it were used then you'd have the equival=
ent
>>>>> > race where the application has initialized some data but not yet ma=
naged
>>>>> > to update the driver to tell it it's being handed over; if the driv=
er
>>>>
>>>>> That's an under run condition.
>>>>
>>>> Yes, of course - the issue is that this approach encourages them, maki=
ng
>>>> the system less robust if things are on the edge. =A0The mpc5200 seems=
to
>>>> be not just on the edge but comfortably beyond it for some reason.
>>>
>>> I can't reproduce the issue at all as long at the dev_dbg() statement
>>> in the trigger stop path is disabled. =A0With it enabled, I hear the
>>> problem every time. =A0The 5200 may not be a speedy beast, but it is
>>> plenty fast enough to shut down the audio stream before stale data
>>> starts getting played out.
>>
>> "fast enough" - you just said it is a race.
>> I've been saying it is a race too.
>
> Yes, it is a race; but not the kind that is dangerous. =A0Audio playout
> is always a real-time problem; whether in the middle of a stream or at
> the end. =A0If the CPU gets nailed with an unbounded latency, then there
> will be audible artifacts - Regardless of whether the driver knows
> where the end of data is or not. =A0If it does know, then audio will
> stutter. =A0If it doesn't know, then there will be repeated samples.
> Both are nasty to the human ear. =A0So, making the driver do extra work
> to keep the extra data in sync will probably force larger minimum
> latencies for playout (trouble for VoIP apps) so the CPU can keep up,
> and won't help one iota for making audio better.
I don't think it is that much more work for ALSA to provide an
accessible field indicating the end of valid data. It's already
tracking appl_ptr. Appl_ptr just needs to be translated into a
physical DMA buffer address and we've been making mistakes doing that
translation.
>
> The real solution is to fix the worst case latencies.
>
>> There are two options:
>> 1) Eliminate the race by developing a system to deterministically flag
>> the end of valid data.
>> 2) Fudge everything around making it almost impossible to lose the
>> race, but the race is still there.
>
> 3) eliminate the unbounded latencies (fix the PSC driver and/or use a
> real time kernel)
> 4) make sure userspace fills all the periods with silence before
> triggering stop. =A0Gstreamer seems to already do this. =A0I suspect
> pulseaudio does the same.
>
>> The dev_dbg() aggravates the race until it is obviously visible every
>> time. A deterministic solution would not be impacted by the dev_dbg().
>
> But it still wouldn't help a bit when the same latency occurs in the
> middle of playback.
The deterministic solution of tracking the end of valid data ensures
that under run will be silent instead of playing invalid data.
>
> g.
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
>
--=20
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [PATCH 0/6] gianfar: Some fixes
From: David Miller @ 2009-11-12 3:04 UTC (permalink / raw)
To: galak; +Cc: jdl, B05799, netdev, linuxppc-dev, afleming, shemminger, buytenh
In-Reply-To: <BEE5C957-99C1-4399-AB5D-BCF5BC05A73C@kernel.crashing.org>
From: Kumar Gala <galak@kernel.crashing.org>
Date: Wed, 11 Nov 2009 09:16:41 -0600
>
> On Nov 10, 2009, at 6:10 PM, Anton Vorontsov wrote:
>
>> Hi all,
>>
>> Here are some fixes for the gianfar driver, patches on the way.
>>
>> Thanks,
>
> Acked-by: Kumar Gala <galak@kernel.crashing.org>
All applied to net-next-2.6, thanks.
^ permalink raw reply
* Problem during mtd initialization
From: Divya @ 2009-11-12 5:16 UTC (permalink / raw)
To: linuxppc-dev, linux-mtd
[-- Attachment #1: Type: text/plain, Size: 2274 bytes --]
Hi,
We are working on MPC8640D based processor board with,
Boot Loader version : u-boot-2009-06
Kernel version : linux-2.6.30 (Downloaded from kernel.org)
RAM size : 1 GB
Flash memory size : 256 MB
When we are booting the linux kernel, during mtd subsystem initialization the following error message is obtained
# vmap allocation for size 268439552 failed: use vmalloc=<size> to increase size.
# of-flash f0000000.bootflash: Failed to ioremap() flash region
# of-flash: probe of f0000000.bootflash failed with error -12
It seems ioremap call during mtd initialization is failing.
The flash partitions are created through the device tree as follows,
ranges = <0 0 0xf0000000 0x10000000 >; // 256MB Boot flash
bootflash@0,0 {
compatible = "cfi-flash";
reg = <0 0 0x10000000>;
bank-width = <4>;
device-width = <2>;
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "dtb";
reg = <0x00000000 0x00100000>;
read-only;
};
partition@300000 {
label = "kernel";
reg = <0x00100000 0x00400000>;
read-only;
};
partition@400000 {
label = "fs";
reg = <0x00500000 0x00a00000>;
};
partition@700000 {
label = "firmware";
reg = <0x00f00000 0x00100000>;
read-only;
};
};
Kindly provide us suggestions regarding this issue whether any kernel configuration changes need to be done or if any additional implementations required in flash memory mapping
Regards,
Divya
[-- Attachment #2: Type: text/html, Size: 8043 bytes --]
^ permalink raw reply
* Re: Micrel PHY KSZ8001 on MPC5200B FEC
From: Roman Fietze @ 2009-11-12 6:33 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <200910281420.n9SEKI2R005094@nti1.com>
Hello Suvidh,
On Wednesday 28 October 2009 16:19:04 suvidh kankariya wrote:
> I am sorry for the misguided statement.
No problem, help is always welcome.
> I indeed had patched it.
Allthough Grant's mail got stuck in our beloved Notes spam filter, we
found out how to use that KSZ8001 on our board.
As Grant mentioned as well, the key was and is a correct DTS. (At
least) one statement was missing:
interrupt-parent =3D <&mpc5200_pic>;
This statement seemed to move all the way up from the devices to the
root of the tree, and somehow we missed that move.
Thanks again to all who answered.
Roman
=2D-=20
Roman Fietze Telemotive AG B=FCro M=FChlhausen
Breitwiesen 73347 M=FChlhausen
Tel.: +49(0)7335/18493-45 http://www.telemotive.de
^ permalink raw reply
* Re: Micrel PHY KSZ8001 on MPC5200B FEC
From: Grant Likely @ 2009-11-12 7:03 UTC (permalink / raw)
To: Roman Fietze; +Cc: linuxppc-dev
In-Reply-To: <200911120733.58112.roman.fietze@telemotive.de>
On Wed, Nov 11, 2009 at 11:33 PM, Roman Fietze
<roman.fietze@telemotive.de> wrote:
> As Grant mentioned as well, the key was and is a correct DTS. (At
> least) one statement was missing:
>
> =A0interrupt-parent =3D <&mpc5200_pic>;
>
> This statement seemed to move all the way up from the devices to the
> root of the tree, and somehow we missed that move.
Yes, nodes inherit the interrupt-parent property from their parent. I
took advantage of that to tidy up all the mpc5200 device trees.
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* linux-next: rr tree build failure
From: Stephen Rothwell @ 2009-11-12 8:03 UTC (permalink / raw)
To: Rusty Russell; +Cc: linux-next, Paul Mackerras, linux-kernel, linuxppc-dev
Hi Rusty,
Today's linux-next build (powerpc ppc44x_defconfig) failed like this:
.tmp_exports-asm.o: In function `__ksymtab_pci_alloc_consistent':
(__ksymtab_sorted+0x2a30): undefined reference to `pci_alloc_consistent'
.tmp_exports-asm.o: In function `__ksymtab_pci_free_consistent':
(__ksymtab_sorted+0x2b70): undefined reference to `pci_free_consistent'
Caused by the powerpc architecture EXPORTing static inlines (for 32 bit
builds) interacting with changes in the rr tree.
I have applied this patch for today:
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Thu, 12 Nov 2009 18:54:13 +1100
Subject: [PATCH] powerpc: do not export pci_alloc/free_consistent
Since they are static inline functions.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
arch/powerpc/kernel/ppc_ksyms.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 07115d6..4254514 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -96,8 +96,6 @@ EXPORT_SYMBOL(copy_4K_page);
EXPORT_SYMBOL(isa_io_base);
EXPORT_SYMBOL(isa_mem_base);
EXPORT_SYMBOL(pci_dram_offset);
-EXPORT_SYMBOL(pci_alloc_consistent);
-EXPORT_SYMBOL(pci_free_consistent);
#endif /* CONFIG_PCI */
EXPORT_SYMBOL(start_thread);
--
1.6.5.2
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
^ permalink raw reply related
* High traffic from eth to cf-ata blocks other eth traffic
From: Jan Husak @ 2009-11-12 8:44 UTC (permalink / raw)
To: linuxppc-dev
I have ppc system with compactflash card connected by ata. On this system is
running process using raw socket to send and receive cyclic data each 4ms.
When I start another iptraffic - sshftp - to write to compact flash, after
certain time the IRQ-135 (mpc52xx_ata) of ata driver locks task irqs from
network card for cca 300ms. And my cyclic data transfer is broken. Any idea
how to solve this problem?
Thanks a lot for hint. Jan
Output from sched_switch trace here:
pniodhld-2516 [000] 1305.162746: 2516: 33:T ==> [000] 6: 33:R sirq-net-rx/0
sirq-net-rx/0-6 [000] 1305.162755: 6: 33:R + [000] 2516: 33:T pniodhld
sirq-net-rx/0-6 [000] 1305.162766: 6: 49:R ==> [000] 2516: 33:S pniodhld
pniodhld-2516 [000] 1305.162835: 2516: 33:D ==> [000] 6: 49:R sirq-net-rx/0
sirq-net-rx/0-6 [000] 1305.162923: 6: 49:D ==> [000] 99:115:R ata/0
ata/0-99 [000] 1305.163050: 99:115:D ==> [000] 2409:120:R sftp-server
sftp-server-2409 [000] 1305.163100: 2409:120:R + [000] 710: 49:D IRQ-135
sftp-server-2409 [000] 1305.163119: 2409:120:R ==> [000] 710: 49:R IRQ-135
IRQ-135-710 [000] 1305.163227: 710: 49:D + [000] 710: 49:D IRQ-135
IRQ-135-710 [000] 1305.163324: 710: 49:D ==> [000] 2409:120:R sftp-server
sftp-server-2409 [000] 1305.163344: 2409:120:R + [000] 710: 49:D IRQ-135
sftp-server-2409 [000] 1305.163355: 2409:120:R ==> [000] 710: 49:R IRQ-135
IRQ-135-710 [000] 1305.163448: 710: 49:D + [000] 710: 49:D IRQ-135
IRQ-135-710 [000] 1305.163543: 710: 49:D ==> [000] 2409:120:R sftp-server
sftp-server-2409 [000] 1305.163562: 2409:120:R + [000] 710: 49:D IRQ-135
sftp-server-2409 [000] 1305.163574: 2409:120:R ==> [000] 710: 49:R IRQ-135
IRQ-135-710 [000] 1305.163634: 710: 49:R + [000] 4: 49:D sirq-timer/0
IRQ-135-710 [000] 1305.163768: 710: 49:D + [000] 710: 49:D IRQ-135
IRQ-135-710 [000] 1305.163870: 710: 49:D ==> [000] 4: 49:R sirq-timer/0
sirq-timer/0-4 [000] 1305.163894: 4: 49:R + [000] 710: 49:D IRQ-135
sirq-timer/0-4 [000] 1305.163918: 4: 49:D ==> [000] 710: 49:R IRQ-135
and another 500 similar lines till new net_rx irq task is scheduled
--
View this message in context: http://old.nabble.com/High-traffic-from-eth-to-cf-ata-blocks-other-eth-traffic-tp26315068p26315068.html
Sent from the linuxppc-dev mailing list archive at Nabble.com.
^ permalink raw reply
* Re: linux-next: rr tree build failure
From: Benjamin Herrenschmidt @ 2009-11-12 9:02 UTC (permalink / raw)
To: Stephen Rothwell
Cc: linuxppc-dev, Rusty Russell, Paul Mackerras, linux-next,
linux-kernel
In-Reply-To: <20091112190308.443d97a3.sfr@canb.auug.org.au>
On Thu, 2009-11-12 at 19:03 +1100, Stephen Rothwell wrote:
> Hi Rusty,
>
> Today's linux-next build (powerpc ppc44x_defconfig) failed like this:
>
> .tmp_exports-asm.o: In function `__ksymtab_pci_alloc_consistent':
> (__ksymtab_sorted+0x2a30): undefined reference to `pci_alloc_consistent'
> .tmp_exports-asm.o: In function `__ksymtab_pci_free_consistent':
> (__ksymtab_sorted+0x2b70): undefined reference to `pci_free_consistent'
>
> Caused by the powerpc architecture EXPORTing static inlines (for 32 bit
> builds) interacting with changes in the rr tree.
>
> I have applied this patch for today:
Thanks. Our EXPORTs are bogus (probably leftovers) it seems. I'll dbl
check tomorrow but that looks like a patch I should pickup in powerpc
-next anyways.
Cheers,
Ben.
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Thu, 12 Nov 2009 18:54:13 +1100
> Subject: [PATCH] powerpc: do not export pci_alloc/free_consistent
>
> Since they are static inline functions.
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
> arch/powerpc/kernel/ppc_ksyms.c | 2 --
> 1 files changed, 0 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
> index 07115d6..4254514 100644
> --- a/arch/powerpc/kernel/ppc_ksyms.c
> +++ b/arch/powerpc/kernel/ppc_ksyms.c
> @@ -96,8 +96,6 @@ EXPORT_SYMBOL(copy_4K_page);
> EXPORT_SYMBOL(isa_io_base);
> EXPORT_SYMBOL(isa_mem_base);
> EXPORT_SYMBOL(pci_dram_offset);
> -EXPORT_SYMBOL(pci_alloc_consistent);
> -EXPORT_SYMBOL(pci_free_consistent);
> #endif /* CONFIG_PCI */
>
> EXPORT_SYMBOL(start_thread);
> --
> 1.6.5.2
>
^ permalink raw reply
* Re: [PATCH 0/8] 8xx: Misc fixes for buggy insn
From: Joakim Tjernlund @ 2009-11-12 9:10 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev@ozlabs.org, Rex Feany
In-Reply-To: <20091111152653.GA688@loki.buserror.net>
Scott Wood <scottwood@freescale.com> wrote on 11/11/2009 16:26:53:
>
> On Wed, Nov 11, 2009 at 01:06:10AM +0100, Joakim Tjernlund wrote:
> > Scott Wood <scottwood@freescale.com> wrote on 11/11/2009 00:21:18:
> > > Where would you put the dcbi? How do you regain control after that
> > > cache line has been refilled, but before code flows back to the bad branch?
> >
> > The dcbi would replace the current CPU15 tlbie.
>
> But that only works if you take an ITLB miss at the right time.
Yeah, I misread the CPU15 errata so my ideas will not work.
Anyhow, will you send a patch that make TLB pinning mandatory?
After that my series can go in.
Jocke
^ permalink raw reply
* Re: Disable Caching for mmap() address
From: Benjamin Herrenschmidt @ 2009-11-12 9:32 UTC (permalink / raw)
To: Jonathan Haws; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <BB99A6BA28709744BF22A68E6D7EB51F03310B03B4@midas.usurf.usu.edu>
On Mon, 2009-11-09 at 16:21 -0700, Jonathan Haws wrote:
> All,
>
> I would like to disable caching for an address that was returned from a call to mmap(). I am using this address for DMA operations in user space and want to make sure that the data cache is turned off for that buffer.
>
> The way this works is the driver simply takes an address I provide and begins a DMA operation to that location in RAM (I have ensured that this is a physical address I am passing already). When the DMA is complete, an interrupt fires and the ISR gives a semaphore that the user space application is pending on (RT_SEM from Xenomai). I have tried simply calling a cache invalidate routine in the ISR before I give the semaphore, but the kernel crashes when I try to call that routine - my guess it because the kernel does not have direct access to that location in memory (only my application does, according to the MMU).
>
> Anyway, all I want to do is make sure that the buffer is never stored in the cache and that I always fetch it from RAM. How can I specify that using mmap() on the /dev/mem device, or is there a better way to accomplish this?
There is no "proper" way to do this, in large part because it's not
always legal to map memory non-cached for various reasons I don't
have time to explain right now...
You may be able to get it working though but using a specific driver
with an mmap function that tweaks the attributes or using mmap
of /dev/mem after opening it with O_SYNC (off the top of my mind)
But it's a bit fishy as the kernel has a cacheable mapping of most
of memory and so you may end up with cache aliases...
Cheers,
Ben.
^ permalink raw reply
* MTD subsystem Initialization
From: thirumalai.p @ 2009-11-12 10:15 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Linuxppc dev
Hi Ben,
When i try to boot my MPC8640D based target on 2.6.30 kernel. My
target is having 1GB of RAM and 256 MB of Flash memory. I am passing the
partition information using OF Tree. During MTD subsystem initialization,
the following error message is displayed. "vmap allocation for size
268435456 failed". i found that this is due to ioremap failure which is
happening during the time of MTD initializtion.
Even thoogh HIGH_MEM support was enabled on the kernel, this is failing.
Any configurations that need to be modified for this.
I am using ELDK-4.0 for compilation.
Thank you
T.
**************** CAUTION - Disclaimer *****************This email may contain confidential and privileged material for the
sole use of the intended recipient(s). Any review, use, retention, distribution or disclosure by others is strictly prohibited. If you are not the intended recipient (or authorized to receive for the recipient), please contact the sender by reply email and delete all copies of this message. Also, email is susceptible to data corruption, interception, tampering, unauthorized amendment and viruses. We only send and receive emails on the basis that we are not liable for any such corruption, interception, tampering, amendment or viruses or any consequence thereof.
*********** End of Disclaimer ***********DataPatterns ITS Group**********
^ permalink raw reply
* Re: linux-next: rr tree build failure
From: Stephen Rothwell @ 2009-11-12 10:50 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Rusty Russell, Paul Mackerras, linux-next,
linux-kernel
In-Reply-To: <1258016520.2140.329.camel@pasglop>
[-- Attachment #1: Type: text/plain, Size: 410 bytes --]
Hi Ben,
On Thu, 12 Nov 2009 20:02:00 +1100 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> Thanks. Our EXPORTs are bogus (probably leftovers) it seems. I'll dbl
> check tomorrow but that looks like a patch I should pickup in powerpc
> -next anyways.
That was the idea, thanks.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [powerpc] Next tree Nov 2 : kernel BUG at mm/mmap.c:2135!
From: Sachin Sant @ 2009-11-12 11:16 UTC (permalink / raw)
To: dwg; +Cc: Linux/PPC Development, linux-next, Stephen Rothwell
In-Reply-To: <20091105001650.GD3613@yookeroo.seuss>
David Gibson wrote:
> On Wed, Nov 04, 2009 at 06:08:44PM +0530, Sachin Sant wrote:
>
>> Sachin Sant wrote:
>>
>>> Today's next tree failed to boot on a POWER 6 box with :
>>>
>>> ------------[ cut here ]------------
>>> kernel BUG at mm/mmap.c:2135!
>>> Oops: Exception in kernel mode, sig: 5 [#2]
>>> SMP NR_CPUS=1024 NUMA pSeries
>>>
>> Problem exists with today's next as well.
>>
>> Likely cause for this problem seems to the following commit.
>> If i revert this patch the machine boots fine.
>>
>> commit a0668cdc154e54bf0c85182e0535eea237d53146
>> powerpc/mm: Cleanup management of kmem_caches for pagetables
>>
>
> Ugh. Ok, it's not at all obvious how my patch could cause this bug.
> Can you send your .config?
>
>
Still present in today's next.
Thanks
-Sachin
>>> Modules linked in: ibmvscsic scsi_transport_srp scsi_tgt scsi_mod
>>> NIP: c00000000014e30c LR: c00000000014e2f8 CTR: c00000000014db88
>>> REGS: c0000000db703620 TRAP: 0700 Tainted: G D
>>> (2.6.32-rc5-autotest-next-20091102)
>>> MSR: 8000000000029032 <EE,ME,CE,IR,DR> CR: 24022442 XER: 2000000c
>>> TASK = c0000000db7f6fe0[76] 'init' THREAD: c0000000db700000 CPU: 1
>>> GPR00: 0000000000000001 c0000000db7038a0 c000000000b19900
>>> 0000000000000000
>>> GPR04: c0000000db406a40 000000000000000c c0000000fe10c370
>>> c000000000bb2800
>>> GPR08: 000000000000db40 0000000000000000 c0000000dfdc0e00
>>> 000000000000000c
>>> GPR12: 0000000044022442 c000000000bb2800 00000000ffffffff
>>> ffffffffffffffff
>>> GPR16: 0000000008430000 00000000003c0000 c0000000db703ea0
>>> c0000000db569108
>>> GPR20: c0000000db568908 0000000000000000 c0000000db703d60
>>> 0000000000000000
>>> GPR24: 0000000000000001 0000000000040100 c0000000fe503580
>>> c0000000db1ac180
>>> GPR28: 0000000000000000 c000000000f812d0 c000000000a84f00
>>> 0000000000000000
>>> NIP [c00000000014e30c] .exit_mmap+0x190/0x1b8
>>> LR [c00000000014e2f8] .exit_mmap+0x17c/0x1b8
>>> Call Trace:
>>> [c0000000db7038a0] [c00000000014e2f8] .exit_mmap+0x17c/0x1b8 (unreliable)
>>> [c0000000db703950] [c0000000000916cc] .mmput+0x54/0x164
>>> [c0000000db7039e0] [c0000000000968d8] .exit_mm+0x17c/0x1a0
>>> [c0000000db703a90] [c000000000098cb8] .do_exit+0x248/0x784
>>> [c0000000db703b70] [c0000000000992a8] .do_group_exit+0xb4/0xe8
>>> [c0000000db703c00] [c0000000000aca2c] .get_signal_to_deliver+0x3ec/0x478
>>> [c0000000db703cf0] [c0000000000134ac] .do_signal+0x6c/0x31c
>>> [c0000000db703e30] [c000000000008b7c] do_work+0x24/0x28
>>> Instruction dump:
>>> 7c8407b4 387d0018 4800ab11 60000000 939d0008 7fe3fb78 4bfffdbd 7c7f1b79
>>> 4082fff4 e81b00e8 3120ffff 7c090110 <0b000000> 382100b0 e8010010 eb61ffd8
>>> ---[ end trace ec052ac77a8e7cb4 ]---
>>> Fixing recursive fault but reboot is needed!
>>>
>>> mm/mmap.c:2135 corresponds to :
>>>
>>> BUG_ON(mm->nr_ptes > (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT);
>>>
>>>
>
>
--
---------------------------------
Sachin Sant
IBM Linux Technology Center
India Systems and Technology Labs
Bangalore, India
---------------------------------
^ permalink raw reply
* Re: [alsa-devel] [PATCH 2/6] ASoC/mpc5200: get rid of the appl_ptr tracking nonsense
From: Mark Brown @ 2009-11-12 12:10 UTC (permalink / raw)
To: Jon Smirl; +Cc: John Bonesio, alsa-devel, linuxppc-dev, lrg
In-Reply-To: <9e4733910911111513w5423333cp6cf08ceec9a94ac3@mail.gmail.com>
On Wed, Nov 11, 2009 at 06:13:25PM -0500, Jon Smirl wrote:
> I don't think it is that much more work for ALSA to provide an
> accessible field indicating the end of valid data. It's already
> tracking appl_ptr. Appl_ptr just needs to be translated into a
> physical DMA buffer address and we've been making mistakes doing that
> translation.
I'm sure if you provide reasonable patches they'll get applied; it
doesn't seem likely that anyone else will work on this.
> On Wed, Nov 11, 2009 at 4:57 PM, Grant Likely <grant.likely@secretlab.ca> wrote
> > But it still wouldn't help a bit when the same latency occurs in the
> > middle of playback.
> The deterministic solution of tracking the end of valid data ensures
> that under run will be silent instead of playing invalid data.
In the middle of playback a sudden silence period is very noticable -
applications that expect data loss generally have some means to try to
cover it up since sudden silence is so noticable to the human ear. Mid
playback there's a bit more chance that random data from earlier in the
playback will be acceptable, and if the application has actually updated
the data but not got round to telling the driver about that yet then
even better.
I think you're getting too focused on the fact that there is a race
condition here since the consequences of race conditions are usually so
severe. There's always going to be some hardware for which there's a
degree of racyness (free running hardware has its own set of issues
here) so the system design takes this into account.
^ permalink raw reply
* Re: [PATCH 5/5] powerpc/86xx: Support for NVRAM on GE Fanuc's PPC9A
From: Kumar Gala @ 2009-11-12 14:04 UTC (permalink / raw)
To: Martyn Welch; +Cc: linuxppc-dev
In-Reply-To: <20090702161244.31202.22026.stgit@ES-J7S4D2J.amer.consind.ge.com>
On Jul 2, 2009, at 11:12 AM, Martyn Welch wrote:
> Add support for NVRAM on GE Fanuc's PPC9A.
>
> Signed-off-by: Martyn Welch <martyn.welch@gefanuc.com>
> ---
>
> arch/powerpc/boot/dts/gef_ppc9a.dts | 6 ++++++
> arch/powerpc/configs/86xx/gef_ppc9a_defconfig | 4 ++--
> arch/powerpc/platforms/86xx/Kconfig | 1 +
> arch/powerpc/platforms/86xx/gef_ppc9a.c | 5 +++++
> 4 files changed, 14 insertions(+), 2 deletions(-)
applied to next
- k
^ permalink raw reply
* Re: [PATCH 4/5] powerpc/86xx: Support for NVRAM on GE Fanuc's SBC310
From: Kumar Gala @ 2009-11-12 14:04 UTC (permalink / raw)
To: Martyn Welch; +Cc: linuxppc-dev
In-Reply-To: <20090702161237.31202.95547.stgit@ES-J7S4D2J.amer.consind.ge.com>
On Jul 2, 2009, at 11:12 AM, Martyn Welch wrote:
> Add support for NVRAM on GE Fanuc's SBC310.
>
> Signed-off-by: Martyn Welch <martyn.welch@gefanuc.com>
> ---
>
> arch/powerpc/boot/dts/gef_sbc310.dts | 6 ++++++
> arch/powerpc/configs/86xx/gef_sbc310_defconfig | 4 ++--
> arch/powerpc/platforms/86xx/Kconfig | 1 +
> arch/powerpc/platforms/86xx/gef_sbc310.c | 5 +++++
> 4 files changed, 14 insertions(+), 2 deletions(-)
applied to next
- k
^ permalink raw reply
* Re: [PATCH 3/5] powerpc/86xx: Enable NVRAM on GE Fanuc's SBC610
From: Kumar Gala @ 2009-11-12 14:03 UTC (permalink / raw)
To: Martyn Welch; +Cc: linuxppc-dev
In-Reply-To: <20090702161231.31202.87763.stgit@ES-J7S4D2J.amer.consind.ge.com>
On Jul 2, 2009, at 11:12 AM, Martyn Welch wrote:
> This patch enables the NVRAM found on the GE Fanuc SBC610
>
> Signed-off-by: Martyn Welch <martyn.welch@gefanuc.com>
> ---
>
> arch/powerpc/boot/dts/gef_sbc610.dts | 6 ++++++
> arch/powerpc/configs/86xx/gef_sbc610_defconfig | 4 ++--
> arch/powerpc/platforms/86xx/Kconfig | 1 +
> arch/powerpc/platforms/86xx/gef_sbc610.c | 5 +++++
> 4 files changed, 14 insertions(+), 2 deletions(-)
applied to next
- k
^ permalink raw reply
* [PATCH v2 0/4] xilinx_spi: Split into platform and of driver, support new IP, platform independence.
From: Richard Röjfors @ 2009-11-12 14:26 UTC (permalink / raw)
To: spi-devel-general; +Cc: linuxppc-dev, Andrew Morton, dbrownell, John Linn
Hi,
To follow is a series of patches against the xilinx_spi driver.
The patchset is against 2.6.32-rc6
The patchset addresses several problems in the current driver:
* It's PPC only (OF and uses PPC specific memory operations)
* Only supporting big endian writes
* Supports only 8bit SPI, support for DS570 (also 16 or 32 bit) is added.
* A platform driver is introduced for non OF capable architectures.
These patches were posted as one big patch up to 4 iterations, not splitted into 4.
This version, 2, is updated after review from Grant Likely and John Linn
--Richard
^ permalink raw reply
* [PATCH v2 1/4] xilinx_spi: Split into of driver and generic part.
From: Richard Röjfors @ 2009-11-12 14:26 UTC (permalink / raw)
To: spi-devel-general; +Cc: linuxppc-dev, Andrew Morton, dbrownell, John Linn
This patch splits the xilinx_spi driver into a generic part and a
OF driver part.
The reason for this is to later add in a platform driver as well.
Signed-off-by: Richard Röjfors <richard.rojfors@mocean-labs.com>
---
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b6f7cb..e60b264 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -236,7 +236,7 @@ config SPI_TXX9
config SPI_XILINX
tristate "Xilinx SPI controller"
- depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
+ depends on EXPERIMENTAL
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
@@ -244,6 +244,12 @@ config SPI_XILINX
See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
Product Specification document (DS464) for hardware details.
+config SPI_XILINX_OF
+ tristate "Xilinx SPI controller OF device"
+ depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE)
+ help
+ This is the OF 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 21a1182..97dee8f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
+obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o
obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
# ... add above this line ...
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 46b8c5c..5761a4c 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -14,16 +14,14 @@
#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>
+#include "xilinx_spi.h"
+#include <linux/spi/xilinx_spi.h>
+
#define XILINX_SPI_NAME "xilinx_spi"
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
@@ -78,7 +76,7 @@ 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;
@@ -283,40 +281,22 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
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, s16 bus_num)
{
struct spi_master *master;
struct xilinx_spi *xspi;
- struct resource r_irq_struct;
- struct resource r_mem_struct;
-
- struct resource *r_irq = &r_irq_struct;
- struct resource *r_mem = &r_mem_struct;
- int rc = 0;
- const u32 *prop;
- int len;
-
- /* Get resources(memory, IRQ) associated with the device */
- master = spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi));
+ struct xspi_platform_data *pdata = dev->platform_data;
+ int ret;
- if (master == NULL) {
- return -ENOMEM;
- }
-
- dev_set_drvdata(&ofdev->dev, master);
-
- rc = of_address_to_resource(ofdev->node, 0, r_mem);
- if (rc) {
- dev_warn(&ofdev->dev, "invalid address\n");
- goto put_master;
+ if (!pdata) {
+ dev_err(dev, "No platform data attached\n");
+ return NULL;
}
- rc = of_irq_to_resource(ofdev->node, 0, r_irq);
- if (rc == NO_IRQ) {
- dev_warn(&ofdev->dev, "no IRQ found\n");
- goto put_master;
- }
+ master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
+ if (!master)
+ return NULL;
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA;
@@ -329,128 +309,67 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev,
xspi->bitbang.master->setup = xilinx_spi_setup;
init_completion(&xspi->done);
- xspi->irq = r_irq->start;
-
- if (!request_mem_region(r_mem->start,
- r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) {
- rc = -ENXIO;
- dev_warn(&ofdev->dev, "memory request failure\n");
+ if (!request_mem_region(mem->start, resource_size(mem),
+ XILINX_SPI_NAME))
goto put_master;
- }
- xspi->regs = ioremap(r_mem->start, r_mem->end - r_mem->start + 1);
+ xspi->regs = ioremap(mem->start, resource_size(mem));
if (xspi->regs == NULL) {
- rc = -ENOMEM;
- dev_warn(&ofdev->dev, "ioremap failure\n");
- goto release_mem;
+ dev_warn(dev, "ioremap failure\n");
+ goto map_failed;
}
- xspi->irq = r_irq->start;
- /* dynamic bus assignment */
- master->bus_num = -1;
+ master->bus_num = bus_num;
+ master->num_chipselect = pdata->num_chipselect;
- /* number of slave select bits is required */
- prop = 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->num_chipselect = *prop;
+ xspi->mem = *mem;
+ xspi->irq = irq;
/* SPI controller initializations */
xspi_init_hw(xspi->regs);
/* Register for SPI Interrupt */
- rc = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
- if (rc != 0) {
- dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq);
+ ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+ if (ret)
goto unmap_io;
- }
- rc = spi_bitbang_start(&xspi->bitbang);
- if (rc != 0) {
- dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n");
+ ret = spi_bitbang_start(&xspi->bitbang);
+ if (ret) {
+ dev_err(dev, "spi_bitbang_start FAILED\n");
goto free_irq;
}
- dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=%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=%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 NULL;
}
+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 = platform_get_drvdata(ofdev);
xspi = 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[] = {
- { .compatible = "xlnx,xps-spi-2.00.a", },
- { .compatible = "xlnx,xps-spi-2.00.b", },
- {}
-};
-
-MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-
-static struct of_platform_driver xilinx_spi_of_driver = {
- .owner = THIS_MODULE,
- .name = "xilinx-xps-spi",
- .match_table = xilinx_spi_of_match,
- .probe = xilinx_spi_of_probe,
- .remove = __exit_p(xilinx_spi_of_remove),
- .driver = {
- .name = "xilinx-xps-spi",
- .owner = 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..d211acc
--- /dev/null
+++ b/drivers/spi/xilinx_spi.h
@@ -0,0 +1,32 @@
+/*
+ * Xilinx SPI device driver API and platform data header file
+ *
+ * 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_
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#define XILINX_SPI_NAME "xilinx_spi"
+
+struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
+ u32 irq, s16 bus_num);
+
+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..8c3fb54
--- /dev/null
+++ b/drivers/spi/xilinx_spi_of.c
@@ -0,0 +1,136 @@
+/*
+ * Xilinx SPI OF device driver
+ *
+ * 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 OF 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/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of_spi.h>
+
+#include <linux/spi/xilinx_spi.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 = &r_irq_struct;
+ struct resource *r_mem = &r_mem_struct;
+ int rc = 0;
+ const u32 *prop;
+ int len;
+
+ rc = of_address_to_resource(ofdev->node, 0, r_mem);
+ if (rc) {
+ dev_warn(&ofdev->dev, "invalid address\n");
+ return rc;
+ }
+
+ rc = of_irq_to_resource(ofdev->node, 0, r_irq);
+ if (rc == NO_IRQ) {
+ dev_warn(&ofdev->dev, "no IRQ found\n");
+ return -ENODEV;
+ }
+
+ if (!ofdev->dev.platform_data) {
+ ofdev->dev.platform_data =
+ kzalloc(sizeof(struct xspi_platform_data), GFP_KERNEL);
+ if (!ofdev->dev.platform_data)
+ return -ENOMEM;
+ }
+
+ /* number of slave select bits is required */
+ prop = 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;
+ }
+ ofdev->dev.platform_data->num_chipselect = *prop;
+ master = xilinx_spi_init(&ofdev->dev, r_mem, r_irq->start, -1);
+ if (!master)
+ return -ENODEV;
+
+ 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[] = {
+ { .compatible = "xlnx,xps-spi-2.00.a", },
+ { .compatible = "xlnx,xps-spi-2.00.b", },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+
+static struct of_platform_driver xilinx_spi_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "xilinx-xps-spi",
+ .match_table = xilinx_spi_of_match,
+ .probe = xilinx_spi_of_probe,
+ .remove = __exit_p(xilinx_spi_of_remove),
+ .driver = {
+ .name = "xilinx-xps-spi",
+ .owner = 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("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..06df0ab
--- /dev/null
+++ b/include/linux/spi/xilinx_spi.h
@@ -0,0 +1,16 @@
+#ifndef __LINUX_SPI_XILINX_SPI_H
+#define __LINUX_SPI_XILINX_SPI_H
+
+/**
+ * struct xspi_platform_data - Platform data of the Xilinx SPI driver
+ * @num_chipselect: Number of chip select by the IP
+ * @devices: Devices to add when the driver is probed.
+ * @num_devices: Number of devices in the devices array.
+ */
+struct xspi_platform_data {
+ u16 num_chipselect;
+ struct spi_board_info *devices;
+ u8 num_devices;
+};
+
+#endif /* __LINUX_SPI_XILINX_SPI_H */
^ permalink raw reply related
* [PATCH v2 2/4] xilinx_spi: Switch to iomem functions and support little endian.
From: Richard Röjfors @ 2009-11-12 14:26 UTC (permalink / raw)
To: spi-devel-general; +Cc: linuxppc-dev, Andrew Morton, dbrownell, John Linn
This patch changes the out_(be)(8|16|32) and in_(be)(8|16|32) calls to 32 bits ioread/iowrite.
The read and write function are attached to the internal struct as callbacks, callback
is selected depending on endianess.
This will also build on platforms not supporting the in/out calls for instance x86.
Signed-off-by: Richard Röjfors <richard.rojfors@mocean-labs.com>
---
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index e60b264..9667650 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -236,7 +236,7 @@ config SPI_TXX9
config SPI_XILINX
tristate "Xilinx SPI controller"
- depends on EXPERIMENTAL
+ depends on HAS_IOMEM && EXPERIMENTAL
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 5761a4c..d0ca13a 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -27,7 +27,7 @@
/* 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 0x60 /* 16-bit Control Register */
#define XSPI_CR_ENABLE 0x02
#define XSPI_CR_MASTER_MODE 0x04
@@ -39,7 +39,7 @@
#define XSPI_CR_MANUAL_SSELECT 0x80
#define XSPI_CR_TRANS_INHIBIT 0x100
-#define XSPI_SR_OFFSET 0x67 /* 8-bit Status Register */
+#define XSPI_SR_OFFSET 0x64 /* 8-bit Status Register */
#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
@@ -47,8 +47,8 @@
#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 0x68 /* 8-bit Data Transmit Register */
+#define XSPI_RXD_OFFSET 0x6c /* 8-bit Data Receive Register */
#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
@@ -86,25 +86,29 @@ struct xilinx_spi {
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 */
+ unsigned int (*read_fn) (void __iomem *);
+ void (*write_fn) (u32, void __iomem *);
};
-static void xspi_init_hw(void __iomem *regs_base)
+static void xspi_init_hw(struct xilinx_spi *xspi)
{
+ void __iomem *regs_base = xspi->regs;
+
/* Reset the SPI device */
- out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
- XIPIF_V123B_RESET_MASK);
+ xspi->write_fn(XIPIF_V123B_RESET_MASK,
+ regs_base + XIPIF_V123B_RESETR_OFFSET);
/* Disable all the interrupts just in case */
- out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
+ xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
/* Enable the global IPIF interrupt */
- out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
- XIPIF_V123B_GINTR_ENABLE);
+ xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
+ regs_base + XIPIF_V123B_DGIER_OFFSET);
/* Deselect the slave on the SPI bus */
- out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
+ xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
/* 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->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
+ XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE,
+ regs_base + XSPI_CR_OFFSET);
}
static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
@@ -113,16 +117,16 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
if (is_on == BITBANG_CS_INACTIVE) {
/* Deselect the slave on the SPI bus */
- out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
+ xspi->write_fn(0xffff, xspi->regs + XSPI_SSR_OFFSET);
} else if (is_on == BITBANG_CS_ACTIVE) {
/* Set the SPI clock phase and polarity */
- u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET)
+ u16 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET)
& ~XSPI_CR_MODE_MASK;
if (spi->mode & SPI_CPHA)
cr |= XSPI_CR_CPHA;
if (spi->mode & SPI_CPOL)
cr |= XSPI_CR_CPOL;
- out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+ xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
/* We do not check spi->max_speed_hz here as the SPI clock
* frequency is not software programmable (the IP block design
@@ -130,8 +134,8 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
*/
/* Activate the chip select */
- out_be32(xspi->regs + XSPI_SSR_OFFSET,
- ~(0x0001 << spi->chip_select));
+ xspi->write_fn(~(0x0001 << spi->chip_select),
+ xspi->regs + XSPI_SSR_OFFSET);
}
}
@@ -177,15 +181,15 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
u8 sr;
/* Fill the Tx FIFO with as many bytes as possible */
- sr = in_8(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) {
- if (xspi->tx_ptr) {
- out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
- } else {
- out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
- }
+ if (xspi->tx_ptr)
+ xspi->write_fn(*xspi->tx_ptr++,
+ xspi->regs + XSPI_TXD_OFFSET);
+ else
+ xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
xspi->remaining_bytes--;
- sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
}
}
@@ -207,18 +211,19 @@ 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 = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
- out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
- ipif_ier | XSPI_INTR_TX_EMPTY);
+ ipif_ier = xspi->read_fn(xspi->regs + XIPIF_V123B_IIER_OFFSET);
+ xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY,
+ xspi->regs + XIPIF_V123B_IIER_OFFSET);
/* Start the transfer by not inhibiting the transmitter any longer */
- cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
- out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+ cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) &
+ ~XSPI_CR_TRANS_INHIBIT;
+ xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
wait_for_completion(&xspi->done);
/* Disable the transmit empty interrupt */
- out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
+ xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET);
return t->len - xspi->remaining_bytes;
}
@@ -235,8 +240,8 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
u32 ipif_isr;
/* Get the IPIF interrupts, and clear them immediately */
- ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
- out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
+ ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
u16 cr;
@@ -247,20 +252,20 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
* transmitter while the Isr refills the transmit register/FIFO,
* or make sure it is stopped if we're done.
*/
- cr = in_be16(xspi->regs + XSPI_CR_OFFSET);
- out_be16(xspi->regs + XSPI_CR_OFFSET,
- cr | XSPI_CR_TRANS_INHIBIT);
+ cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
+ xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
+ xspi->regs + XSPI_CR_OFFSET);
/* Read out all the data from the Rx FIFO */
- sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
u8 data;
- data = in_8(xspi->regs + XSPI_RXD_OFFSET);
+ data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
*xspi->rx_ptr++ = data;
}
- sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
}
/* See if there is more data to send */
@@ -269,7 +274,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->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
} else {
/* No more data to send.
* Indicate the transfer is completed.
@@ -324,9 +329,16 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
xspi->mem = *mem;
xspi->irq = irq;
+ if (pdata->little_endian) {
+ xspi->read_fn = ioread32;
+ xspi->write_fn = iowrite32;
+ } else {
+ xspi->read_fn = ioread32be;
+ xspi->write_fn = iowrite32be;
+ }
/* SPI controller initializations */
- xspi_init_hw(xspi->regs);
+ xspi_init_hw(xspi);
/* Register for SPI Interrupt */
ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_spi.h
index 06df0ab..a705ad8 100644
--- a/include/linux/spi/xilinx_spi.h
+++ b/include/linux/spi/xilinx_spi.h
@@ -4,11 +4,13 @@
/**
* struct xspi_platform_data - Platform data of the Xilinx SPI driver
* @num_chipselect: Number of chip select by the IP
+ * @little_endian If registers should be accessed little endian or not
* @devices: Devices to add when the driver is probed.
* @num_devices: Number of devices in the devices array.
*/
struct xspi_platform_data {
u16 num_chipselect;
+ bool little_endian;
struct spi_board_info *devices;
u8 num_devices;
};
^ permalink raw reply related
* [PATCH v2 3/4] xilinx_spi: add support for the DS570 IP.
From: Richard Röjfors @ 2009-11-12 14:27 UTC (permalink / raw)
To: spi-devel-general; +Cc: linuxppc-dev, Andrew Morton, dbrownell, John Linn
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.
Signed-off-by: Richard Röjfors <richard.rojfors@mocean-labs.com>
---
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 9667650..b956284 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -235,7 +235,7 @@ config SPI_TXX9
SPI driver for Toshiba TXx9 MIPS SoCs
config SPI_XILINX
- tristate "Xilinx SPI controller"
+ tristate "Xilinx SPI controller common module"
depends on HAS_IOMEM && EXPERIMENTAL
select SPI_BITBANG
help
@@ -244,6 +244,8 @@ 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 || MICROBLAZE)
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index d0ca13a..8d30c8f 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -27,7 +27,7 @@
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
* 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_MASTER_MODE 0x04
@@ -38,8 +38,9 @@
#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 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_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_MODE_FAULT_MASK 0x10 /* Mode fault error */
-#define XSPI_TXD_OFFSET 0x68 /* 8-bit Data Transmit Register */
-#define XSPI_RXD_OFFSET 0x6c /* 8-bit Data Receive Register */
+#define XSPI_TXD_OFFSET 0x68 /* Data Transmit Register */
+#define XSPI_RXD_OFFSET 0x6c /* Data Receive 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_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 */
@@ -81,15 +83,61 @@ struct xilinx_spi {
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 */
+ u8 bits_per_word;
unsigned int (*read_fn) (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)
{
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,
* put SPI controller into master mode, and enable it */
xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
- XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE,
- regs_base + XSPI_CR_OFFSET);
+ XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |
+ XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET);
}
static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
@@ -141,17 +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
* 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.
- * 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 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 = spi_master_get_devdata(spi->master);
- bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
- if (bits_per_word != 8) {
+ bits_per_word = (t->bits_per_word) ? t->bits_per_word :
+ spi->bits_per_word;
+ if (bits_per_word != xspi->bits_per_word) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, bits_per_word);
return -EINVAL;
@@ -162,17 +213,16 @@ 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 = spi_master_get_devdata(spi->master);
- bitbang = &xspi->bitbang;
-
- retval = 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;
}
@@ -184,11 +234,10 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
if (xspi->tx_ptr)
- xspi->write_fn(*xspi->tx_ptr++,
- xspi->regs + XSPI_TXD_OFFSET);
+ xspi->tx_fn(xspi);
else
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);
}
}
@@ -259,12 +308,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
/* Read out all the data from the Rx FIFO */
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
- u8 data;
-
- data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
- if (xspi->rx_ptr) {
- *xspi->rx_ptr++ = data;
- }
+ xspi->rx_fn(xspi);
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
}
@@ -336,6 +380,19 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
xspi->read_fn = ioread32be;
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 */
xspi_init_hw(xspi);
diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
index 8c3fb54..13e1591 100644
--- a/drivers/spi/xilinx_spi_of.c
+++ b/drivers/spi/xilinx_spi_of.c
@@ -75,6 +75,7 @@ static int __init xilinx_spi_of_probe(struct of_device *ofdev,
return -EINVAL;
}
ofdev->dev.platform_data->num_chipselect = *prop;
+ ofdev->dev.platform_data->bits_per_word = 8;
master = xilinx_spi_init(&ofdev->dev, r_mem, r_irq->start, -1);
if (!master)
return -ENODEV;
diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_spi.h
index a705ad8..6f17278 100644
--- a/include/linux/spi/xilinx_spi.h
+++ b/include/linux/spi/xilinx_spi.h
@@ -3,14 +3,16 @@
/**
* struct xspi_platform_data - Platform data of the Xilinx SPI driver
- * @num_chipselect: Number of chip select by the IP
- * @little_endian If registers should be accessed little endian or not
+ * @num_chipselect: Number of chip select by the IP.
+ * @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.
* @num_devices: Number of devices in the devices array.
*/
struct xspi_platform_data {
u16 num_chipselect;
bool little_endian;
+ u8 bits_per_word;
struct spi_board_info *devices;
u8 num_devices;
};
^ permalink raw reply related
* [PATCH v2 4/4] xilinx_spi: add a platform driver using the xilinx_spi common module.
From: Richard Röjfors @ 2009-11-12 14:28 UTC (permalink / raw)
To: spi-devel-general; +Cc: linuxppc-dev, Andrew Morton, dbrownell, John Linn
This patch adds in a platform device driver using the xilinx_spi common module.
Signed-off-by: Richard Röjfors <richard.rojfors@mocean-labs.com>
---
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b956284..d1f8ee3 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -252,6 +252,13 @@ config SPI_XILINX_OF
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 97dee8f..d8b0e4c 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o
+obj-$(CONFIG_SPI_XILINX_PLTFM) += xilinx_spi_pltfm.o
obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
# ... add above this line ...
diff --git a/drivers/spi/xilinx_spi_pltfm.c b/drivers/spi/xilinx_spi_pltfm.c
new file mode 100644
index 0000000..24debac
--- /dev/null
+++ b/drivers/spi/xilinx_spi_pltfm.c
@@ -0,0 +1,102 @@
+/*
+ * 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 <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 = dev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0)
+ return -ENXIO;
+
+ master = xilinx_spi_init(&dev->dev, r, irq, dev->id);
+ if (!master)
+ return -ENODEV;
+
+ for (i = 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 = {
+ .probe = xilinx_spi_probe,
+ .remove = __devexit_p(xilinx_spi_remove),
+ .driver = {
+ .name = XILINX_SPI_NAME,
+ .owner = 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");
^ permalink raw reply related
* Re: [PATCH v2 1/4] xilinx_spi: Split into of driver and generic part.
From: Grant Likely @ 2009-11-12 14:56 UTC (permalink / raw)
To: Richard Röjfors
Cc: spi-devel-general, Andrew Morton, dbrownell, John Linn,
linuxppc-dev
In-Reply-To: <4AFC1B1E.60304@mocean-labs.com>
On Thu, Nov 12, 2009 at 7:26 AM, Richard R=F6jfors
<richard.rojfors@mocean-labs.com> wrote:
> This patch splits the xilinx_spi driver into a generic part and a
> OF driver part.
>
> The reason for this is to later add in a platform driver as well.
>
> Signed-off-by: Richard R=F6jfors <richard.rojfors@mocean-labs.com>
> ---
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 4b6f7cb..e60b264 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -236,7 +236,7 @@ config SPI_TXX9
>
> =A0config SPI_XILINX
> =A0 =A0 =A0 =A0tristate "Xilinx SPI controller"
> - =A0 =A0 =A0 depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
> + =A0 =A0 =A0 depends on EXPERIMENTAL
> =A0 =A0 =A0 =A0select SPI_BITBANG
> =A0 =A0 =A0 =A0help
> =A0 =A0 =A0 =A0 =A0This exposes the SPI controller IP from the Xilinx EDK=
.
> @@ -244,6 +244,12 @@ config SPI_XILINX
> =A0 =A0 =A0 =A0 =A0See the "OPB Serial Peripheral Interface (SPI) (v1.00e=
)"
> =A0 =A0 =A0 =A0 =A0Product Specification document (DS464) for hardware de=
tails.
>
> +config SPI_XILINX_OF
> + =A0 =A0 =A0 tristate "Xilinx SPI controller OF device"
> + =A0 =A0 =A0 depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE)
> + =A0 =A0 =A0 help
> + =A0 =A0 =A0 =A0 This is the OF driver for the SPI controller IP from th=
e Xilinx EDK.
> +
> =A0#
> =A0# Add new SPI master controllers in alphabetical order above this line
> =A0#
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 21a1182..97dee8f 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -31,6 +31,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0+=3D spi_s3c24xx_gpio.o
> =A0obj-$(CONFIG_SPI_S3C24XX) =A0 =A0 =A0 =A0 =A0 =A0 =A0+=3D spi_s3c24xx.=
o
> =A0obj-$(CONFIG_SPI_TXX9) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 +=3D spi_txx9.o
> =A0obj-$(CONFIG_SPI_XILINX) =A0 =A0 =A0 =A0 =A0 =A0 =A0 +=3D xilinx_spi.o
> +obj-$(CONFIG_SPI_XILINX_OF) =A0 =A0 =A0 =A0 =A0 =A0+=3D xilinx_spi_of.o
> =A0obj-$(CONFIG_SPI_SH_SCI) =A0 =A0 =A0 =A0 =A0 =A0 =A0 +=3D spi_sh_sci.o
> =A0obj-$(CONFIG_SPI_STMP3XXX) =A0 =A0 =A0 =A0 =A0 =A0 +=3D spi_stmp.o
> =A0# =A0 =A0 =A0... add above this line ...
> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
> index 46b8c5c..5761a4c 100644
> --- a/drivers/spi/xilinx_spi.c
> +++ b/drivers/spi/xilinx_spi.c
> @@ -14,16 +14,14 @@
> =A0#include <linux/module.h>
> =A0#include <linux/init.h>
> =A0#include <linux/interrupt.h>
> -#include <linux/platform_device.h>
> -
> -#include <linux/of_platform.h>
> -#include <linux/of_device.h>
> -#include <linux/of_spi.h>
>
> =A0#include <linux/spi/spi.h>
> =A0#include <linux/spi/spi_bitbang.h>
> =A0#include <linux/io.h>
>
> +#include "xilinx_spi.h"
> +#include <linux/spi/xilinx_spi.h>
> +
> =A0#define XILINX_SPI_NAME "xilinx_spi"
>
> =A0/* Register definitions as per "OPB Serial Peripheral Interface (SPI) =
(v1.00e)
> @@ -78,7 +76,7 @@ struct xilinx_spi {
> =A0 =A0 =A0 =A0/* bitbang has to be first */
> =A0 =A0 =A0 =A0struct spi_bitbang bitbang;
> =A0 =A0 =A0 =A0struct completion done;
> -
> + =A0 =A0 =A0 struct resource mem; /* phys mem */
> =A0 =A0 =A0 =A0void __iomem =A0 =A0*regs; =A0/* virt. address of the cont=
rol registers */
>
> =A0 =A0 =A0 =A0u32 =A0 =A0 =A0 =A0 =A0 =A0 irq;
> @@ -283,40 +281,22 @@ static irqreturn_t xilinx_spi_irq(int irq, void *de=
v_id)
> =A0 =A0 =A0 =A0return IRQ_HANDLED;
> =A0}
>
> -static int __init xilinx_spi_of_probe(struct of_device *ofdev,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 const struct of_device_id *match)
> +struct spi_master *xilinx_spi_init(struct device *dev, struct resource *=
mem,
> + =A0 =A0 =A0 u32 irq, s16 bus_num)
> =A0{
> =A0 =A0 =A0 =A0struct spi_master *master;
> =A0 =A0 =A0 =A0struct xilinx_spi *xspi;
> - =A0 =A0 =A0 struct resource r_irq_struct;
> - =A0 =A0 =A0 struct resource r_mem_struct;
> -
> - =A0 =A0 =A0 struct resource *r_irq =3D &r_irq_struct;
> - =A0 =A0 =A0 struct resource *r_mem =3D &r_mem_struct;
> - =A0 =A0 =A0 int rc =3D 0;
> - =A0 =A0 =A0 const u32 *prop;
> - =A0 =A0 =A0 int len;
> -
> - =A0 =A0 =A0 /* Get resources(memory, IRQ) associated with the device */
> - =A0 =A0 =A0 master =3D spi_alloc_master(&ofdev->dev, sizeof(struct xili=
nx_spi));
> + =A0 =A0 =A0 struct xspi_platform_data *pdata =3D dev->platform_data;
> + =A0 =A0 =A0 int ret;
>
> - =A0 =A0 =A0 if (master =3D=3D NULL) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> - =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 dev_set_drvdata(&ofdev->dev, master);
> -
> - =A0 =A0 =A0 rc =3D of_address_to_resource(ofdev->node, 0, r_mem);
> - =A0 =A0 =A0 if (rc) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "invalid address\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto put_master;
> + =A0 =A0 =A0 if (!pdata) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "No platform data attached\n")=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 rc =3D of_irq_to_resource(ofdev->node, 0, r_irq);
> - =A0 =A0 =A0 if (rc =3D=3D NO_IRQ) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "no IRQ found\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto put_master;
> - =A0 =A0 =A0 }
> + =A0 =A0 =A0 master =3D spi_alloc_master(dev, sizeof(struct xilinx_spi))=
;
> + =A0 =A0 =A0 if (!master)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>
> =A0 =A0 =A0 =A0/* the spi->mode bits understood by this driver: */
> =A0 =A0 =A0 =A0master->mode_bits =3D SPI_CPOL | SPI_CPHA;
> @@ -329,128 +309,67 @@ static int __init xilinx_spi_of_probe(struct of_de=
vice *ofdev,
> =A0 =A0 =A0 =A0xspi->bitbang.master->setup =3D xilinx_spi_setup;
> =A0 =A0 =A0 =A0init_completion(&xspi->done);
>
> - =A0 =A0 =A0 xspi->irq =3D r_irq->start;
> -
> - =A0 =A0 =A0 if (!request_mem_region(r_mem->start,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 r_mem->end - r_mem->start +=
1, XILINX_SPI_NAME)) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENXIO;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "memory request failu=
re\n");
> + =A0 =A0 =A0 if (!request_mem_region(mem->start, resource_size(mem),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 XILINX_SPI_NAME))
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto put_master;
> - =A0 =A0 =A0 }
>
> - =A0 =A0 =A0 xspi->regs =3D ioremap(r_mem->start, r_mem->end - r_mem->st=
art + 1);
> + =A0 =A0 =A0 xspi->regs =3D ioremap(mem->start, resource_size(mem));
> =A0 =A0 =A0 =A0if (xspi->regs =3D=3D NULL) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D -ENOMEM;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "ioremap failure\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto release_mem;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(dev, "ioremap failure\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto map_failed;
> =A0 =A0 =A0 =A0}
> - =A0 =A0 =A0 xspi->irq =3D r_irq->start;
>
> - =A0 =A0 =A0 /* dynamic bus assignment */
> - =A0 =A0 =A0 master->bus_num =3D -1;
> + =A0 =A0 =A0 master->bus_num =3D bus_num;
> + =A0 =A0 =A0 master->num_chipselect =3D pdata->num_chipselect;
>
> - =A0 =A0 =A0 /* number of slave select bits is required */
> - =A0 =A0 =A0 prop =3D of_get_property(ofdev->node, "xlnx,num-ss-bits", &=
len);
> - =A0 =A0 =A0 if (!prop || len < sizeof(*prop)) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits=
' property\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto unmap_io;
> - =A0 =A0 =A0 }
> - =A0 =A0 =A0 master->num_chipselect =3D *prop;
> + =A0 =A0 =A0 xspi->mem =3D *mem;
> + =A0 =A0 =A0 xspi->irq =3D irq;
>
> =A0 =A0 =A0 =A0/* SPI controller initializations */
> =A0 =A0 =A0 =A0xspi_init_hw(xspi->regs);
>
> =A0 =A0 =A0 =A0/* Register for SPI Interrupt */
> - =A0 =A0 =A0 rc =3D request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI=
_NAME, xspi);
> - =A0 =A0 =A0 if (rc !=3D 0) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "irq request failure:=
%d\n", xspi->irq);
> + =A0 =A0 =A0 ret =3D request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SP=
I_NAME, xspi);
> + =A0 =A0 =A0 if (ret)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto unmap_io;
> - =A0 =A0 =A0 }
>
> - =A0 =A0 =A0 rc =3D spi_bitbang_start(&xspi->bitbang);
> - =A0 =A0 =A0 if (rc !=3D 0) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&ofdev->dev, "spi_bitbang_start FAI=
LED\n");
> + =A0 =A0 =A0 ret =3D spi_bitbang_start(&xspi->bitbang);
> + =A0 =A0 =A0 if (ret) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "spi_bitbang_start FAILED\n");
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto free_irq;
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=3D%d=
\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (unsigned int)r_mem->start,=
(u32)xspi->regs, xspi->irq);
> -
> - =A0 =A0 =A0 /* Add any subnodes on the SPI bus */
> - =A0 =A0 =A0 of_register_spi_devices(master, ofdev->node);
> -
> - =A0 =A0 =A0 return rc;
> + =A0 =A0 =A0 dev_info(dev, "at 0x%08X mapped to 0x%08X, irq=3D%d\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 (u32)mem->start, (u32)xspi->regs, xspi->irq=
);
> + =A0 =A0 =A0 return master;
>
> =A0free_irq:
> =A0 =A0 =A0 =A0free_irq(xspi->irq, xspi);
> =A0unmap_io:
> =A0 =A0 =A0 =A0iounmap(xspi->regs);
> -release_mem:
> - =A0 =A0 =A0 release_mem_region(r_mem->start, resource_size(r_mem));
> +map_failed:
> + =A0 =A0 =A0 release_mem_region(mem->start, resource_size(mem));
> =A0put_master:
> =A0 =A0 =A0 =A0spi_master_put(master);
> - =A0 =A0 =A0 return rc;
> + =A0 =A0 =A0 return NULL;
> =A0}
> +EXPORT_SYMBOL(xilinx_spi_init);
>
> -static int __devexit xilinx_spi_remove(struct of_device *ofdev)
> +void xilinx_spi_deinit(struct spi_master *master)
> =A0{
> =A0 =A0 =A0 =A0struct xilinx_spi *xspi;
> - =A0 =A0 =A0 struct spi_master *master;
> - =A0 =A0 =A0 struct resource r_mem;
>
> - =A0 =A0 =A0 master =3D platform_get_drvdata(ofdev);
> =A0 =A0 =A0 =A0xspi =3D spi_master_get_devdata(master);
>
> =A0 =A0 =A0 =A0spi_bitbang_stop(&xspi->bitbang);
> =A0 =A0 =A0 =A0free_irq(xspi->irq, xspi);
> =A0 =A0 =A0 =A0iounmap(xspi->regs);
> - =A0 =A0 =A0 if (!of_address_to_resource(ofdev->node, 0, &r_mem))
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 release_mem_region(r_mem.start, resource_si=
ze(&r_mem));
> - =A0 =A0 =A0 dev_set_drvdata(&ofdev->dev, 0);
> - =A0 =A0 =A0 spi_master_put(xspi->bitbang.master);
> -
> - =A0 =A0 =A0 return 0;
> -}
> -
> -/* work with hotplug and coldplug */
> -MODULE_ALIAS("platform:" XILINX_SPI_NAME);
> -
> -static int __exit xilinx_spi_of_remove(struct of_device *op)
> -{
> - =A0 =A0 =A0 return xilinx_spi_remove(op);
> -}
>
> -static struct of_device_id xilinx_spi_of_match[] =3D {
> - =A0 =A0 =A0 { .compatible =3D "xlnx,xps-spi-2.00.a", },
> - =A0 =A0 =A0 { .compatible =3D "xlnx,xps-spi-2.00.b", },
> - =A0 =A0 =A0 {}
> -};
> -
> -MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
> -
> -static struct of_platform_driver xilinx_spi_of_driver =3D {
> - =A0 =A0 =A0 .owner =3D THIS_MODULE,
> - =A0 =A0 =A0 .name =3D "xilinx-xps-spi",
> - =A0 =A0 =A0 .match_table =3D xilinx_spi_of_match,
> - =A0 =A0 =A0 .probe =3D xilinx_spi_of_probe,
> - =A0 =A0 =A0 .remove =3D __exit_p(xilinx_spi_of_remove),
> - =A0 =A0 =A0 .driver =3D {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "xilinx-xps-spi",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 .owner =3D THIS_MODULE,
> - =A0 =A0 =A0 },
> -};
> -
> -static int __init xilinx_spi_init(void)
> -{
> - =A0 =A0 =A0 return of_register_platform_driver(&xilinx_spi_of_driver);
> + =A0 =A0 =A0 release_mem_region(xspi->mem.start, resource_size(&xspi->me=
m));
> + =A0 =A0 =A0 spi_master_put(xspi->bitbang.master);
> =A0}
> -module_init(xilinx_spi_init);
> +EXPORT_SYMBOL(xilinx_spi_deinit);
>
> -static void __exit xilinx_spi_exit(void)
> -{
> - =A0 =A0 =A0 of_unregister_platform_driver(&xilinx_spi_of_driver);
> -}
> -module_exit(xilinx_spi_exit);
> =A0MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
> =A0MODULE_DESCRIPTION("Xilinx SPI driver");
> =A0MODULE_LICENSE("GPL");
> diff --git a/drivers/spi/xilinx_spi.h b/drivers/spi/xilinx_spi.h
> new file mode 100644
> index 0000000..d211acc
> --- /dev/null
> +++ b/drivers/spi/xilinx_spi.h
> @@ -0,0 +1,32 @@
> +/*
> + * Xilinx SPI device driver API and platform data header file
> + *
> + * 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. =A0See 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_
> +
> +#include <linux/spi/spi.h>
> +#include <linux/spi/spi_bitbang.h>
> +
> +#define XILINX_SPI_NAME "xilinx_spi"
> +
> +struct spi_master *xilinx_spi_init(struct device *dev, struct resource *=
mem,
> + =A0 =A0 =A0 u32 irq, s16 bus_num);
> +
> +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..8c3fb54
> --- /dev/null
> +++ b/drivers/spi/xilinx_spi_of.c
> @@ -0,0 +1,136 @@
> +/*
> + * Xilinx SPI OF device driver
> + *
> + * 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. =A0See 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 OF 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/of_platform.h>
> +#include <linux/of_device.h>
> +#include <linux/of_spi.h>
> +
> +#include <linux/spi/xilinx_spi.h>
> +#include "xilinx_spi.h"
> +
> +
> +static int __init xilinx_spi_of_probe(struct of_device *ofdev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 const struct of_device_id *match)
> +{
> + =A0 =A0 =A0 struct resource r_irq_struct;
> + =A0 =A0 =A0 struct resource r_mem_struct;
> + =A0 =A0 =A0 struct spi_master *master;
> +
> + =A0 =A0 =A0 struct resource *r_irq =3D &r_irq_struct;
> + =A0 =A0 =A0 struct resource *r_mem =3D &r_mem_struct;
This r_{irq,mem}_struct/*r_{irq,mem} construct is really weird (I do
understand this is just copied from the old code). r_*_struct can
just be dropped and reference the structures with &r_irq and &_mem.
> + =A0 =A0 =A0 int rc =3D 0;
> + =A0 =A0 =A0 const u32 *prop;
> + =A0 =A0 =A0 int len;
> +
> + =A0 =A0 =A0 rc =3D of_address_to_resource(ofdev->node, 0, r_mem);
> + =A0 =A0 =A0 if (rc) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "invalid address\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return rc;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rc =3D of_irq_to_resource(ofdev->node, 0, r_irq);
> + =A0 =A0 =A0 if (rc =3D=3D NO_IRQ) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "no IRQ found\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (!ofdev->dev.platform_data) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ofdev->dev.platform_data =3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 kzalloc(sizeof(struct xspi_=
platform_data), GFP_KERNEL);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!ofdev->dev.platform_data)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 }
Minor memory leak. Anything alloced in the probe path should also be
freed in the remove path. It's not going to spiral out of control or
anything, but it is important to be strict about such things. Drop
the outer if{} block here and kfree platform_data on remove.
> +
> + =A0 =A0 =A0 /* number of slave select bits is required */
> + =A0 =A0 =A0 prop =3D of_get_property(ofdev->node, "xlnx,num-ss-bits", &=
len);
> + =A0 =A0 =A0 if (!prop || len < sizeof(*prop)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits=
' property\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 ofdev->dev.platform_data->num_chipselect =3D *prop;
Have you compile tested this? platform_data is a void*, the
dereference will not work. I know you don't have hardware; but
getting the needed cross compiler is easy.
> + =A0 =A0 =A0 master =3D xilinx_spi_init(&ofdev->dev, r_mem, r_irq->start=
, -1);
> + =A0 =A0 =A0 if (!master)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> +
> + =A0 =A0 =A0 dev_set_drvdata(&ofdev->dev, master);
> +
> + =A0 =A0 =A0 /* Add any subnodes on the SPI bus */
> + =A0 =A0 =A0 of_register_spi_devices(master, ofdev->node);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int __devexit xilinx_spi_remove(struct of_device *ofdev)
> +{
> + =A0 =A0 =A0 xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
> + =A0 =A0 =A0 dev_set_drvdata(&ofdev->dev, 0);
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int __exit xilinx_spi_of_remove(struct of_device *op)
> +{
> + =A0 =A0 =A0 return xilinx_spi_remove(op);
> +}
> +
> +static struct of_device_id xilinx_spi_of_match[] =3D {
> + =A0 =A0 =A0 { .compatible =3D "xlnx,xps-spi-2.00.a", },
> + =A0 =A0 =A0 { .compatible =3D "xlnx,xps-spi-2.00.b", },
> + =A0 =A0 =A0 {}
> +};
> +
> +MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
> +
> +static struct of_platform_driver xilinx_spi_of_driver =3D {
> + =A0 =A0 =A0 .owner =3D THIS_MODULE,
> + =A0 =A0 =A0 .name =3D "xilinx-xps-spi",
You can actually drop the above two lines. They aren't needed.
> + =A0 =A0 =A0 .match_table =3D xilinx_spi_of_match,
> + =A0 =A0 =A0 .probe =3D xilinx_spi_of_probe,
> + =A0 =A0 =A0 .remove =3D __exit_p(xilinx_spi_of_remove),
> + =A0 =A0 =A0 .driver =3D {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "xilinx-xps-spi",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .owner =3D THIS_MODULE,
> + =A0 =A0 =A0 },
> +};
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH v2 2/4] xilinx_spi: Switch to iomem functions and support little endian.
From: Grant Likely @ 2009-11-12 14:59 UTC (permalink / raw)
To: Richard Röjfors
Cc: spi-devel-general, Andrew Morton, dbrownell, John Linn,
linuxppc-dev
In-Reply-To: <4AFC1B2D.2070809@mocean-labs.com>
On Thu, Nov 12, 2009 at 7:26 AM, Richard R=F6jfors
<richard.rojfors@mocean-labs.com> wrote:
> This patch changes the out_(be)(8|16|32) and in_(be)(8|16|32) calls to 32=
bits ioread/iowrite.
>
> The read and write function are attached to the internal struct as callba=
cks, callback
> is selected depending on endianess.
>
> This will also build on platforms not supporting the in/out calls for ins=
tance x86.
>
> Signed-off-by: Richard R=F6jfors <richard.rojfors@mocean-labs.com>
On brief review looks good to me.
Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index e60b264..9667650 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -236,7 +236,7 @@ config SPI_TXX9
>
> =A0config SPI_XILINX
> =A0 =A0 =A0 =A0tristate "Xilinx SPI controller"
> - =A0 =A0 =A0 depends on EXPERIMENTAL
> + =A0 =A0 =A0 depends on HAS_IOMEM && EXPERIMENTAL
> =A0 =A0 =A0 =A0select SPI_BITBANG
> =A0 =A0 =A0 =A0help
> =A0 =A0 =A0 =A0 =A0This exposes the SPI controller IP from the Xilinx EDK=
.
> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
> index 5761a4c..d0ca13a 100644
> --- a/drivers/spi/xilinx_spi.c
> +++ b/drivers/spi/xilinx_spi.c
> @@ -27,7 +27,7 @@
> =A0/* Register definitions as per "OPB Serial Peripheral Interface (SPI) =
(v1.00e)
> =A0* Product Specification", DS464
> =A0*/
> -#define XSPI_CR_OFFSET =A0 =A0 =A0 =A0 0x62 =A0 =A0/* 16-bit Control Reg=
ister */
> +#define XSPI_CR_OFFSET =A0 =A0 =A0 =A0 0x60 =A0 =A0/* 16-bit Control Reg=
ister */
>
> =A0#define XSPI_CR_ENABLE =A0 =A0 =A0 =A0 0x02
> =A0#define XSPI_CR_MASTER_MODE =A0 =A00x04
> @@ -39,7 +39,7 @@
> =A0#define XSPI_CR_MANUAL_SSELECT 0x80
> =A0#define XSPI_CR_TRANS_INHIBIT =A00x100
>
> -#define XSPI_SR_OFFSET =A0 =A0 =A0 =A0 0x67 =A0 =A0/* 8-bit Status Regis=
ter */
> +#define XSPI_SR_OFFSET =A0 =A0 =A0 =A0 0x64 =A0 =A0/* 8-bit Status Regis=
ter */
>
> =A0#define XSPI_SR_RX_EMPTY_MASK =A00x01 =A0 =A0/* Receive FIFO is empty =
*/
> =A0#define XSPI_SR_RX_FULL_MASK =A0 0x02 =A0 =A0/* Receive FIFO is full *=
/
> @@ -47,8 +47,8 @@
> =A0#define XSPI_SR_TX_FULL_MASK =A0 0x08 =A0 =A0/* Transmit FIFO is full =
*/
> =A0#define XSPI_SR_MODE_FAULT_MASK =A0 =A0 =A0 =A00x10 =A0 =A0/* Mode fau=
lt error */
>
> -#define XSPI_TXD_OFFSET =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x6b =A0 =A0/* 8-=
bit Data Transmit Register */
> -#define XSPI_RXD_OFFSET =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x6f =A0 =A0/* 8-=
bit Data Receive Register */
> +#define XSPI_TXD_OFFSET =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x68 =A0 =A0/* 8-=
bit Data Transmit Register */
> +#define XSPI_RXD_OFFSET =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x6c =A0 =A0/* 8-=
bit Data Receive Register */
>
> =A0#define XSPI_SSR_OFFSET =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x70 =A0 =A0/* =
32-bit Slave Select Register */
>
> @@ -86,25 +86,29 @@ struct xilinx_spi {
> =A0 =A0 =A0 =A0u8 *rx_ptr; =A0 =A0 =A0 =A0 =A0 =A0 /* pointer in the Tx b=
uffer */
> =A0 =A0 =A0 =A0const u8 *tx_ptr; =A0 =A0 =A0 /* pointer in the Rx buffer =
*/
> =A0 =A0 =A0 =A0int remaining_bytes; =A0 =A0/* the number of bytes left to=
transfer */
> + =A0 =A0 =A0 unsigned int (*read_fn) (void __iomem *);
> + =A0 =A0 =A0 void (*write_fn) (u32, void __iomem *);
> =A0};
>
> -static void xspi_init_hw(void __iomem *regs_base)
> +static void xspi_init_hw(struct xilinx_spi *xspi)
> =A0{
> + =A0 =A0 =A0 void __iomem *regs_base =3D xspi->regs;
> +
> =A0 =A0 =A0 =A0/* Reset the SPI device */
> - =A0 =A0 =A0 out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XIPIF_V123B_RESET_MASK);
> + =A0 =A0 =A0 xspi->write_fn(XIPIF_V123B_RESET_MASK,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 regs_base + XIPIF_V123B_RESETR_OFFSET);
> =A0 =A0 =A0 =A0/* Disable all the interrupts just in case */
> - =A0 =A0 =A0 out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
> + =A0 =A0 =A0 xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
> =A0 =A0 =A0 =A0/* Enable the global IPIF interrupt */
> - =A0 =A0 =A0 out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XIPIF_V123B_GINTR_ENABLE);
> + =A0 =A0 =A0 xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 regs_base + XIPIF_V123B_DGIER_OFFSET);
> =A0 =A0 =A0 =A0/* Deselect the slave on the SPI bus */
> - =A0 =A0 =A0 out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
> + =A0 =A0 =A0 xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
> =A0 =A0 =A0 =A0/* Disable the transmitter, enable Manual Slave Select Ass=
ertion,
> =A0 =A0 =A0 =A0 * put SPI controller into master mode, and enable it */
> - =A0 =A0 =A0 out_be16(regs_base + XSPI_CR_OFFSET,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_S=
SELECT
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
> + =A0 =A0 =A0 xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELE=
CT |
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 regs_base + XSPI_CR_OFFSET);
> =A0}
>
> =A0static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
> @@ -113,16 +117,16 @@ static void xilinx_spi_chipselect(struct spi_device=
*spi, int is_on)
>
> =A0 =A0 =A0 =A0if (is_on =3D=3D BITBANG_CS_INACTIVE) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Deselect the slave on the SPI bus */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xff=
ff);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn(0xffff, xspi->regs + XSPI_SS=
R_OFFSET);
> =A0 =A0 =A0 =A0} else if (is_on =3D=3D BITBANG_CS_ACTIVE) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Set the SPI clock phase and polarity */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 u16 cr =3D in_be16(xspi->regs + XSPI_CR_OFF=
SET)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 u16 cr =3D xspi->read_fn(xspi->regs + XSPI_=
CR_OFFSET)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 & ~XSPI_CR_MODE_MASK;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (spi->mode & SPI_CPHA)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cr |=3D XSPI_CR_CPHA;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (spi->mode & SPI_CPOL)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cr |=3D XSPI_CR_CPOL;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn(cr, xspi->regs + XSPI_CR_OFF=
SET);
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* We do not check spi->max_speed_hz here =
as the SPI clock
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * frequency is not software programmable =
(the IP block design
> @@ -130,8 +134,8 @@ static void xilinx_spi_chipselect(struct spi_device *=
spi, int is_on)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 */
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Activate the chip select */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(xspi->regs + XSPI_SSR_OFFSET,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0~(0x0001 << spi->chip_se=
lect));
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn(~(0x0001 << spi->chip_select=
),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->regs + XSPI_SSR_OFFSE=
T);
> =A0 =A0 =A0 =A0}
> =A0}
>
> @@ -177,15 +181,15 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_s=
pi *xspi)
> =A0 =A0 =A0 =A0u8 sr;
>
> =A0 =A0 =A0 =A0/* Fill the Tx FIFO with as many bytes as possible */
> - =A0 =A0 =A0 sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> + =A0 =A0 =A0 sr =3D xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
> =A0 =A0 =A0 =A0while ((sr & XSPI_SR_TX_FULL_MASK) =3D=3D 0 && xspi->remai=
ning_bytes > 0) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (xspi->tx_ptr) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(xspi->regs + XSPI_TXD=
_OFFSET, *xspi->tx_ptr++);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(xspi->regs + XSPI_TXD=
_OFFSET, 0);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (xspi->tx_ptr)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn(*xspi->tx_pt=
r++,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->regs =
+ XSPI_TXD_OFFSET);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn(0, xspi->reg=
s + XSPI_TXD_OFFSET);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0xspi->remaining_bytes--;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 sr =3D xspi->read_fn(xspi->regs + XSPI_SR_O=
FFSET);
> =A0 =A0 =A0 =A0}
> =A0}
>
> @@ -207,18 +211,19 @@ static int xilinx_spi_txrx_bufs(struct spi_device *=
spi, struct spi_transfer *t)
> =A0 =A0 =A0 =A0/* Enable the transmit empty interrupt, which we use to de=
termine
> =A0 =A0 =A0 =A0 * progress on the transmission.
> =A0 =A0 =A0 =A0 */
> - =A0 =A0 =A0 ipif_ier =3D in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
> - =A0 =A0 =A0 out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ipif_ier | XSPI_INTR_TX_EMPTY);
> + =A0 =A0 =A0 ipif_ier =3D xspi->read_fn(xspi->regs + XIPIF_V123B_IIER_OF=
FSET);
> + =A0 =A0 =A0 xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->regs + XIPIF_V123B_IIER_OFFSET);
>
> =A0 =A0 =A0 =A0/* Start the transfer by not inhibiting the transmitter an=
y longer */
> - =A0 =A0 =A0 cr =3D in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRAN=
S_INHIBIT;
> - =A0 =A0 =A0 out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
> + =A0 =A0 =A0 cr =3D xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) &
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ~XSPI_CR_TRANS_INHIBIT;
> + =A0 =A0 =A0 xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
>
> =A0 =A0 =A0 =A0wait_for_completion(&xspi->done);
>
> =A0 =A0 =A0 =A0/* Disable the transmit empty interrupt */
> - =A0 =A0 =A0 out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
> + =A0 =A0 =A0 xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFS=
ET);
>
> =A0 =A0 =A0 =A0return t->len - xspi->remaining_bytes;
> =A0}
> @@ -235,8 +240,8 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_=
id)
> =A0 =A0 =A0 =A0u32 ipif_isr;
>
> =A0 =A0 =A0 =A0/* Get the IPIF interrupts, and clear them immediately */
> - =A0 =A0 =A0 ipif_isr =3D in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
> - =A0 =A0 =A0 out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
> + =A0 =A0 =A0 ipif_isr =3D xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OF=
FSET);
> + =A0 =A0 =A0 xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFS=
ET);
>
> =A0 =A0 =A0 =A0if (ipif_isr & XSPI_INTR_TX_EMPTY) { =A0 =A0/* Transmissio=
n completed */
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u16 cr;
> @@ -247,20 +252,20 @@ static irqreturn_t xilinx_spi_irq(int irq, void *de=
v_id)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * transmitter while the Isr refills the t=
ransmit register/FIFO,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * or make sure it is stopped if we're don=
e.
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 cr =3D in_be16(xspi->regs + XSPI_CR_OFFSET)=
;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be16(xspi->regs + XSPI_CR_OFFSET,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cr | XSPI_CR_TRANS_INHIB=
IT);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 cr =3D xspi->read_fn(xspi->regs + XSPI_CR_O=
FFSET);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->regs + XSPI_CR_OFFSET=
);
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Read out all the data from the Rx FIFO =
*/
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 sr =3D in_8(xspi->regs + XSPI_SR_OFFSET);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 sr =3D xspi->read_fn(xspi->regs + XSPI_SR_O=
FFSET);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0while ((sr & XSPI_SR_RX_EMPTY_MASK) =3D=3D=
0) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u8 data;
>
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 data =3D in_8(xspi->regs + =
XSPI_RXD_OFFSET);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 data =3D xspi->read_fn(xspi=
->regs + XSPI_RXD_OFFSET);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (xspi->rx_ptr) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*xspi->rx_=
ptr++ =3D data;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sr =3D in_8(xspi->regs + XS=
PI_SR_OFFSET);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sr =3D xspi->read_fn(xspi->=
regs + XSPI_SR_OFFSET);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* See if there is more data to send */
> @@ -269,7 +274,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_=
id)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Start the transfer by n=
ot inhibiting the
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * transmitter any longer
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be16(xspi->regs + XSPI_=
CR_OFFSET, cr);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn(cr, xspi->re=
gs + XSPI_CR_OFFSET);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} else {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* No more data to send.
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * Indicate the transfer i=
s completed.
> @@ -324,9 +329,16 @@ struct spi_master *xilinx_spi_init(struct device *de=
v, struct resource *mem,
>
> =A0 =A0 =A0 =A0xspi->mem =3D *mem;
> =A0 =A0 =A0 =A0xspi->irq =3D irq;
> + =A0 =A0 =A0 if (pdata->little_endian) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->read_fn =3D ioread32;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn =3D iowrite32;
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->read_fn =3D ioread32be;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 xspi->write_fn =3D iowrite32be;
> + =A0 =A0 =A0 }
>
> =A0 =A0 =A0 =A0/* SPI controller initializations */
> - =A0 =A0 =A0 xspi_init_hw(xspi->regs);
> + =A0 =A0 =A0 xspi_init_hw(xspi);
>
> =A0 =A0 =A0 =A0/* Register for SPI Interrupt */
> =A0 =A0 =A0 =A0ret =3D request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_S=
PI_NAME, xspi);
> diff --git a/include/linux/spi/xilinx_spi.h b/include/linux/spi/xilinx_sp=
i.h
> index 06df0ab..a705ad8 100644
> --- a/include/linux/spi/xilinx_spi.h
> +++ b/include/linux/spi/xilinx_spi.h
> @@ -4,11 +4,13 @@
> =A0/**
> =A0* struct xspi_platform_data - Platform data of the Xilinx SPI driver
> =A0* @num_chipselect: =A0 =A0Number of chip select by the IP
> + * @little_endian =A0 =A0 =A0If registers should be accessed little endi=
an or not
> =A0* @devices: =A0 =A0 =A0 =A0 =A0 Devices to add when the driver is prob=
ed.
> =A0* @num_devices: =A0 =A0 =A0 Number of devices in the devices array.
> =A0*/
> =A0struct xspi_platform_data {
> =A0 =A0 =A0 =A0u16 num_chipselect;
> + =A0 =A0 =A0 bool little_endian;
> =A0 =A0 =A0 =A0struct spi_board_info *devices;
> =A0 =A0 =A0 =A0u8 num_devices;
> =A0};
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox