diff options
| author | Richard Röjfors <richard.rojfors@mocean-labs.com> | 2009-11-13 06:28:49 -0500 |
|---|---|---|
| committer | Grant Likely <grant.likely@secretlab.ca> | 2009-12-08 20:48:14 -0500 |
| commit | 86fc593599c11b62a11c85b4d7b709089df15c29 (patch) | |
| tree | aea08df21b6c9b7e6fe7b4a93c00ae56d8737140 | |
| parent | d5af91a1faca68e9a8cc493b85aa7b194b6128aa (diff) | |
xilinx_spi: Switch to iomem functions and support little endian.
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.
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Tested-by: John Linn <John.Linn@xilinx.com>
Signed-off-by: Richard Röjfors <richard.rojfors@mocean-labs.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
| -rw-r--r-- | drivers/spi/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/spi/xilinx_spi.c | 96 | ||||
| -rw-r--r-- | include/linux/spi/xilinx_spi.h | 2 |
3 files changed, 57 insertions, 43 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f34a2d16d18f..b528271c72ef 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
| @@ -244,7 +244,7 @@ config SPI_TXX9 | |||
| 244 | 244 | ||
| 245 | config SPI_XILINX | 245 | config SPI_XILINX |
| 246 | tristate "Xilinx SPI controller" | 246 | tristate "Xilinx SPI controller" |
| 247 | depends on EXPERIMENTAL | 247 | depends on HAS_IOMEM && EXPERIMENTAL |
| 248 | select SPI_BITBANG | 248 | select SPI_BITBANG |
| 249 | select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE) | 249 | select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE) |
| 250 | help | 250 | help |
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 69fa26d82ce4..135a3a5931a4 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) | 27 | /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) |
| 28 | * Product Specification", DS464 | 28 | * Product Specification", DS464 |
| 29 | */ | 29 | */ |
| 30 | #define XSPI_CR_OFFSET 0x62 /* 16-bit Control Register */ | 30 | #define XSPI_CR_OFFSET 0x60 /* 16-bit Control Register */ |
| 31 | 31 | ||
| 32 | #define XSPI_CR_ENABLE 0x02 | 32 | #define XSPI_CR_ENABLE 0x02 |
| 33 | #define XSPI_CR_MASTER_MODE 0x04 | 33 | #define XSPI_CR_MASTER_MODE 0x04 |
| @@ -39,7 +39,7 @@ | |||
| 39 | #define XSPI_CR_MANUAL_SSELECT 0x80 | 39 | #define XSPI_CR_MANUAL_SSELECT 0x80 |
| 40 | #define XSPI_CR_TRANS_INHIBIT 0x100 | 40 | #define XSPI_CR_TRANS_INHIBIT 0x100 |
| 41 | 41 | ||
| 42 | #define XSPI_SR_OFFSET 0x67 /* 8-bit Status Register */ | 42 | #define XSPI_SR_OFFSET 0x64 /* 8-bit Status Register */ |
| 43 | 43 | ||
| 44 | #define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */ | 44 | #define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */ |
| 45 | #define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */ | 45 | #define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */ |
| @@ -47,8 +47,8 @@ | |||
| 47 | #define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */ | 47 | #define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */ |
| 48 | #define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */ | 48 | #define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */ |
| 49 | 49 | ||
| 50 | #define XSPI_TXD_OFFSET 0x6b /* 8-bit Data Transmit Register */ | 50 | #define XSPI_TXD_OFFSET 0x68 /* 8-bit Data Transmit Register */ |
| 51 | #define XSPI_RXD_OFFSET 0x6f /* 8-bit Data Receive Register */ | 51 | #define XSPI_RXD_OFFSET 0x6c /* 8-bit Data Receive Register */ |
| 52 | 52 | ||
| 53 | #define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */ | 53 | #define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */ |
| 54 | 54 | ||
| @@ -86,25 +86,29 @@ struct xilinx_spi { | |||
| 86 | u8 *rx_ptr; /* pointer in the Tx buffer */ | 86 | u8 *rx_ptr; /* pointer in the Tx buffer */ |
| 87 | const u8 *tx_ptr; /* pointer in the Rx buffer */ | 87 | const u8 *tx_ptr; /* pointer in the Rx buffer */ |
| 88 | int remaining_bytes; /* the number of bytes left to transfer */ | 88 | int remaining_bytes; /* the number of bytes left to transfer */ |
| 89 | unsigned int (*read_fn) (void __iomem *); | ||
| 90 | void (*write_fn) (u32, void __iomem *); | ||
| 89 | }; | 91 | }; |
| 90 | 92 | ||
| 91 | static void xspi_init_hw(void __iomem *regs_base) | 93 | static void xspi_init_hw(struct xilinx_spi *xspi) |
| 92 | { | 94 | { |
| 95 | void __iomem *regs_base = xspi->regs; | ||
| 96 | |||
| 93 | /* Reset the SPI device */ | 97 | /* Reset the SPI device */ |
| 94 | out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET, | 98 | xspi->write_fn(XIPIF_V123B_RESET_MASK, |
| 95 | XIPIF_V123B_RESET_MASK); | 99 | regs_base + XIPIF_V123B_RESETR_OFFSET); |
| 96 | /* Disable all the interrupts just in case */ | 100 | /* Disable all the interrupts just in case */ |
| 97 | out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0); | 101 | xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); |
| 98 | /* Enable the global IPIF interrupt */ | 102 | /* Enable the global IPIF interrupt */ |
| 99 | out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET, | 103 | xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, |
| 100 | XIPIF_V123B_GINTR_ENABLE); | 104 | regs_base + XIPIF_V123B_DGIER_OFFSET); |
| 101 | /* Deselect the slave on the SPI bus */ | 105 | /* Deselect the slave on the SPI bus */ |
| 102 | out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff); | 106 | xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET); |
| 103 | /* Disable the transmitter, enable Manual Slave Select Assertion, | 107 | /* Disable the transmitter, enable Manual Slave Select Assertion, |
| 104 | * put SPI controller into master mode, and enable it */ | 108 | * put SPI controller into master mode, and enable it */ |
| 105 | out_be16(regs_base + XSPI_CR_OFFSET, | 109 | xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT | |
| 106 | XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT | 110 | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE, |
| 107 | | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE); | 111 | regs_base + XSPI_CR_OFFSET); |
| 108 | } | 112 | } |
| 109 | 113 | ||
| 110 | static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) | 114 | 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) | |||
| 113 | 117 | ||
| 114 | if (is_on == BITBANG_CS_INACTIVE) { | 118 | if (is_on == BITBANG_CS_INACTIVE) { |
| 115 | /* Deselect the slave on the SPI bus */ | 119 | /* Deselect the slave on the SPI bus */ |
| 116 | out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff); | 120 | xspi->write_fn(0xffff, xspi->regs + XSPI_SSR_OFFSET); |
| 117 | } else if (is_on == BITBANG_CS_ACTIVE) { | 121 | } else if (is_on == BITBANG_CS_ACTIVE) { |
| 118 | /* Set the SPI clock phase and polarity */ | 122 | /* Set the SPI clock phase and polarity */ |
| 119 | u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET) | 123 | u16 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) |
| 120 | & ~XSPI_CR_MODE_MASK; | 124 | & ~XSPI_CR_MODE_MASK; |
| 121 | if (spi->mode & SPI_CPHA) | 125 | if (spi->mode & SPI_CPHA) |
| 122 | cr |= XSPI_CR_CPHA; | 126 | cr |= XSPI_CR_CPHA; |
| 123 | if (spi->mode & SPI_CPOL) | 127 | if (spi->mode & SPI_CPOL) |
| 124 | cr |= XSPI_CR_CPOL; | 128 | cr |= XSPI_CR_CPOL; |
| 125 | out_be16(xspi->regs + XSPI_CR_OFFSET, cr); | 129 | xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); |
| 126 | 130 | ||
| 127 | /* We do not check spi->max_speed_hz here as the SPI clock | 131 | /* We do not check spi->max_speed_hz here as the SPI clock |
| 128 | * frequency is not software programmable (the IP block design | 132 | * 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) | |||
| 130 | */ | 134 | */ |
| 131 | 135 | ||
| 132 | /* Activate the chip select */ | 136 | /* Activate the chip select */ |
| 133 | out_be32(xspi->regs + XSPI_SSR_OFFSET, | 137 | xspi->write_fn(~(0x0001 << spi->chip_select), |
| 134 | ~(0x0001 << spi->chip_select)); | 138 | xspi->regs + XSPI_SSR_OFFSET); |
| 135 | } | 139 | } |
| 136 | } | 140 | } |
| 137 | 141 | ||
| @@ -178,15 +182,15 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi) | |||
| 178 | u8 sr; | 182 | u8 sr; |
| 179 | 183 | ||
| 180 | /* Fill the Tx FIFO with as many bytes as possible */ | 184 | /* Fill the Tx FIFO with as many bytes as possible */ |
| 181 | sr = in_8(xspi->regs + XSPI_SR_OFFSET); | 185 | sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); |
| 182 | while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) { | 186 | while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) { |
| 183 | if (xspi->tx_ptr) { | 187 | if (xspi->tx_ptr) |
| 184 | out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++); | 188 | xspi->write_fn(*xspi->tx_ptr++, |
| 185 | } else { | 189 | xspi->regs + XSPI_TXD_OFFSET); |
| 186 | out_8(xspi->regs + XSPI_TXD_OFFSET, 0); | 190 | else |
| 187 | } | 191 | xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); |
| 188 | xspi->remaining_bytes--; | 192 | xspi->remaining_bytes--; |
| 189 | sr = in_8(xspi->regs + XSPI_SR_OFFSET); | 193 | sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); |
| 190 | } | 194 | } |
| 191 | } | 195 | } |
| 192 | 196 | ||
| @@ -208,18 +212,19 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) | |||
| 208 | /* Enable the transmit empty interrupt, which we use to determine | 212 | /* Enable the transmit empty interrupt, which we use to determine |
| 209 | * progress on the transmission. | 213 | * progress on the transmission. |
| 210 | */ | 214 | */ |
| 211 | ipif_ier = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET); | 215 | ipif_ier = xspi->read_fn(xspi->regs + XIPIF_V123B_IIER_OFFSET); |
| 212 | out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, | 216 | xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY, |
| 213 | ipif_ier | XSPI_INTR_TX_EMPTY); | 217 | xspi->regs + XIPIF_V123B_IIER_OFFSET); |
| 214 | 218 | ||
| 215 | /* Start the transfer by not inhibiting the transmitter any longer */ | 219 | /* Start the transfer by not inhibiting the transmitter any longer */ |
| 216 | cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT; | 220 | cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & |
| 217 | out_be16(xspi->regs + XSPI_CR_OFFSET, cr); | 221 | ~XSPI_CR_TRANS_INHIBIT; |
| 222 | xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); | ||
| 218 | 223 | ||
| 219 | wait_for_completion(&xspi->done); | 224 | wait_for_completion(&xspi->done); |
| 220 | 225 | ||
| 221 | /* Disable the transmit empty interrupt */ | 226 | /* Disable the transmit empty interrupt */ |
| 222 | out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier); | 227 | xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET); |
| 223 | 228 | ||
| 224 | return t->len - xspi->remaining_bytes; | 229 | return t->len - xspi->remaining_bytes; |
| 225 | } | 230 | } |
| @@ -236,8 +241,8 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) | |||
| 236 | u32 ipif_isr; | 241 | u32 ipif_isr; |
| 237 | 242 | ||
| 238 | /* Get the IPIF interrupts, and clear them immediately */ | 243 | /* Get the IPIF interrupts, and clear them immediately */ |
| 239 | ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET); | 244 | ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET); |
| 240 | out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr); | 245 | xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET); |
| 241 | 246 | ||
| 242 | if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */ | 247 | if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */ |
| 243 | u16 cr; | 248 | u16 cr; |
| @@ -248,20 +253,20 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) | |||
| 248 | * transmitter while the Isr refills the transmit register/FIFO, | 253 | * transmitter while the Isr refills the transmit register/FIFO, |
| 249 | * or make sure it is stopped if we're done. | 254 | * or make sure it is stopped if we're done. |
| 250 | */ | 255 | */ |
| 251 | cr = in_be16(xspi->regs + XSPI_CR_OFFSET); | 256 | cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); |
| 252 | out_be16(xspi->regs + XSPI_CR_OFFSET, | 257 | xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, |
| 253 | cr | XSPI_CR_TRANS_INHIBIT); | 258 | xspi->regs + XSPI_CR_OFFSET); |
| 254 | 259 | ||
| 255 | /* Read out all the data from the Rx FIFO */ | 260 | /* Read out all the data from the Rx FIFO */ |
| 256 | sr = in_8(xspi->regs + XSPI_SR_OFFSET); | 261 | sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); |
| 257 | while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) { | 262 | while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) { |
| 258 | u8 data; | 263 | u8 data; |
| 259 | 264 | ||
| 260 | data = in_8(xspi->regs + XSPI_RXD_OFFSET); | 265 | data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); |
| 261 | if (xspi->rx_ptr) { | 266 | if (xspi->rx_ptr) { |
| 262 | *xspi->rx_ptr++ = data; | 267 | *xspi->rx_ptr++ = data; |
| 263 | } | 268 | } |
| 264 | sr = in_8(xspi->regs + XSPI_SR_OFFSET); | 269 | sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); |
| 265 | } | 270 | } |
| 266 | 271 | ||
| 267 | /* See if there is more data to send */ | 272 | /* See if there is more data to send */ |
| @@ -270,7 +275,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) | |||
| 270 | /* Start the transfer by not inhibiting the | 275 | /* Start the transfer by not inhibiting the |
| 271 | * transmitter any longer | 276 | * transmitter any longer |
| 272 | */ | 277 | */ |
| 273 | out_be16(xspi->regs + XSPI_CR_OFFSET, cr); | 278 | xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); |
| 274 | } else { | 279 | } else { |
| 275 | /* No more data to send. | 280 | /* No more data to send. |
| 276 | * Indicate the transfer is completed. | 281 | * Indicate the transfer is completed. |
| @@ -325,9 +330,16 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, | |||
| 325 | 330 | ||
| 326 | xspi->mem = *mem; | 331 | xspi->mem = *mem; |
| 327 | xspi->irq = irq; | 332 | xspi->irq = irq; |
| 333 | if (pdata->little_endian) { | ||
| 334 | xspi->read_fn = ioread32; | ||
| 335 | xspi->write_fn = iowrite32; | ||
| 336 | } else { | ||
| 337 | xspi->read_fn = ioread32be; | ||
| 338 | xspi->write_fn = iowrite32be; | ||
| 339 | } | ||
| 328 | 340 | ||
| 329 | /* SPI controller initializations */ | 341 | /* SPI controller initializations */ |
| 330 | xspi_init_hw(xspi->regs); | 342 | xspi_init_hw(xspi); |
| 331 | 343 | ||
| 332 | /* Register for SPI Interrupt */ | 344 | /* Register for SPI Interrupt */ |
| 333 | ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi); | 345 | 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 06df0aba3aee..a705ad85eebe 100644 --- a/include/linux/spi/xilinx_spi.h +++ b/include/linux/spi/xilinx_spi.h | |||
| @@ -4,11 +4,13 @@ | |||
| 4 | /** | 4 | /** |
| 5 | * struct xspi_platform_data - Platform data of the Xilinx SPI driver | 5 | * struct xspi_platform_data - Platform data of the Xilinx SPI driver |
| 6 | * @num_chipselect: Number of chip select by the IP | 6 | * @num_chipselect: Number of chip select by the IP |
| 7 | * @little_endian If registers should be accessed little endian or not | ||
| 7 | * @devices: Devices to add when the driver is probed. | 8 | * @devices: Devices to add when the driver is probed. |
| 8 | * @num_devices: Number of devices in the devices array. | 9 | * @num_devices: Number of devices in the devices array. |
| 9 | */ | 10 | */ |
| 10 | struct xspi_platform_data { | 11 | struct xspi_platform_data { |
| 11 | u16 num_chipselect; | 12 | u16 num_chipselect; |
| 13 | bool little_endian; | ||
| 12 | struct spi_board_info *devices; | 14 | struct spi_board_info *devices; |
| 13 | u8 num_devices; | 15 | u8 num_devices; |
| 14 | }; | 16 | }; |
