Simple driver for Xilinx SPI controler.
Subsystems (3)
PATCH 1/1 Simple driver for Xilinx SPI controler.
Only master mode is supported.
No support for multiple masters. Slave mode is not supported either. Not using level 1 drivers from EDK.
The reason not to use EDK is basically this driver being a simple one:
- SPI level 1 driver from EDK supports much more then needed for this simple version of the SPI driver (slave mode, multiple masters etc). And leaving just single master case alone is not possible without changing the level 1 driver.
- SPI level 1 driver from EDK manipulates chip selects on its own. This makes it impossible to use the spi_bitbang.
The driver has been tested with Xilinx ML300 reference design.
The patch to enable SPI for Xilinx ML300 board (EDK reference design) will be sent to linuxppc-embedded list shortly.
Would be nice to get this driver into mainline.
Reviews and comments are welcome.
Thanks,
Andrei
--- arch/ppc/syslib/virtex_devices.h | 6 + drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 + drivers/spi/xilinx_spi.c | 447 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 463 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/xilinx_spi.c
arch/ppc/syslib/virtex_devices.h +6 -0
@@ -45,4 +45,10 @@ struct xtemac_platform_data { u8 mac_addr[6]; }; +/* SPI Controller IP */ +struct xspi_platform_data { +s16 bus_num; +u16 num_chipselect; +}; +#endif /* __ASM_VIRTEX_DEVICES_H__ */
drivers/spi/Kconfig +9 -0
@@ -156,6 +156,15 @@ config SPI_S3C24XX_GPIO GPIO lines to provide the SPI bus. This can be used where the inbuilt hardware cannot provide the transfer mode, or where the board is using non hardware connected pins. + +config SPI_XILINX + tristate "Xilinx SPI controller" + depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL + select SPI_BITBANG + help + This enables using the SPI controller IP from Xilinx EDK in master + mode. See the DS464, "OPB Serial Peripheral Interface (SPI) (v1.00e)" + Product Specification document for the hardware details. # # Add new SPI master controllers in alphabetical order above this line #
drivers/spi/Makefile +1 -0
@@ -23,6 +23,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o +obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o # ... add above this line ... # SPI protocol drivers (device/link on bus)
drivers/spi/xilinx_spi.c new file +447 -0
447 lines not on this page · raw message
Signature · 1 line
1.5.1.1
In order to anticipate future Microblaze support with most of these drivers,
we've been moving towards having all of the Kconfig dependencies on XILINX_EDK,
rather than XILINX_VIRTEX...
Steve Neuendorffer
Quoted 5 lines
-----Original Message-----
From:
[email protected][mailto:linuxppc-embedded-bounces+stephen=neuendorffer.name@oz
labs.org] On Behalf Of Andrei Konovalov
Quoted 538 lines
Sent: Wednesday, June 06, 2007 7:06 AM
To: [email protected]
Cc: [email protected]
Subject: [PATCH] Simple driver for Xilinx SPI controler.drivers/spi/Kconfig +6
-0+config SPI_XILINX + tristate "Xilinx SPI controller" + depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL + select SPI_BITBANG + help + This enables using the SPI controller IP from XilinxEDK in master
(quoted diff) +1
-0+ mode. See the DS464, "OPB Serial Peripheral Interface(SPI) (v1.00e)"
drivers/spi/Kconfig +1
-0+ Product Specification document for the hardware details. # # Add new SPI master controllers in alphabetical orderabove this line
#drivers/spi/Makefile +2
-0@@ -23,6 +23,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o +obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o # ... add above this line ... # SPI protocol drivers (device/link on bus) diff --git
a/drivers/spi/xilinx_spi.cb/drivers/spi/xilinx_spi.cnew file mode 100644 index 0000000..e5f149fdrivers/spi/xilinx_spi.c new file +9
-0@@ -0,0 +1,447 @@ +/* +* xilinx_spi.c +* +* Xilinx SPI controler driver (master mode only) +* +* Author: MontaVista Software, Inc. +* [email protected] +* +* 2002-2007 (c) MontaVista Software, Inc. This file is licensed under
+the
+ * terms of the GNU General Public License version 2. This program is
+licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */drivers/spi/xilinx_spi.c new file +14
-0+ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> + +#include <asm/io.h> +#include <syslib/virtex_devices.h> + +#define XILINX_SPI_NAME "xspi" + +/* Register definitions as per "OPB Serial Peripheral Interface (SPI)
drivers/spi/xilinx_spi.c new file +4
-0+(v1.00e) +* Product Specification", DS464 +*/ +#define XSPI_CR_OFFSET 0x62/* 16-bit Control Register */
drivers/spi/xilinx_spi.c new file +12
-0+ +#define XSPI_CR_ENABLE 0x02 +#define XSPI_CR_MASTER_MODE 0x04 +#define XSPI_CR_CPOL 0x08 +#define XSPI_CR_CPHA 0x10 +#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL) +#define XSPI_CR_TXFIFO_RESET 0x20 +#define XSPI_CR_RXFIFO_RESET 0x40 +#define XSPI_CR_MANUAL_SSELECT 0x80 +#define XSPI_CR_TRANS_INHIBIT 0x100 + +#define XSPI_SR_OFFSET 0x67/* 8-bit Status Register */
drivers/spi/xilinx_spi.c new file +2
-0+ +#define XSPI_SR_RX_EMPTY_MASK 0x01/* Receive FIFO is empty */
drivers/spi/xilinx_spi.c new file +2
-0+#define XSPI_SR_RX_FULL_MASK 0x02/* Receive FIFO is full */ +#define XSPI_SR_TX_EMPTY_MASK 0x04/* Transmit FIFO is empty */
drivers/spi/xilinx_spi.c new file +4
-0+#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 */
+#defineXSPI_RXD_OFFSET0x6f/* 8-bit Data
Receive Register */drivers/spi/xilinx_spi.c new file +2
-0+ +#define XSPI_SSR_OFFSET 0x70/* 32-bit Slave Select Register */
drivers/spi/xilinx_spi.c new file +6
-0+ +/* Register definitions as per "OPB IPIF (v3.01c) Product +Specification", DS414 +* IPIF registers are 32 bit +*/ +#define XIPIF_V123B_DGIER_OFFSET 0x1c/* IPIF global int enable reg */
drivers/spi/xilinx_spi.c new file +3
-0+#define XIPIF_V123B_GINTR_ENABLE 0x80000000 + +#define XIPIF_V123B_IISR_OFFSET 0x20/* IPIF interrupt status reg */
+#defineXIPIF_V123B_IIER_OFFSET0x28/* IPIF
interrupt enable reg */drivers/spi/xilinx_spi.c new file +3
-0+ +#define XSPI_INTR_MODE_FAULT 0x01/* Mode fault error */ +#define XSPI_INTR_SLAVE_MODE_FAULT 0x02/* Selected as slave while
drivers/spi/xilinx_spi.c new file +3
-0+* disabled */ +#define XSPI_INTR_TX_EMPTY 0x04/* TxFIFO is empty */ +#define XSPI_INTR_TX_UNDERRUN 0x08/* TxFIFO was underrun */
drivers/spi/xilinx_spi.c new file +4
-0+#define XSPI_INTR_RX_FULL 0x10/* RxFIFO is full */ +#define XSPI_INTR_RX_OVERRUN 0x20/* RxFIFO was overrun */ + +#define XIPIF_V123B_RESETR_OFFSET 0x40/* IPIF reset register */
+#defineXIPIF_V123B_RESET_MASK0x0a/* the
value to write */drivers/spi/xilinx_spi.c new file +5
-0+ +/* Simple macros to get the code more readable */ +#define xspi_in16 (addr) in_be16((u16 __iomem *)(addr)) +#define xspi_in32 (addr) in_be32((u32 __iomem *)(addr)) +#define xspi_out16 (addr, value) out_be16((u16 __iomem*)(addr), (value))
+#definexspi_out32(addr, value)out_be32((u32__iomem
*)(addr), (value))drivers/spi/xilinx_spi.c new file +7
-0+ +struct xilinx_spi { +/* bitbang has to be first */ +struct spi_bitbang bitbang; +struct completion done; + +u32 regs_phys;/* phys. address of the control registers */
drivers/spi/xilinx_spi.c new file +1
-0+void __iomem *regs;/* virt. address of the control registers */
drivers/spi/xilinx_spi.c new file +6
-0+ +u32 irq; + +u8 *rx_ptr;/* pointer in the Tx buffer */ +const u8 *tx_ptr;/* pointer in the Rx buffer */ +int remaining_bytes;/* the number of bytes left to transfer */
drivers/spi/xilinx_spi.c new file +7
-0+}; + +static void xspi_abort_transfer (u8 __iomem *regs_base) { +/* Deselect the slave on the SPI bus */ +xspi_out32 (regs_base +XSPI_SSR_OFFSET ,0xffff ); + +/* Terminate transmit in progress (if any) and Reset the FIFOs */
drivers/spi/xilinx_spi.c new file +18
-0+xspi_out16 (regs_base +XSPI_CR_OFFSET , +xspi_in16 (regs_base +XSPI_CR_OFFSET ) + |XSPI_CR_TRANS_INHIBIT |XSPI_CR_TXFIFO_RESET + |XSPI_CR_RXFIFO_RESET ); +} + +static void xspi_init_hw (u8 __iomem *regs_base) { +/* Reset the SPI device */ +xspi_out32 (regs_base +XIPIF_V123B_RESETR_OFFSET , +XIPIF_V123B_RESET_MASK ); +/* Disable all the interrupts just in case */ +xspi_out32 (regs_base +XIPIF_V123B_IIER_OFFSET ,0 ); +/* Enable the global IPIF interrupt */ +xspi_out32 (regs_base +XIPIF_V123B_DGIER_OFFSET , +XIPIF_V123B_GINTR_ENABLE ); +/* Deselect the slave on the SPI bus */ +xspi_out32 (regs_base +XSPI_SSR_OFFSET ,0xffff ); +/* Disable the transmitter, enable Manual Slave Select Assertion,
drivers/spi/xilinx_spi.c new file +6
-0+* put SPI controller into master mode, and enable it */ +xspi_out16 (regs_base +XSPI_CR_OFFSET , +XSPI_CR_TRANS_INHIBIT |XSPI_CR_MANUAL_SSELECT + |XSPI_CR_MASTER_MODE |XSPI_CR_ENABLE ); } + +static void xilinx_spi_chipselect(struct spi_device *spi,int
is_on) {drivers/spi/xilinx_spi.c new file +20
-0+struct xilinx_spi *xspi; +u8 __iomem *regs_base; + + xspi =spi_master_get_devdata (spi->master); + regs_base = xspi->regs; + +if (is_on ==BITBANG_CS_INACTIVE ) { +/* Deselect the slave on the SPI bus */ +xspi_out32 (regs_base +XSPI_SSR_OFFSET ,0xffff ); + }else if (is_on ==BITBANG_CS_ACTIVE ) { +/* Set the SPI clock phase and polarity */ +u16 cr =xspi_in16 (regs_base +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 ; +xspi_out16 (regs_base +XSPI_CR_OFFSET , cr); + +/* We do not check spi->max_speed_hz here as the SPI clock
drivers/spi/xilinx_spi.c new file +1
-0+* frequency is not software programmable (the IP block design
drivers/spi/xilinx_spi.c new file +10
-0+* parameter) +*/ + +/* Activate the chip select */ +xspi_out32 (regs_base +XSPI_SSR_OFFSET , + ~(0x0001 << spi->chip_select)); + } +} + +/* spi_bitbang requires custom setup_transfer() to be defined if there
drivers/spi/xilinx_spi.c new file +4
-0+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 bechanged in software.
+ * Check for 8 bits per word;speed_hzchecking could be added if the
+SPI
+ * clock information is available. Chip select delay calculations could
+be
+ * added here as soon asbitbang_work()can be made aware of the delay value.
+ */drivers/spi/xilinx_spi.c new file +56
-0+static int xilinx_spi_setup_transfer (struct spi_device *spi, +struct spi_transfer *t) +{ +u8 bits_per_word; + + bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; +if (bits_per_word !=8 ) +return -EINVAL ; + +return 0 ; +} + + +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; + +if (!spi->bits_per_word) + spi->bits_per_word =8 ; + + retval =xilinx_spi_setup_transfer (spi,NULL ); +if (retval <0 ) +return retval; + +dev_dbg (&spi->dev,"%s, mode %d, %u bits/w, %u nsec/bit\n" , + __FUNCTION__, spi->mode & (SPI_CPOL |SPI_CPHA ), + spi->bits_per_word,0 ); + +return 0 ; +} + +static int xilinx_spi_txrx_bufs (struct spi_device *spi,struct +spi_transfer *t) { +struct xilinx_spi *xspi; +u8 __iomem *regs_base; +u32 ipif_ier; +u16 cr; +u8 sr; + +/* We get here with transmitter inhibited */ + + xspi =spi_master_get_devdata (spi->master); + regs_base = xspi->regs; + + xspi->tx_ptr = t->tx_buf; + xspi->rx_ptr = t->rx_buf; + xspi->remaining_bytes = t->len; +INIT_COMPLETION (xspi->done); + +/* Fill the Tx FIFO with as many bytes as possible */ + sr =in_8 (regs_base +XSPI_SR_OFFSET ); + while ((sr & XSPI_SR_TX_FULL_MASK) == 0 &&
xspi->remaining_bytes> 0) {drivers/spi/xilinx_spi.c new file +2
-0+if (xspi->tx_ptr) { + out_8(regs_base + XSPI_TXD_OFFSET,*xspi->tx_ptr++);
drivers/spi/xilinx_spi.c new file +8
-0+ }else { +out_8 (regs_base +XSPI_TXD_OFFSET ,0 ); + } + xspi->remaining_bytes--; + sr =in_8 (regs_base +XSPI_SR_OFFSET ); + } + +/* Enable the transmit empty interrupt, which we use to determine
drivers/spi/xilinx_spi.c new file +7
-0+* progress on the transmission. +*/ + ipif_ier =xspi_in32 (regs_base +XIPIF_V123B_IIER_OFFSET ); +xspi_out32 (regs_base +XIPIF_V123B_IIER_OFFSET , + ipif_ier |XSPI_INTR_TX_EMPTY ); + +/* Start the transfer by not inhibiting the transmitter any longer */
drivers/spi/xilinx_spi.c new file +1
-0+ cr = xspi_in16(regs_base + XSPI_CR_OFFSET) &~XSPI_CR_TRANS_INHIBIT;
drivers/spi/xilinx_spi.c new file +13
-0+xspi_out16 (regs_base +XSPI_CR_OFFSET , cr); + +wait_for_completion (&xspi->done); + +/* Disable the transmit empty interrupt */ +xspi_out32 (regs_base +XIPIF_V123B_IIER_OFFSET , ipif_ier); + +return t->len - xspi->remaining_bytes; } + + +/* This driver supports single master mode only. Hence Tx FIFO Empty +* is the only interrupt we care about. +* Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave
drivers/spi/xilinx_spi.c new file +12
-0+Mode +* Fault are not to happen. +*/ +static irqreturn_t xilinx_spi_irq (int irq,void *dev_id) { +struct xilinx_spi *xspi; +u8 __iomem *regs_base; +u32 ipif_isr; + + xspi = (struct xilinx_spi *) dev_id; + regs_base = xspi->regs; + +/* Get the IPIF inetrrupts, and clear them immediately */
drivers/spi/xilinx_spi.c new file +4
-0+ ipif_isr =xspi_in32 (regs_base +XIPIF_V123B_IISR_OFFSET ); +xspi_out32 (regs_base +XIPIF_V123B_IISR_OFFSET , ipif_isr); + +if (ipif_isr &XSPI_INTR_TX_EMPTY ) {/* Transmission completed */
drivers/spi/xilinx_spi.c new file +4
-0+u16 cr; +u8 sr; + +/* A transmit has just completed. Process received data and
drivers/spi/xilinx_spi.c new file +2
-0+* check for more data to transmit. Always inhibit the +* transmitter while the Isr refills the transmit register/FIFO,
drivers/spi/xilinx_spi.c new file +21
-0+* or make sure it is stopped if we're done. +*/ + cr =xspi_in16 (regs_base +XSPI_CR_OFFSET ); +xspi_out16 (regs_base +XSPI_CR_OFFSET , + cr |XSPI_CR_TRANS_INHIBIT ); + +/* Read out all the data from the Rx FIFO */ + sr =in_8 (regs_base +XSPI_SR_OFFSET ); +while ((sr &XSPI_SR_RX_EMPTY_MASK ) ==0 ) { +u8 data; + + data =in_8 (regs_base +XSPI_RXD_OFFSET ); +if (xspi->rx_ptr) { + *xspi->rx_ptr++ = data; + } + sr =in_8 (regs_base +XSPI_SR_OFFSET ); + } + +/* See if there is more data to send */ +if (xspi->remaining_bytes >0 ) { +/* sr content is valid here; no need for
io_8()*/drivers/spi/xilinx_spi.c new file +4
-0+while ((sr &XSPI_SR_TX_FULL_MASK ) ==0 + && xspi->remaining_bytes >0 ) { +if (xspi->tx_ptr) { + out_8(regs_base +
XSPI_TXD_OFFSET,drivers/spi/xilinx_spi.c new file +3
-0+ *xspi->tx_ptr++); + }else { + out_8(regs_base +
XSPI_TXD_OFFSET, 0);drivers/spi/xilinx_spi.c new file +77
-0+ } + xspi->remaining_bytes--; + sr =in_8 (regs_base +XSPI_SR_OFFSET ); + } +/* Start the transfer by not inhibiting the +* transmitter any longer +*/ +xspi_out16 (regs_base +XSPI_CR_OFFSET , cr); + }else { +/* No more data to send. +* Indicate the transfer is completed. +*/ +complete (&xspi->done); + } + }else { +/* spurious interrupt */ + } + +return IRQ_HANDLED ; +} + +static int __init xilinx_spi_probe (struct platform_device *dev) { +int ret =0 ; +struct spi_master *master; +struct xilinx_spi *xspi; +struct xspi_platform_data *pdata; +struct resource *r; + +/* Get resources(memory, IRQ) associated with the device */ + master =spi_alloc_master (&dev->dev,sizeof (struct xilinx_spi )); + +if (master ==NULL ) { +return -ENOMEM ; + } + +platform_set_drvdata (dev, master); + pdata = dev->dev.platform_data; + +if (pdata ==NULL ) { + ret = -ENODEV ; + goto put_master; + } + + r =platform_get_resource (dev,IORESOURCE_MEM ,0 ); +if (r ==NULL ) { + ret = -ENODEV ; + goto put_master; + } + + xspi =spi_master_get_devdata (master); + xspi->bitbang.master =spi_master_get (master); + xspi->bitbang.chipselect = xilinx_spi_chipselect; + xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; + xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; + xspi->bitbang.master->setup = xilinx_spi_setup; +init_completion (&xspi->done); + + xspi->regs =ioremap (r->start, r->end - r->start +1 ); +if (xspi->regs ==NULL ) { + ret = -ENOMEM ; + goto put_master; + } + + xspi->irq =platform_get_irq (dev,0 ); +if (xspi->irq <0 ) { + ret = -ENXIO ; + goto unmap_io; + } + + master->bus_num = pdata->bus_num; + master->num_chipselect = pdata->num_chipselect; + +/* SPI controller initializations */ +xspi_init_hw (xspi->regs); + +/* Register for SPI Interrupt */ + ret = request_irq(xspi->irq, xilinx_spi_irq, 0,
XILINX_SPI_NAME, xspi);drivers/spi/xilinx_spi.c new file +62
-1+if (ret !=0 ) + goto unmap_io; + + ret =spi_bitbang_start (&xspi->bitbang); +if (ret !=0 ) { +printk (KERN_ALERT "spi_btbang_start FAILED\n" ); + goto free_irq; + } + +printk (KERN_INFO "%s: at 0x%08X mapped to 0x%08X, irq=%d\n" , + dev->dev.bus_id, r->start, (u32 )xspi->regs, xspi->irq); + +return ret; + +free_irq: +free_irq (xspi->irq, xspi); +unmap_io: +iounmap (xspi->regs); +put_master: +spi_master_put (master); +return ret; +} + +static int __devexit xilinx_spi_remove(struct platform_device *dev) { +struct xilinx_spi *xspi; +struct spi_master *master; + + master =platform_get_drvdata (dev); + xspi =spi_master_get_devdata (master); + +spi_bitbang_stop (&xspi->bitbang); +xspi_abort_transfer (xspi->regs); +free_irq (xspi->irq, xspi); +iounmap (xspi->regs); +platform_set_drvdata (dev,0 ); +spi_master_put (xspi->bitbang.master); + +return 0 ; +} + +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_init (void ) { +return platform_driver_register (&xilinx_spi_driver); +} + +static void __exit xilinx_spi_exit(void) { +platform_driver_unregister (&xilinx_spi_driver); +} + +module_init (xilinx_spi_init); +module_exit (xilinx_spi_exit); + +MODULE_AUTHOR ("MontaVista Software, Inc. <[email protected]>" ); +MODULE_DESCRIPTION ("Xilinx SPI driver" );MODULE_LICENSE ("GPL" ); --1.5.1.1
_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
Hi Steve,
Quoted 4 lines · Stephen Neuendorffer
In order to anticipate future Microblaze support with most of these drivers,
we've been moving towards having all of theKconfigdependencies onXILINX_EDK,
There is no XILINX_EDK in the ko tree.
Quoted 1 line
rather than
XILINX_VIRTEX...
Using XILINX_VIRTEX seems to be a common thing:
Quoted 8 lines
-------- Original Message --------
Subject: [RFC] Xilinx SystemACE device driver
Date: Sat, 14 Apr 2007 19:23:14 -0600
From: Grant Likely <[email protected]>
To: [email protected], Andrei Konovalov <[email protected]>, Peter Korsgaard <[email protected]>, Rick Moleres <[email protected]>, Stefan Roese <[email protected]>Add support for block device access to the Xilinx SystemACE Compact flash interface
<snip>
Quoted 5 lines
drivers/block/Kconfig +0
-0
drivers/block/Kconfig config ATA_OVER_ETH · line 461
Quoted 9 lines
drivers/block/Kconfig +6
-0@@ -453,6 +453,12 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +config XILINX_SYSACE + tristate "Xilinx SystemACE support" + depends on XILINX_VIRTEX + help + Include support for the Xilinx SystemACE CompactFlash interface +
BTW the SystemACE has been successfully tested with ppc440 based board. So XILINX_VIRTEX doesn't imply ppc405.
On the other side,
UART Lite driver (in the ko tree) doesn't depend on both XILINX_EDK and XILINX_VIRTEX
Couldn't Microblaze port use XILINX_VIRTEX too?
IMHO XILINX_VIRTEX is more general name for something inside the Virtex chip (ppc405 core, Microblaze softcore, IP blocks from EDK or elsewhere).
I've recently added XILINX_EDK to linux-xilinx-26.git repository at source.mvista.com, but to include the level 1 drivers (aka OS independent drivers) from EDK. Haven't planned to use XILINX_EDK for drivers not using EDK code.
Here is the relevant snippet from arch/ppc/platforms/4xx/Kconfig
(from linux-xilinx-26.git @ source.mvista.com, ko doesn't have XILINX_EDK and the rest below):
===8<=====================================
config XILINX_VIRTEX_II_PRO
bool
select XILINX_VIRTEX
config XILINX_VIRTEX_4_FX
bool
select XILINX_VIRTEX
config XILINX_VIRTEX
bool
# The options selected by EDK based drivers. Not visible from [menu]config. config XILINX_EDK
bool
config XILINX_IPIF_V123B
bool
config XILINX_FIFO_V200A
bool
config XILINX_DMA_V300A
bool
===8<=====================================
If we do something like
config XILINX_MICROBLAZE
bool
select XILINX_VIRTEX
in arch/microblaze/Kconfig
would it work?
Thanks,
Andrei
Yes, except that microblazes systems run in non-virtex FPGAs...
It may be that XILINX_EDK is not the right thing either, but it seemed like the easiest way to have a superset of powerpc and microblaze systems
What I'm trying to do is (in concert with Grant's recent configuration changes)
having an easy way for a new board configuration to select the Kconfig options for
all of the Xilinx drivers. Namely:
config XILINX_ML300
bool "Xilinx-ML300" select XILINX_VIRTEX_II_PRO select EMBEDDEDBOOT help This option enables support for the Xilinx ML300 evaluation
board.
config XILINX_VIRTEX_II_PRO
bool
select XILINX_VIRTEX
config XILINX_EDK
bool depends on XILINX_VIRTEX || XILINX_MICROBLAZE default y
config XILINX_GPIO
tristate "Xilinx OPB GPIO Support" depends on XILINX_EDK
help
This option enables support for Xilinx GPIO.
It seems like I'm using XILINX_EDK to mean something different than you are.
Perhaps it sould be instead:
config XILINX_DRIVERS
bool depends on XILINX_VIRTEX || XILINX_MICROBLAZE default y
config XILINX_GPIO_EDK
tristate "Xilinx EDK-based OPB GPIO Support" depends on XILINX_DRIVERS
select XILINX_EDK
help
This option enables support for Xilinx GPIO using EDK OS
independent driver.
config XILINX_GPIO
tristate "Xilinx OPB GPIO Support" depends on XILINX_DRIVERS
help
This option enables support for Xilinx GPIO.
Would this work for you?
Steve
Quoted 106 lines
-----Original Message-----
From: Andrei Konovalov [mailto:[email protected]]
Sent: Wednesday, June 06, 2007 10:58 AM
To: Stephen Neuendorffer
Cc: [email protected]; [email protected]; Wolfgang Reissnegger
Subject: Re: [PATCH] Simple driver for Xilinx SPI controler.Hi Steve,
Quoted 3 lines · Stephen Neuendorffer
In order to anticipate future Microblaze support with most of these drivers, we've been moving towards having all of the
Kconfigdependencies onXILINX_EDK,There is no
XILINX_EDKin the ko tree.Quoted 1 line
rather than
XILINX_VIRTEX...Using
XILINX_VIRTEXseems to be a common thing:Quoted 5 lines
-------- Original Message --------
Subject: [RFC] Xilinx SystemACE device driver
Date: Sat, 14 Apr 2007 19:23:14 -0600
From: Grant Likely <[email protected]>
To: [email protected], Andrei Konovalov<[email protected]>, Peter Korsgaard
<[email protected]>, Rick Moleres <[email protected]>,
Stefan Roese <[email protected]>Quoted 3 lines
Add support for block device access to the Xilinx SystemACE Compact flash interface
<snip>
drivers/block/Kconfig config ATA_OVER_ETH · line 460
Quoted 13 lines
drivers/block/Kconfig index renamed from drivers/block/Kconfig +0
-017ee97f..08ad23c 100644
drivers/block/Kconfig +5
-0@@ -453,6 +453,12 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +config XILINX_SYSACE + tristate "Xilinx SystemACE support" + depends on XILINX_VIRTEX + help + Include support for the Xilinx SystemACE CompactFlashinterface
drivers/block/Kconfig config ATA_OVER_ETH · line 461
Quoted 1 line
drivers/block/Kconfig +1
-0+BTW the SystemACE has been successfully tested with ppc440 based board. So
XILINX_VIRTEXdoesn't imply ppc405.On the other side,
UART Lite driver (in the ko tree) doesn't depend on bothXILINX_EDKandXILINX_VIRTEXCouldn't Microblaze port use
XILINX_VIRTEXtoo? IMHOXILINX_VIRTEXis more general name for something inside the Virtex chip (ppc405 core, Microblaze softcore, IP blocks from EDK or elsewhere).I've recently added
XILINX_EDKto linux-xilinx-26.git repository at source.mvista.com, but to include the level 1 drivers (aka OS independent drivers) from EDK. Haven't planned to useXILINX_EDKfor drivers not using EDK code. Here is the relevant snippet fromarch/ppc/platforms/4xx/Kconfig(from linux-xilinx-26.git @ source.mvista.com, ko doesn't haveXILINX_EDKand the rest below):===8<=====================================
configXILINX_VIRTEX_II_PRO
bool
selectXILINX_VIRTEXconfig
XILINX_VIRTEX_4_FX
bool
selectXILINX_VIRTEXconfig
XILINX_VIRTEX
bool# The options selected by EDK based drivers. Not visible from [menu]config.
configXILINX_EDK
bool
configXILINX_IPIF_V123B
bool
configXILINX_FIFO_V200A
bool
configXILINX_DMA_V300A
bool
===8<=====================================If we do something like
configXILINX_MICROBLAZE
bool
selectXILINX_VIRTEX
inarch/microblaze/Kconfig
would it work?Thanks,
Andrei
Quoted 21 lines · Stephen Neuendorffer
Yes, except that microblazes systems run in non-virtex FPGAs...
It may be that
XILINX_EDKis not the right thing either, but it seemed like the easiest way to have a superset of powerpc and microblaze systemsWhat I'm trying to do is (in concert with Grant's recent configuration changes)
having an easy way for a new board configuration to select theKconfigoptions for
all of the Xilinx drivers. Namely:config
XILINX_ML300
bool "Xilinx-ML300"
selectXILINX_VIRTEX_II_PRO
select EMBEDDEDBOOT
help
This option enables support for the Xilinx ML300 evaluation
board.
Quoted 8 lines
config
XILINX_VIRTEX_II_PRO
bool
selectXILINX_VIRTEXconfig
XILINX_EDKbool depends on XILINX_VIRTEX || XILINX_MICROBLAZE default y
I don't have any problem with adding XILINX_EDK (or whatever), but think particular layout is back-assward. Rather than XILINX_EDK depending on XILINX_VIRTEX/MICROBLAZE, XILINX_VIRTEX/MICROBLAZE should 'select' XILINX_EDK and you need to drop the 'default y' line. Otherwise the XILINX_EDK option shows up in non-edk config files.
Quoted 8 lines
config
XILINX_GPIO
tristate "Xilinx OPB GPIO Support" depends onXILINX_EDK
help
This option enables support for Xilinx GPIO.
Quoted 8 lines
It seems like I'm using
XILINX_EDKto mean something different than you are.
Perhaps it sould be instead:config
XILINX_DRIVERSbool depends on XILINX_VIRTEX || XILINX_MICROBLAZE default y
Hmmm, yes. XILINX_DRIVERS is probably better.
Quoted 8 lines
config
XILINX_GPIO_EDK
tristate "Xilinx EDK-based OPB GPIO Support" depends onXILINX_DRIVERS
selectXILINX_EDK
help
This option enables support for Xilinx GPIO using EDK OS
independent driver.
Why still have XILINX_EDK? I thought you meant replace XILINX_EDK with XILINX_DRIVERS.
Cheers,
g.
Signature · 4 lines
Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. [email protected] (403) 399-0195
A message that is not in the archive (sent off-list or not yet received): fa686aa40706061200u1141fcc9k73b7cc80c07240d1-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org
Quoted 6 lines
Quoted 5 lines
config
XILINX_EDKbool depends on XILINX_VIRTEX || XILINX_MICROBLAZE default y
Quoted 6 lines
I don't have any problem with adding
XILINX_EDK(or whatever), but think particular layout is back-assward. Rather thanXILINX_EDKdepending on XILINX_VIRTEX/MICROBLAZE, XILINX_VIRTEX/MICROBLAZE should 'select'XILINX_EDKand you need to drop the 'default y' line.
Otherwise theXILINX_EDKoption shows up in non-edk config files.
Good point...
Quoted 2 lines
Why still have
XILINX_EDK? I thought you meant replaceXILINX_EDKwithXILINX_DRIVERS.
Yes, that's what I was suggesting.
But I think that Andrei still wants to use XILINX_EDK to pull in the stuff in drivers/xilinx_common.
# The Xilinx OS common code
obj-$(CONFIG_XILINX_EDK) += xbasic_types.o xpacket_fifo_l_v2_00_a.o \ xpacket_fifo_v2_00_a.o xversion.o \ xdma_channel.o xdma_channel_sg.o
Which you wouldn't want if you were able to build a kernel completely from 'non-edk' drivers.
Steve
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
Quoted 7 lines · Stephen Neuendorffer
Quoted 2 lines
Why still have
XILINX_EDK? I thought you meant replaceXILINX_EDKwithXILINX_DRIVERS.Yes, that's what I was suggesting.
But I think that Andrei still wants to useXILINX_EDKto pull in the stuff indrivers/xilinx_common.
Quoted 7 lines
# The Xilinx OS common code
obj-$(CONFIG_XILINX_EDK) += xbasic_types.o xpacket_fifo_l_v2_00_a.o \ xpacket_fifo_v2_00_a.o xversion.o \ xdma_channel.o xdma_channel_sg.oWhich you wouldn't want if you were able to build a kernel completely from 'non-edk' drivers.
Fair enough, but that's only an issue for vendor trees. None of this code will be going into mainline. Any of it that does get into good shape should probably go under drivers/misc, and have the drivers select only the pieces that are needed (with finer-grain CONFIG_ items). A blanked CONFIG_XILINX_EDK for random stuff is not a good idea.
Cheers,
g.
Quoted 5 lines
Steve
Signature · 4 lines
Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. [email protected] (403) 399-0195
IMHO the Kconfig stuff is off topic on spi-devel-general list, so I've removed them from the distribution list. OK?
Quoted 7 lines · Grant Likely
Quoted 6 lines · Stephen Neuendorffer
Quoted 2 lines
Why still have
XILINX_EDK? I thought you meant replaceXILINX_EDKwithXILINX_DRIVERS.Yes, that's what I was suggesting.
But I think that Andrei still wants to useXILINX_EDKto pull in the stuff indrivers/xilinx_common.
Correct,
Quoted 5 lines
Quoted 5 lines
# The Xilinx OS common code
obj-$(CONFIG_XILINX_EDK) += xbasic_types.o xpacket_fifo_l_v2_00_a.o \ xpacket_fifo_v2_00_a.o xversion.o \ xdma_channel.o xdma_channel_sg.o
.. but not exactly this way.
See
http://source.mvista.com/git/gitweb.cgi?p=linux-xilinx-26.git;a=commitdiff;h=e5b35cc7fdef280b7dd7e592a57c6dd823c62ea1
http://source.mvista.com/git/gitweb.cgi?p=linux-xilinx-26.git;a=commitdiff;h=b03eb158a0c1b4a8dd32940df02431bdd5ffcef9
Quoted 6 lines
Quoted 2 lines
Which you wouldn't want if you were able to build a kernel completely from 'non-edk' drivers.
Fair enough, but that's only an issue for vendor trees. None of this code will be going into mainline. Any of it that does get into good shape should probably go under
drivers/misc, and have the drivers
At the moment I have this stuff in arch/ppc/syslib/xilinx. drivers/misc seems a better place indeed.
Anyone objects I move arch/ppc/syslib/xilinx/* to drivers/misc/xilinx/* ?
Quoted 2 lines
select only the pieces that are needed (with finer-grain
CONFIG_items).
Yes, my current implementation is:
arch/ppc/platforms/4xx/Kconfig +0 -0
@@ -229,6 +229,16 @@ config XILINX_VIRTEX_4_FX
config XILINX_VIRTEX
bool
+# The options selected by EDK based drivers. Not visible from [menu]config. +config XILINX_EDK
+ bool
+config XILINX_IPIF_V123B
+ bool
+config XILINX_FIFO_V200A
+ bool
+config XILINX_DMA_V300A
+ bool
+
config STB03xxx
arch/ppc/syslib/xilinx/Makefile new file +10 -0
@@ -0,0 +1,10 @@ +# +# Makefile for generic hardware blocks that could be incorporated into +# various IP blocks: IPIF, FIFO, SGDMA. +# + +obj-$(CONFIG_XILINX_EDK) += xbasic_types.o +obj-$(CONFIG_XILINX_IPIF_V123B) += xipif_v1_23_b.o +obj-$(CONFIG_XILINX_FIFO_V200A) += xpacket_fifo_v2_00_a.o \ + xpacket_fifo_l_v2_00_a.o +obj-$(CONFIG_XILINX_DMA_V300A) += xdmav3.o xdmav3_intr.o xdmav3_sg.o
drivers/net/Kconfig +0 -0
@@ -2330,6 +2330,18 @@ config ATL1
To compile this driver as a module, choose M here. The module will be called atl1.
+config XILINX_TEMAC
+ tristate "Xilinx 10/100/1000 Mbit TEMAC support"
+ depends on XILINX_VIRTEX
+ select PHYLIB
+ select XILINX_EDK
+# select XILINX_IPIF_V123B
+ select XILINX_FIFO_V200A
+ select XILINX_DMA_V300A
+ help
+ This driver supports Tri-Mode, 10/100/1000 Mbit EMAC IP
+ from Xilinx EDK.
+
endif # NETDEV_1000
Is it better?
(Except for CONFIG_XILINX_EDK which should be better renamed to CONFIG_XILINX_COMMON or CONFIG_XILINX_COMMON_V100A as per the level 1 driver name in the EDK:
sw/XilinxProcessrIPLib/drivers/common_v1_00_a/src)
Quoted 2 lines
A blanked
CONFIG_XILINX_EDKfor random stuff is not a good idea.
Agreed
Thanks,
Andrei
Quoted 10 lines
Cheers,
g.Quoted 5 lines
Steve
Grant,
I'm in the process of merging your virtex-dev tree into our linux-2.6-xlnx tree. I'll be taking care of the necessary changes. They will show up on the Xilinx git repository soon.
Thanks,
Wolfgang
Quoted 71 lines · Grant Likely
Quoted 21 lines · Stephen Neuendorffer
Yes, except that microblazes systems run in non-virtex FPGAs...
It may be that
XILINX_EDKis not the right thing either, but it seemed like the easiest way to have a superset of powerpc and microblaze systemsWhat I'm trying to do is (in concert with Grant's recent configuration changes)
having an easy way for a new board configuration to select theKconfigoptions for
all of the Xilinx drivers. Namely:config
XILINX_ML300
bool "Xilinx-ML300"
selectXILINX_VIRTEX_II_PRO
select EMBEDDEDBOOT
help
This option enables support for the Xilinx ML300 evaluation
board.Quoted 8 lines
config
XILINX_VIRTEX_II_PRO
bool
selectXILINX_VIRTEXconfig
XILINX_EDKbool depends on XILINX_VIRTEX || XILINX_MICROBLAZE default yI don't have any problem with adding
XILINX_EDK(or whatever), but think particular layout is back-assward. Rather thanXILINX_EDKdepending on XILINX_VIRTEX/MICROBLAZE, XILINX_VIRTEX/MICROBLAZE should 'select'XILINX_EDKand you need to drop the 'default y' line. Otherwise theXILINX_EDKoption shows up in non-edk config files.Quoted 8 lines
config
XILINX_GPIO
tristate "Xilinx OPB GPIO Support" depends onXILINX_EDK
help
This option enables support for Xilinx GPIO.Quoted 8 lines
It seems like I'm using
XILINX_EDKto mean something different than you are.
Perhaps it sould be instead:config
XILINX_DRIVERSbool depends on XILINX_VIRTEX || XILINX_MICROBLAZE default yHmmm, yes.
XILINX_DRIVERSis probably better.Quoted 8 lines
config
XILINX_GPIO_EDK
tristate "Xilinx EDK-based OPB GPIO Support" depends onXILINX_DRIVERS
selectXILINX_EDK
help
This option enables support for Xilinx GPIO using EDK OS
independent driver.Why still have
XILINX_EDK? I thought you meant replaceXILINX_EDKwithXILINX_DRIVERS.Cheers,
g.
Quoted 5 lines · Wolfgang Reissnegger
Grant,
I'm in the process of merging your virtex-dev tree into our linux-2.6-xlnx tree. I'll be taking care of the necessary changes. They will show up on the Xilinx git repository soon.
Don't forget to send patches to the list for review so we can get this stuff into mainline.
g.
Signature · 4 lines
Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. [email protected] (403) 399-0195
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 3 lines · Andrei Konovalov
Would be nice to get this driver into mainline.
Reviews and comments are welcome.
I'll ignore the Kconfig flamage ... ;)
Quoted 12 lines
drivers/spi/xilinx_spi.c new file +9
-0@@ -0,0 +1,447 @@ +/* +* xilinx_spi.c +* +* Xilinx SPI controler driver (master mode only) +* +* Author: MontaVista Software, Inc. +* [email protected] +* +* 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the
drivers/spi/xilinx_spi.c line 19
Quoted 10 lines
drivers/spi/xilinx_spi.c new file +10
-0+* terms of the GNU General Public License version 2. This program is licensed +* "as is" without any warranty of any kind, whether express or implied. +*/ + + +/* Simple macros to get the code more readable */ +#define xspi_in16 (addr) in_be16((u16 __iomem *)(addr)) +#define xspi_in32 (addr) in_be32((u32 __iomem *)(addr)) +#define xspi_out16 (addr, value) out_be16((u16 __iomem *)(addr), (value)) +#define xspi_out32 (addr, value) out_be32((u32 __iomem *)(addr), (value))
I'm rather used to seeing I/O addressses passed around as "void __iomem *" so those sorts of cast are not needed... :)
drivers/spi/xilinx_spi.c line 96
Quoted 3 lines
drivers/spi/xilinx_spi.c new file +3
-0+ +static void xspi_abort_transfer (u8 __iomem *regs_base) +{
You should not need an abort primitive. This is called only in the remove-controller path. By the time it's called, every child spi_device on this bus segment should have been removed ... which means any spi_driver attached to that device has already returned from its remove() method, which in turn means that there will be no spi_message objects in flight from any of those drivers.
drivers/spi/xilinx_spi.c line 136
Quoted 11 lines
drivers/spi/xilinx_spi.c new file +11
-0+static void xilinx_spi_chipselect (struct spi_device *spi,int is_on) +{ +struct xilinx_spi *xspi; +u8 __iomem *regs_base; + + xspi =spi_master_get_devdata (spi->master); + regs_base = xspi->regs; + +if (is_on ==BITBANG_CS_INACTIVE ) { +/* Deselect the slave on the SPI bus */ +xspi_out32 (regs_base +XSPI_SSR_OFFSET ,0xffff );
I take it you can't support SPI_CS_HIGH??
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+/* 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; speed_hz checking could be added if the SPI +* clock information is available. Chip select delay calculations could be
drivers/spi/xilinx_spi.c line 172
Quoted 10 lines
drivers/spi/xilinx_spi.c new file +10
-0+* 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) +{ +u8 bits_per_word; + + bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; +if (bits_per_word !=8 ) +return -EINVAL ;
Speed checking *SHOULD* be added; the clock info can be platform data.
It would make trouble if a driver needed to turn the clock down to, say, 400 KHz for some operation, and the controller said "yes" but kept it at 25 MHz or whatever. It's OK if the driver is told that 400 KHz can't happen though -- it's possible to recover from that.
(Although in practice it's best to have the transfer method do the error checking, so that messages that will fail do so before they are allowed to enter the I/O queue.)
ISTR you may need to delegate to the default method here too, but it's been a while since I poked at that level and the issue might not apply to this particular driver config.
drivers/spi/xilinx_spi.c line 185
Quoted 13 lines
drivers/spi/xilinx_spi.c new file +13
-0+ +return 0 ; +} + + +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;
You need to verify ALL the input parameters. In particular, mask spi->mode against all the values this driver recognizes and supports. If you don't support SPI_LSB_FIRST it's a bug if setup() succeeds after setting that. Same thing with all other bits defined today (SPI_3WIRE, SPI_CS_HIGH) and in the future...
For an example, see the atmel_spi.c driver and MODEBITS. There's a patch in MM that makes all the SPI controller drivers have analagous tests ... and for bitbang there's a patch adding spi_bitbang.mode flags to declare any extra spi->mode flags that should be accepted.
drivers/spi/xilinx_spi.c line 265
Quoted 12 lines
drivers/spi/xilinx_spi.c new file +12
-0+ ... + +static irqreturn_t xilinx_spi_irq (int irq,void *dev_id) +{ +struct xilinx_spi *xspi; +u8 __iomem *regs_base; +u32 ipif_isr; + + xspi = (struct xilinx_spi *) dev_id; + regs_base = xspi->regs; + +/* Get the IPIF inetrrupts, and clear them immediately */
Spell checkers will tell you this is "interrupts" ... ;)
Quoted 29 lines
drivers/spi/xilinx_spi.c new file +29
-0+ ipif_isr =xspi_in32 (regs_base +XIPIF_V123B_IISR_OFFSET ); +xspi_out32 (regs_base +XIPIF_V123B_IISR_OFFSET , ipif_isr); + +if (ipif_isr &XSPI_INTR_TX_EMPTY ) {/* Transmission completed */ +u16 cr; +u8 sr; + +/* A transmit has just completed. Process received data and +* check for more data to transmit. Always inhibit the +* transmitter while the Isr refills the transmit register/FIFO, +* or make sure it is stopped if we're done. +*/ + cr =xspi_in16 (regs_base +XSPI_CR_OFFSET ); +xspi_out16 (regs_base +XSPI_CR_OFFSET , + cr |XSPI_CR_TRANS_INHIBIT ); + +/* Read out all the data from the Rx FIFO */ + sr =in_8 (regs_base +XSPI_SR_OFFSET ); +while ((sr &XSPI_SR_RX_EMPTY_MASK ) ==0 ) { +u8 data; + + data =in_8 (regs_base +XSPI_RXD_OFFSET ); +if (xspi->rx_ptr) { + *xspi->rx_ptr++ = data; + } + sr =in_8 (regs_base +XSPI_SR_OFFSET ); + } + +/* See if there is more data to send */
drivers/spi/xilinx_spi.c line 304
Quoted 10 lines
drivers/spi/xilinx_spi.c new file +10
-0+if (xspi->remaining_bytes >0 ) { +/* sr content is valid here; no need for io_8() */ +while ((sr &XSPI_SR_TX_FULL_MASK ) ==0 + && xspi->remaining_bytes >0 ) { +if (xspi->tx_ptr) { +out_8 (regs_base +XSPI_TXD_OFFSET , + *xspi->tx_ptr++); + }else { +out_8 (regs_base +XSPI_TXD_OFFSET ,0 ); + }
This duplicates the loop in txrx_bufs(); that's bad style. Have one routine holding the shared code.
Quoted 28 lines
drivers/spi/xilinx_spi.c new file +28
-0+static int __init xilinx_spi_probe (struct platform_device *dev) +{ +int ret =0 ; +struct spi_master *master; +struct xilinx_spi *xspi; +struct xspi_platform_data *pdata; +struct resource *r; + +/* Get resources(memory, IRQ) associated with the device */ + master =spi_alloc_master (&dev->dev,sizeof (struct xilinx_spi )); + +if (master ==NULL ) { +return -ENOMEM ; + } + +platform_set_drvdata (dev, master); + pdata = dev->dev.platform_data; + +if (pdata ==NULL ) { + ret = -ENODEV ; + goto put_master; + } + + r =platform_get_resource (dev,IORESOURCE_MEM ,0 ); +if (r ==NULL ) { + ret = -ENODEV ; + goto put_master; + }
drivers/spi/xilinx_spi.c line 362
Quoted 10 lines
drivers/spi/xilinx_spi.c new file +10
-0+ + xspi =spi_master_get_devdata (master); + xspi->bitbang.master =spi_master_get (master); + xspi->bitbang.chipselect = xilinx_spi_chipselect; + xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; + xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; + xspi->bitbang.master->setup = xilinx_spi_setup; +init_completion (&xspi->done); + + xspi->regs =ioremap (r->start, r->end - r->start +1 );
Strictly speaking a request_region() should precede the ioremap, but a lot of folk don't bother. However, lacking that I'd put the request_irq() earlier, since that will be the only resource providing any guard against another driver sharing the hardware.
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
Hi David,
Thanks for reviewing this stuff!
Quoted 24 lines · David Brownell
Quoted 2 lines · Andrei Konovalov
Would be nice to get this driver into mainline.
Reviews and comments are welcome.I'll ignore the
Kconfigflamage ... ;)Quoted 17 lines
drivers/spi/xilinx_spi.c new file +14
-0@@ -0,0 +1,447 @@ +/* +* xilinx_spi.c +* +* Xilinx SPI controler driver (master mode only) +* +* Author: MontaVista Software, Inc. +* [email protected] +* +* 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the +* terms of the GNU General Public License version 2. This program is licensed +* "as is" without any warranty of any kind, whether express or implied. +*/ + +
Quoted 8 lines
drivers/spi/xilinx_spi.c line 78
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+/* Simple macros to get the code more readable */ +#define xspi_in16 (addr) in_be16((u16 __iomem *)(addr)) +#define xspi_in32 (addr) in_be32((u32 __iomem *)(addr)) +#define xspi_out16 (addr, value) out_be16((u16 __iomem *)(addr), (value)) +#define xspi_out32 (addr, value) out_be32((u32 __iomem *)(addr), (value))I'm rather used to seeing I/O addressses passed around as "void
__iomem*" so those sorts of cast are not needed... :)
I've decided to make the base_address (u8 __iomem *) to make it easier to add the register offsets to the base. Like that:
static void xspi_init_hw(u8 __iomem *regs_base)
{
/* Reset the SPI device */
xspi_out32(regs_base + XIPIF_V123B_RESETR_OFFSET,
XIPIF_V123B_RESET_MASK);...
Without the cast, out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET, XIPIF_V123B_RESET_MASK) produces a warning.
Another solution could be
#define XSPI_REG(base, offset) (void *)((base) + (offset)) and
/* Reset the SPI device */ out_be32(XSPI_REG(regs_base, XIPIF_V123B_RESETR_OFFSET), XIPIF_V123B_RESET_MASK);
Is it better?
Quoted 11 lines
drivers/spi/xilinx_spi.c line 96
Quoted 3 lines
drivers/spi/xilinx_spi.c new file +3
-0+ +static void xspi_abort_transfer (u8 __iomem *regs_base) +{You should not need an abort primitive. This is called only in the remove-controller path. By the time it's called, every child
spi_deviceon this bus segment should have been removed ... which means anyspi_driverattached to that device has already returned from itsremove()method, which in turn means that there will be nospi_messageobjects in flight from any of those drivers.
I am paranoid enough not to rely 100% on the spi_device's and the spi_bitbang doing all that :)
Agreed, xspi_abort_transfer is bad name here. But I still would like to leave these two writes:
+ /* Deselect the slave on the SPI bus */
+ xspi_out32(regs_base + XSPI_SSR_OFFSET, 0xffff);
+ /* Disable the transmitter */
+ xspi_out16(regs_base + XSPI_CR_OFFSET,
+ XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT);
in xilinx_spi_remove(). Just in case :)
Quoted 5 lines
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+static void xilinx_spi_chipselect (struct spi_device *spi,int is_on) +{ +struct xilinx_spi *xspi; +u8 __iomem *regs_base; +
Quoted 8 lines
drivers/spi/xilinx_spi.c line 136
Quoted 6 lines
drivers/spi/xilinx_spi.c new file +6
-0+ xspi =spi_master_get_devdata (spi->master); + regs_base = xspi->regs; + +if (is_on ==BITBANG_CS_INACTIVE ) { +/* Deselect the slave on the SPI bus */ +xspi_out32 (regs_base +XSPI_SSR_OFFSET ,0xffff );I take it you can't support
SPI_CS_HIGH??
There is no clear indication in the SPI controller docs that SPI_CS_HIGH would work. I suspect it would as we don't use the ability of the controller to generate the chip selects automatically (the auto mode doesn't support SPI_CS_HIGH). But it is more safe to advertise SPI_CS_HIGH is not supported.
Quoted 18 lines
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+/* 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; speed_hz checking could be added if the SPI +* clock information is available. Chip select delay calculations could be drivers/spi/xilinx_spi.c line 172
Quoted 10 lines
drivers/spi/xilinx_spi.c new file +10
-0+* 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) +{ +u8 bits_per_word; + + bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; +if (bits_per_word !=8 ) +return -EINVAL ;Speed checking *SHOULD* be added; the clock info can be platform data.
Quoted 4 lines
It would make trouble if a driver needed to turn the clock down to, say, 400 KHz for some operation, and the controller said "yes" but kept it at 25 MHz or whatever. It's OK if the driver is told that 400 KHz can't happen though -- it's possible to recover from that.
OK
Quoted 31 lines
(Although in practice it's best to have the transfer method do the error checking, so that messages that will fail do so before they are allowed to enter the I/O queue.)
ISTR you may need to delegate to the default method here too, but it's been a while since I poked at that level and the issue might not apply to this particular driver config.
drivers/spi/xilinx_spi.c line 185
Quoted 13 lines
drivers/spi/xilinx_spi.c new file +13
-0+ +return 0 ; +} + + +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;You need to verify ALL the input parameters. In particular, mask
spi->modeagainst all the values this driver recognizes and supports. If you don't supportSPI_LSB_FIRSTit's a bug ifsetup()succeeds after setting that. Same thing with all other bits defined today (SPI_3WIRE,SPI_CS_HIGH) and in the future...
Quoted 5 lines
For an example, see the
atmel_spi.cdriver and MODEBITS. There's a patch in MM that makes all the SPI controller drivers have analagous tests ... and for bitbang there's a patch adding spi_bitbang.mode flags to declare any extraspi->modeflags that should be accepted.
OK. Thanks.
Quoted 6 lines
Quoted 6 lines
drivers/spi/xilinx_spi.c new file +6
-0+ ... + +static irqreturn_t xilinx_spi_irq (int irq,void *dev_id) +{ +struct xilinx_spi *xspi; +u8 __iomem *regs_base;
Quoted 8 lines
drivers/spi/xilinx_spi.c line 265
Quoted 6 lines
drivers/spi/xilinx_spi.c new file +6
-0+u32 ipif_isr; + + xspi = (struct xilinx_spi *) dev_id; + regs_base = xspi->regs; + +/* Get the IPIF inetrrupts, and clear them immediately */ Spell checkers will tell you this is "interrupts" ... ;)
Oops...
Quoted 34 lines
Quoted 34 lines
drivers/spi/xilinx_spi.c new file +34
-0+ ipif_isr =xspi_in32 (regs_base +XIPIF_V123B_IISR_OFFSET ); +xspi_out32 (regs_base +XIPIF_V123B_IISR_OFFSET , ipif_isr); + +if (ipif_isr &XSPI_INTR_TX_EMPTY ) {/* Transmission completed */ +u16 cr; +u8 sr; + +/* A transmit has just completed. Process received data and +* check for more data to transmit. Always inhibit the +* transmitter while the Isr refills the transmit register/FIFO, +* or make sure it is stopped if we're done. +*/ + cr =xspi_in16 (regs_base +XSPI_CR_OFFSET ); +xspi_out16 (regs_base +XSPI_CR_OFFSET , + cr |XSPI_CR_TRANS_INHIBIT ); + +/* Read out all the data from the Rx FIFO */ + sr =in_8 (regs_base +XSPI_SR_OFFSET ); +while ((sr &XSPI_SR_RX_EMPTY_MASK ) ==0 ) { +u8 data; + + data =in_8 (regs_base +XSPI_RXD_OFFSET ); +if (xspi->rx_ptr) { + *xspi->rx_ptr++ = data; + } + sr =in_8 (regs_base +XSPI_SR_OFFSET ); + } + +/* See if there is more data to send */ +if (xspi->remaining_bytes >0 ) { +/* sr content is valid here; no need for io_8() */ +while ((sr &XSPI_SR_TX_FULL_MASK ) ==0 + && xspi->remaining_bytes >0 ) { +if (xspi->tx_ptr) {
Quoted 8 lines
drivers/spi/xilinx_spi.c line 304
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+out_8 (regs_base +XSPI_TXD_OFFSET , + *xspi->tx_ptr++); + }else { +out_8 (regs_base +XSPI_TXD_OFFSET ,0 ); + }This duplicates the loop in
txrx_bufs(); that's bad style. Have one routine holding the shared code.
OK
Quoted 35 lines
Quoted 35 lines
drivers/spi/xilinx_spi.c new file +35
-0+static int __init xilinx_spi_probe (struct platform_device *dev) +{ +int ret =0 ; +struct spi_master *master; +struct xilinx_spi *xspi; +struct xspi_platform_data *pdata; +struct resource *r; + +/* Get resources(memory, IRQ) associated with the device */ + master =spi_alloc_master (&dev->dev,sizeof (struct xilinx_spi )); + +if (master ==NULL ) { +return -ENOMEM ; + } + +platform_set_drvdata (dev, master); + pdata = dev->dev.platform_data; + +if (pdata ==NULL ) { + ret = -ENODEV ; + goto put_master; + } + + r =platform_get_resource (dev,IORESOURCE_MEM ,0 ); +if (r ==NULL ) { + ret = -ENODEV ; + goto put_master; + } + + xspi =spi_master_get_devdata (master); + xspi->bitbang.master =spi_master_get (master); + xspi->bitbang.chipselect = xilinx_spi_chipselect; + xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; + xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; + xspi->bitbang.master->setup = xilinx_spi_setup;
Quoted 8 lines
drivers/spi/xilinx_spi.c line 362
Quoted 3 lines
drivers/spi/xilinx_spi.c new file +3
-0+init_completion (&xspi->done); + + xspi->regs =ioremap (r->start, r->end - r->start +1 );Strictly speaking a
request_region()should precede the ioremap, but a lot of folk don't bother. However, lacking that I'd put therequest_irq()earlier, since that will be the only resource providing any guard against another driver sharing the hardware.
Will add request_region(). I was confused by platform_device_register() doing something with the resources (contrary to the "plain" device_register()).
Thanks,
Andrei
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 11 lines · Andrei Konovalov
Quoted 8 lines
drivers/spi/xilinx_spi.c line 78
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+/* Simple macros to get the code more readable */ +#define xspi_in16 (addr) in_be16((u16 __iomem *)(addr)) +#define xspi_in32 (addr) in_be32((u32 __iomem *)(addr)) +#define xspi_out16 (addr, value) out_be16((u16 __iomem *)(addr), (value)) +#define xspi_out32 (addr, value) out_be32((u32 __iomem *)(addr), (value))I'm rather used to seeing I/O addressses passed around as "void
__iomem*" so those sorts of cast are not needed... :)I've decided to make the
base_address(u8__iomem*) to make it easier to add the register offsets to the base. Like that:
Adding register offsets works with "void __iomem *" too ...
Quoted 13 lines
Quoted 1 line
You should not need an abort primitive. ...
I am paranoid enough not to rely 100% on the spi_device's and the
spi_bitbangdoing all that :)
Agreed,xspi_abort_transferis bad name here. But I still would like to leave these two writes:drivers/spi/xilinx_spi.c new file +5
-0+/* Deselect the slave on the SPI bus */ +xspi_out32 (regs_base +XSPI_SSR_OFFSET ,0xffff ); +/* Disable the transmitter */ +xspi_out16 (regs_base +XSPI_CR_OFFSET , +XSPI_CR_TRANS_INHIBIT |XSPI_CR_MANUAL_SSELECT );
Quoted 1 line
in
xilinx_spi_remove(). Just in case :)
What happens when you add a BUG_ON to catch the device still being active?
Really, you need to rely on the rest of the system working correctly.
Quoted 6 lines
Quoted 1 line
I take it you can't support
SPI_CS_HIGH??There is no clear indication in the SPI controller docs that
SPI_CS_HIGHwould work. I suspect it would as we don't use the ability of the controller to generate the chip selects automatically (the auto mode doesn't supportSPI_CS_HIGH). But it is more safe to advertiseSPI_CS_HIGHis not supported.
If you don't explicitly support it, it's unlikely to work. :)
- Dave
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
A message that is not in the archive (sent off-list or not yet received): 200706062209.09731.david-b-yBeKhBN/[email protected]
Hi David,
In the bottom there is the interdiff against the previous version of the patch. The new patch is attached to this message.
Thanks,
Andrei
Quoted 5 lines · David Brownell
Quoted 2 lines · Andrei Konovalov
Would be nice to get this driver into mainline.
Reviews and comments are welcome.I'll ignore the
Kconfigflamage ... ;)
I've left untouched XILINX_VIRTEX in
+config SPI_XILINX
+ tristate "Xilinx SPI controller"
+ depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL
as in the current kernel there is no other symbol to "depend on". If / when someone comes with a separate patch to add XILINX_DRIVERS or whatever suitable this "depends on" line can be revisited.
Quoted 17 lines
Quoted 17 lines
drivers/spi/xilinx_spi.c new file +14
-0@@ -0,0 +1,447 @@ +/* +* xilinx_spi.c +* +* Xilinx SPI controler driver (master mode only) +* +* Author: MontaVista Software, Inc. +* [email protected] +* +* 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the +* terms of the GNU General Public License version 2. This program is licensed +* "as is" without any warranty of any kind, whether express or implied. +*/ + +
Quoted 8 lines
drivers/spi/xilinx_spi.c line 19
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+/* Simple macros to get the code more readable */ +#define xspi_in16 (addr) in_be16((u16 __iomem *)(addr)) +#define xspi_in32 (addr) in_be32((u32 __iomem *)(addr)) +#define xspi_out16 (addr, value) out_be16((u16 __iomem *)(addr), (value)) +#define xspi_out32 (addr, value) out_be32((u32 __iomem *)(addr), (value))I'm rather used to seeing I/O addressses passed around as "void
__iomem*" so those sorts of cast are not needed... :)
The macros has been removed, using "void __iomem *" now.
Quoted 11 lines
drivers/spi/xilinx_spi.c line 22
Quoted 3 lines
drivers/spi/xilinx_spi.c new file +3
-0+ +static void xspi_abort_transfer (u8 __iomem *regs_base) +{You should not need an abort primitive. This is called only in the remove-controller path. By the time it's called, every child
spi_deviceon this bus segment should have been removed ... which means anyspi_driverattached to that device has already returned from itsremove()method, which in turn means that there will be nospi_messageobjects in flight from any of those drivers.
xspi_abort_transfer() removed
Quoted 5 lines
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+static void xilinx_spi_chipselect (struct spi_device *spi,int is_on) +{ +struct xilinx_spi *xspi; +u8 __iomem *regs_base; +
Quoted 8 lines
drivers/spi/xilinx_spi.c line 33
Quoted 6 lines
drivers/spi/xilinx_spi.c new file +6
-0+ xspi =spi_master_get_devdata (spi->master); + regs_base = xspi->regs; + +if (is_on ==BITBANG_CS_INACTIVE ) { +/* Deselect the slave on the SPI bus */ +xspi_out32 (regs_base +XSPI_SSR_OFFSET ,0xffff );I take it you can't support
SPI_CS_HIGH??
Yes.
Quoted 9 lines
Quoted 9 lines
drivers/spi/xilinx_spi.c new file +9
-0+/* 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; speed_hz checking could be added if the SPI +* clock information is available. 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)
Quoted 8 lines
drivers/spi/xilinx_spi.c line 48
Quoted 6 lines
drivers/spi/xilinx_spi.c new file +6
-0+{ +u8 bits_per_word; + + bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; +if (bits_per_word !=8 ) +return -EINVAL ;Speed checking *SHOULD* be added; the clock info can be platform data.
Speed checking has be added.
The current problem is that EDK (the tool to create the FPGA "image" thus configuring what devices are in it) doesn't put the SPI clock information into any *.c or *.h file it generates. I've tried to address that in the "enable SPI driver for ML300" patch, but this doesn't affect the driver patch.
Quoted 7 lines
(Although in practice it's best to have the transfer method do the error checking, so that messages that will fail do so before they are allowed to enter the I/O queue.)
ISTR you may need to delegate to the default method here too, but it's been a while since I poked at that level and the issue might not apply to this particular driver config.
As far as I can tell, for the drivers relying on spi_bitbabg the setup_transfer() method is the right place for the speed checking.
Quoted 12 lines
Quoted 12 lines
drivers/spi/xilinx_spi.c new file +12
-0+ +return 0 ; +} + + +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);
Quoted 8 lines
drivers/spi/xilinx_spi.c line 61
Quoted 1 line
drivers/spi/xilinx_spi.c new file +1
-0+ bitbang = &xspi->bitbang;You need to verify ALL the input parameters. In particular, mask
spi->modeagainst all the values this driver recognizes and supports. If you don't supportSPI_LSB_FIRSTit's a bug ifsetup()succeeds after setting that. Same thing with all other bits defined today (SPI_3WIRE,SPI_CS_HIGH) and in the future...
Done
Quoted 6 lines
Quoted 6 lines
drivers/spi/xilinx_spi.c new file +6
-0+ ... + +static irqreturn_t xilinx_spi_irq (int irq,void *dev_id) +{ +struct xilinx_spi *xspi; +u8 __iomem *regs_base;
Quoted 8 lines
drivers/spi/xilinx_spi.c line 73
Quoted 6 lines
drivers/spi/xilinx_spi.c new file +6
-0+u32 ipif_isr; + + xspi = (struct xilinx_spi *) dev_id; + regs_base = xspi->regs; + +/* Get the IPIF inetrrupts, and clear them immediately */ Spell checkers will tell you this is "interrupts" ... ;)
Fixed
Quoted 34 lines
Quoted 34 lines
drivers/spi/xilinx_spi.c new file +34
-0+ ipif_isr =xspi_in32 (regs_base +XIPIF_V123B_IISR_OFFSET ); +xspi_out32 (regs_base +XIPIF_V123B_IISR_OFFSET , ipif_isr); + +if (ipif_isr &XSPI_INTR_TX_EMPTY ) {/* Transmission completed */ +u16 cr; +u8 sr; + +/* A transmit has just completed. Process received data and +* check for more data to transmit. Always inhibit the +* transmitter while the Isr refills the transmit register/FIFO, +* or make sure it is stopped if we're done. +*/ + cr =xspi_in16 (regs_base +XSPI_CR_OFFSET ); +xspi_out16 (regs_base +XSPI_CR_OFFSET , + cr |XSPI_CR_TRANS_INHIBIT ); + +/* Read out all the data from the Rx FIFO */ + sr =in_8 (regs_base +XSPI_SR_OFFSET ); +while ((sr &XSPI_SR_RX_EMPTY_MASK ) ==0 ) { +u8 data; + + data =in_8 (regs_base +XSPI_RXD_OFFSET ); +if (xspi->rx_ptr) { + *xspi->rx_ptr++ = data; + } + sr =in_8 (regs_base +XSPI_SR_OFFSET ); + } + +/* See if there is more data to send */ +if (xspi->remaining_bytes >0 ) { +/* sr content is valid here; no need for io_8() */ +while ((sr &XSPI_SR_TX_FULL_MASK ) ==0 + && xspi->remaining_bytes >0 ) { +if (xspi->tx_ptr) {
Quoted 8 lines
drivers/spi/xilinx_spi.c line 112
Quoted 5 lines
drivers/spi/xilinx_spi.c new file +5
-0+out_8 (regs_base +XSPI_TXD_OFFSET , + *xspi->tx_ptr++); + }else { +out_8 (regs_base +XSPI_TXD_OFFSET ,0 ); + }This duplicates the loop in
txrx_bufs(); that's bad style. Have one routine holding the shared code.
Moved into separate function.
Quoted 35 lines
Quoted 35 lines
drivers/spi/xilinx_spi.c new file +35
-0+static int __init xilinx_spi_probe (struct platform_device *dev) +{ +int ret =0 ; +struct spi_master *master; +struct xilinx_spi *xspi; +struct xspi_platform_data *pdata; +struct resource *r; + +/* Get resources(memory, IRQ) associated with the device */ + master =spi_alloc_master (&dev->dev,sizeof (struct xilinx_spi )); + +if (master ==NULL ) { +return -ENOMEM ; + } + +platform_set_drvdata (dev, master); + pdata = dev->dev.platform_data; + +if (pdata ==NULL ) { + ret = -ENODEV ; + goto put_master; + } + + r =platform_get_resource (dev,IORESOURCE_MEM ,0 ); +if (r ==NULL ) { + ret = -ENODEV ; + goto put_master; + } + + xspi =spi_master_get_devdata (master); + xspi->bitbang.master =spi_master_get (master); + xspi->bitbang.chipselect = xilinx_spi_chipselect; + xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; + xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; + xspi->bitbang.master->setup = xilinx_spi_setup;
Quoted 8 lines
drivers/spi/xilinx_spi.c line 150
Quoted 3 lines
drivers/spi/xilinx_spi.c new file +3
-0+init_completion (&xspi->done); + + xspi->regs =ioremap (r->start, r->end - r->start +1 );Strictly speaking a
request_region()should precede the ioremap, but a lot of folk don't bother. However, lacking that I'd put therequest_irq()earlier, since that will be the only resource providing any guard against another driver sharing the hardware.
request_region() added
Here is the interdiff against the previous version of the patch:
arch/ppc/syslib/virtex_devices.h +1 -0
@@ -49,6 +49,7 @@struct xspi_platform_data {s16 bus_num;u16 num_chipselect; +u32 speed_hz; };#endif /* __ASM_VIRTEX_DEVICES_H__ */
drivers/spi/xilinx_spi.c +85 -94
327 lines not on this page · raw message
Simple driver for Xilinx SPI controler.
From: Andrei Konovalov <[email protected]>
Only master mode is supported. No support for multiple masters. Slave mode is not supported either.
Not using level 1 drivers from EDK.
---
---
arch/ppc/syslib/virtex_devices.h | 7 + drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 drivers/spi/xilinx_spi.c | 438 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 455 insertions(+), 0 deletions(-)
arch/ppc/syslib/virtex_devices.h +7 -0
@@ -31,4 +31,11 @@ struct xtemac_platform_data {*/ int virtex_device_fixup (struct platform_device *dev); +/* SPI Controller IP */ +struct xspi_platform_data { +s16 bus_num; +u16 num_chipselect; +u32 speed_hz; +}; +#endif /* __ASM_VIRTEX_DEVICES_H__ */
drivers/spi/Kconfig +9 -0
@@ -156,6 +156,15 @@ config SPI_S3C24XX_GPIO GPIO lines to provide the SPI bus. This can be used where the inbuilt hardware cannot provide the transfer mode, or where the board is using non hardware connected pins. + +config SPI_XILINX + tristate "Xilinx SPI controller" + depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL + select SPI_BITBANG + help + This enables using the SPI controller IP from Xilinx EDK in master + mode. See the DS464, "OPB Serial Peripheral Interface (SPI) (v1.00e)" + Product Specification document for the hardware details. # # Add new SPI master controllers in alphabetical order above this line #
drivers/spi/Makefile +1 -0
@@ -23,6 +23,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o +obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o # ... add above this line ... # SPI protocol drivers (device/link on bus)
drivers/spi/xilinx_spi.c new file +438 -0
438 lines not on this page · raw message
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 1 line · Andrei Konovalov
The new patch is attached to this message.
Would you send a version that doesn't produce so many warnings when run against scripts/checkpatch.pl ??
The issues seem to be mostly whitespace and linelength, so that should be easy.
- Dave
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
A message that is not in the archive (sent off-list or not yet received): 200706120928.09176.david-b-yBeKhBN/[email protected]
Quoted 10 lines · David Brownell
Quoted 1 line · Andrei Konovalov
The new patch is attached to this message.
Would you send a version that doesn't produce so many warnings when run against
scripts/checkpatch.pl??The issues seem to be mostly whitespace and linelength, so that should be easy.
- Dave
Here is the updated patch (attached).
The changes are just
- replace "#include <asm/io.h>" with "#include <linux/io.h>"
- whitespace and linelength mods
Thanks again,
Andrei
Simple driver for Xilinx SPI controler.
From: Andrei Konovalov <[email protected]>
Only master mode is supported. No support for multiple masters. Slave mode is not supported either.
Not using level 1 drivers from EDK.
---
arch/ppc/syslib/virtex_devices.h | 7 + drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 drivers/spi/xilinx_spi.c | 438 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 455 insertions(+), 0 deletions(-)
arch/ppc/syslib/virtex_devices.h +7 -0
@@ -31,4 +31,11 @@ void __init virtex_early_serial_map(void);*/ int virtex_device_fixup (struct platform_device *dev); +/* SPI Controller IP */ +struct xspi_platform_data { +s16 bus_num; +u16 num_chipselect; +u32 speed_hz; +}; +#endif /* __ASM_VIRTEX_DEVICES_H__ */
drivers/spi/Kconfig +9 -0
@@ -156,6 +156,15 @@ config SPI_S3C24XX_GPIO GPIO lines to provide the SPI bus. This can be used where the inbuilt hardware cannot provide the transfer mode, or where the board is using non hardware connected pins. + +config SPI_XILINX + tristate "Xilinx SPI controller" + depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL + select SPI_BITBANG + help + This enables using the SPI controller IP from Xilinx EDK in master + mode. See the DS464, "OPB Serial Peripheral Interface (SPI) (v1.00e)" + Product Specification document for the hardware details. # # Add new SPI master controllers in alphabetical order above this line #
drivers/spi/Makefile +1 -0
@@ -23,6 +23,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o +obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o # ... add above this line ... # SPI protocol drivers (device/link on bus)
drivers/spi/xilinx_spi.c new file +438 -0
438 lines not on this page · raw message