Blame view
drivers/spi/spi-xilinx.c
14.3 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
ae918c02d SPI master driver... |
2 |
/* |
ae918c02d SPI master driver... |
3 4 5 6 7 |
* Xilinx SPI controller driver (master mode only) * * Author: MontaVista Software, Inc. * source@mvista.com * |
8fd8821b6 spi/xilinx: fold ... |
8 9 10 |
* Copyright (c) 2010 Secret Lab Technologies, Ltd. * Copyright (c) 2009 Intel Corporation * 2002-2007 (c) MontaVista Software, Inc. |
ae918c02d SPI master driver... |
11 12 13 |
*/ #include <linux/module.h> |
ae918c02d SPI master driver... |
14 |
#include <linux/interrupt.h> |
eae6cb31d spi/xilinx: merge... |
15 |
#include <linux/of.h> |
8fd8821b6 spi/xilinx: fold ... |
16 |
#include <linux/platform_device.h> |
ae918c02d SPI master driver... |
17 18 |
#include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> |
d5af91a1f xilinx_spi: Split... |
19 |
#include <linux/spi/xilinx_spi.h> |
eae6cb31d spi/xilinx: merge... |
20 |
#include <linux/io.h> |
d5af91a1f xilinx_spi: Split... |
21 |
|
eb25f16c6 spi/xilinx: Check... |
22 |
#define XILINX_SPI_MAX_CS 32 |
fc3ba9525 SPI driver hotplu... |
23 |
#define XILINX_SPI_NAME "xilinx_spi" |
ae918c02d SPI master driver... |
24 25 26 27 |
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) * Product Specification", DS464 */ |
c9da2e125 xilinx_spi: add s... |
28 |
#define XSPI_CR_OFFSET 0x60 /* Control Register */ |
ae918c02d SPI master driver... |
29 |
|
082339bc6 spi: spi-xilinx: ... |
30 |
#define XSPI_CR_LOOP 0x01 |
ae918c02d SPI master driver... |
31 32 33 34 |
#define XSPI_CR_ENABLE 0x02 #define XSPI_CR_MASTER_MODE 0x04 #define XSPI_CR_CPOL 0x08 #define XSPI_CR_CPHA 0x10 |
bca690db9 spi/xilinx: Suppo... |
35 |
#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL | \ |
0240f9451 spi/xilinx: Suppo... |
36 |
XSPI_CR_LSB_FIRST | XSPI_CR_LOOP) |
ae918c02d SPI master driver... |
37 38 39 40 |
#define XSPI_CR_TXFIFO_RESET 0x20 #define XSPI_CR_RXFIFO_RESET 0x40 #define XSPI_CR_MANUAL_SSELECT 0x80 #define XSPI_CR_TRANS_INHIBIT 0x100 |
c9da2e125 xilinx_spi: add s... |
41 |
#define XSPI_CR_LSB_FIRST 0x200 |
ae918c02d SPI master driver... |
42 |
|
c9da2e125 xilinx_spi: add s... |
43 |
#define XSPI_SR_OFFSET 0x64 /* Status Register */ |
ae918c02d SPI master driver... |
44 45 46 47 48 49 |
#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */ #define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */ #define XSPI_SR_TX_EMPTY_MASK 0x04 /* Transmit FIFO is empty */ #define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */ #define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */ |
c9da2e125 xilinx_spi: add s... |
50 51 |
#define XSPI_TXD_OFFSET 0x68 /* Data Transmit Register */ #define XSPI_RXD_OFFSET 0x6c /* Data Receive Register */ |
ae918c02d SPI master driver... |
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */ /* 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 */ #define XIPIF_V123B_GINTR_ENABLE 0x80000000 #define XIPIF_V123B_IISR_OFFSET 0x20 /* IPIF interrupt status reg */ #define XIPIF_V123B_IIER_OFFSET 0x28 /* IPIF interrupt enable reg */ #define XSPI_INTR_MODE_FAULT 0x01 /* Mode fault error */ #define XSPI_INTR_SLAVE_MODE_FAULT 0x02 /* Selected as slave while * disabled */ #define XSPI_INTR_TX_EMPTY 0x04 /* TxFIFO is empty */ #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 */ |
c9da2e125 xilinx_spi: add s... |
71 |
#define XSPI_INTR_TX_HALF_EMPTY 0x40 /* TxFIFO is half empty */ |
ae918c02d SPI master driver... |
72 73 74 75 76 77 78 79 |
#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */ #define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */ struct xilinx_spi { /* bitbang has to be first */ struct spi_bitbang bitbang; struct completion done; |
ae918c02d SPI master driver... |
80 |
void __iomem *regs; /* virt. address of the control registers */ |
9ca1273bb spi/xilinx: signe... |
81 |
int irq; |
ae918c02d SPI master driver... |
82 |
|
ae918c02d SPI master driver... |
83 84 |
u8 *rx_ptr; /* pointer in the Tx buffer */ const u8 *tx_ptr; /* pointer in the Rx buffer */ |
17aaaa803 spi/xilinx: Conve... |
85 |
u8 bytes_per_word; |
4c9a76140 spi/xilinx: Simpl... |
86 |
int buffer_size; /* buffer size in words */ |
f9c6ef6cf spi/xilinx: Suppo... |
87 |
u32 cs_inactive; /* Level of the CS pins when inactive*/ |
6ff8672a9 spi: xilinx: remo... |
88 89 |
unsigned int (*read_fn)(void __iomem *); void (*write_fn)(u32, void __iomem *); |
ae918c02d SPI master driver... |
90 |
}; |
0635287a3 spi: Revert "spi/... |
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
static void xspi_write32(u32 val, void __iomem *addr) { iowrite32(val, addr); } static unsigned int xspi_read32(void __iomem *addr) { return ioread32(addr); } static void xspi_write32_be(u32 val, void __iomem *addr) { iowrite32be(val, addr); } static unsigned int xspi_read32_be(void __iomem *addr) { return ioread32be(addr); } |
24ba5e593 spi/xilinx: Remov... |
110 |
static void xilinx_spi_tx(struct xilinx_spi *xspi) |
c9da2e125 xilinx_spi: add s... |
111 |
{ |
34093cb97 spi/xilinx: Fix a... |
112 |
u32 data = 0; |
c30929415 spi/xilinx: Make ... |
113 114 115 116 |
if (!xspi->tx_ptr) { xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); return; } |
34093cb97 spi/xilinx: Fix a... |
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
switch (xspi->bytes_per_word) { case 1: data = *(u8 *)(xspi->tx_ptr); break; case 2: data = *(u16 *)(xspi->tx_ptr); break; case 4: data = *(u32 *)(xspi->tx_ptr); break; } xspi->write_fn(data, xspi->regs + XSPI_TXD_OFFSET); |
17aaaa803 spi/xilinx: Conve... |
131 |
xspi->tx_ptr += xspi->bytes_per_word; |
c9da2e125 xilinx_spi: add s... |
132 |
} |
24ba5e593 spi/xilinx: Remov... |
133 |
static void xilinx_spi_rx(struct xilinx_spi *xspi) |
c9da2e125 xilinx_spi: add s... |
134 135 |
{ u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); |
c9da2e125 xilinx_spi: add s... |
136 |
|
24ba5e593 spi/xilinx: Remov... |
137 138 |
if (!xspi->rx_ptr) return; |
c9da2e125 xilinx_spi: add s... |
139 |
|
17aaaa803 spi/xilinx: Conve... |
140 141 |
switch (xspi->bytes_per_word) { case 1: |
24ba5e593 spi/xilinx: Remov... |
142 143 |
*(u8 *)(xspi->rx_ptr) = data; break; |
17aaaa803 spi/xilinx: Conve... |
144 |
case 2: |
24ba5e593 spi/xilinx: Remov... |
145 146 |
*(u16 *)(xspi->rx_ptr) = data; break; |
17aaaa803 spi/xilinx: Conve... |
147 |
case 4: |
c9da2e125 xilinx_spi: add s... |
148 |
*(u32 *)(xspi->rx_ptr) = data; |
24ba5e593 spi/xilinx: Remov... |
149 |
break; |
c9da2e125 xilinx_spi: add s... |
150 |
} |
24ba5e593 spi/xilinx: Remov... |
151 |
|
17aaaa803 spi/xilinx: Conve... |
152 |
xspi->rx_ptr += xspi->bytes_per_word; |
c9da2e125 xilinx_spi: add s... |
153 |
} |
86fc59359 xilinx_spi: Switc... |
154 |
static void xspi_init_hw(struct xilinx_spi *xspi) |
ae918c02d SPI master driver... |
155 |
{ |
86fc59359 xilinx_spi: Switc... |
156 |
void __iomem *regs_base = xspi->regs; |
ae918c02d SPI master driver... |
157 |
/* Reset the SPI device */ |
86fc59359 xilinx_spi: Switc... |
158 159 |
xspi->write_fn(XIPIF_V123B_RESET_MASK, regs_base + XIPIF_V123B_RESETR_OFFSET); |
899929bab spi/xilinx: Leave... |
160 161 162 163 164 |
/* Enable the transmit empty interrupt, which we use to determine * progress on the transmission. */ xspi->write_fn(XSPI_INTR_TX_EMPTY, regs_base + XIPIF_V123B_IIER_OFFSET); |
22417352f spi/xilinx: Use p... |
165 166 |
/* Disable the global IPIF interrupt */ xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); |
ae918c02d SPI master driver... |
167 |
/* Deselect the slave on the SPI bus */ |
86fc59359 xilinx_spi: Switc... |
168 |
xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET); |
ae918c02d SPI master driver... |
169 170 |
/* Disable the transmitter, enable Manual Slave Select Assertion, * put SPI controller into master mode, and enable it */ |
22417352f spi/xilinx: Use p... |
171 172 173 |
xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET); |
ae918c02d SPI master driver... |
174 175 176 177 178 |
} static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); |
f9c6ef6cf spi/xilinx: Suppo... |
179 180 |
u16 cr; u32 cs; |
ae918c02d SPI master driver... |
181 182 183 |
if (is_on == BITBANG_CS_INACTIVE) { /* Deselect the slave on the SPI bus */ |
f9c6ef6cf spi/xilinx: Suppo... |
184 185 |
xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET); return; |
ae918c02d SPI master driver... |
186 |
} |
f9c6ef6cf spi/xilinx: Suppo... |
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
/* Set the SPI clock phase and polarity */ 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; if (spi->mode & SPI_LSB_FIRST) cr |= XSPI_CR_LSB_FIRST; if (spi->mode & SPI_LOOP) cr |= XSPI_CR_LOOP; 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 * parameter) */ cs = xspi->cs_inactive; cs ^= BIT(spi->chip_select); /* Activate the chip select */ xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET); |
ae918c02d SPI master driver... |
210 211 212 |
} /* spi_bitbang requires custom setup_transfer() to be defined if there is a |
9bf46f6df spi: xilinx: Conv... |
213 |
* custom txrx_bufs(). |
ae918c02d SPI master driver... |
214 215 216 217 |
*/ static int xilinx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { |
f9c6ef6cf spi/xilinx: Suppo... |
218 219 220 221 222 223 |
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); if (spi->mode & SPI_CS_HIGH) xspi->cs_inactive &= ~BIT(spi->chip_select); else xspi->cs_inactive |= BIT(spi->chip_select); |
ae918c02d SPI master driver... |
224 225 |
return 0; } |
ae918c02d SPI master driver... |
226 227 228 |
static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); |
b563bfb8d spi/xilinx: Remov... |
229 |
int remaining_words; /* the number of words left to transfer */ |
22417352f spi/xilinx: Use p... |
230 231 |
bool use_irq = false; u16 cr = 0; |
ae918c02d SPI master driver... |
232 233 234 235 236 |
/* We get here with transmitter inhibited */ xspi->tx_ptr = t->tx_buf; xspi->rx_ptr = t->rx_buf; |
b563bfb8d spi/xilinx: Remov... |
237 |
remaining_words = t->len / xspi->bytes_per_word; |
ae918c02d SPI master driver... |
238 |
|
22417352f spi/xilinx: Use p... |
239 |
if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) { |
74346841e spi/spi-xilinx: F... |
240 |
u32 isr; |
22417352f spi/xilinx: Use p... |
241 |
use_irq = true; |
22417352f spi/xilinx: Use p... |
242 243 244 245 |
/* Inhibit irq to avoid spurious irqs on tx_empty*/ cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, xspi->regs + XSPI_CR_OFFSET); |
74346841e spi/spi-xilinx: F... |
246 247 248 249 250 251 252 253 254 |
/* ACK old irqs (if any) */ isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET); if (isr) xspi->write_fn(isr, xspi->regs + XIPIF_V123B_IISR_OFFSET); /* Enable the global IPIF interrupt */ xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, xspi->regs + XIPIF_V123B_DGIER_OFFSET); reinit_completion(&xspi->done); |
22417352f spi/xilinx: Use p... |
255 |
} |
b563bfb8d spi/xilinx: Remov... |
256 |
while (remaining_words) { |
b563bfb8d spi/xilinx: Remov... |
257 |
int n_words, tx_words, rx_words; |
eca37c7c1 spi/spi-xilinx: F... |
258 |
u32 sr; |
5a1314fa6 spi: xilinx: Dete... |
259 |
int stalled; |
68c315bb9 spi: spi-xilinx: ... |
260 |
|
b563bfb8d spi/xilinx: Remov... |
261 |
n_words = min(remaining_words, xspi->buffer_size); |
4c9a76140 spi/xilinx: Simpl... |
262 |
|
b563bfb8d spi/xilinx: Remov... |
263 264 265 |
tx_words = n_words; while (tx_words--) xilinx_spi_tx(xspi); |
68c315bb9 spi: spi-xilinx: ... |
266 267 268 269 |
/* Start the transfer by not inhibiting the transmitter any * longer */ |
68c315bb9 spi: spi-xilinx: ... |
270 |
|
22417352f spi/xilinx: Use p... |
271 |
if (use_irq) { |
d9f588124 spi/xilinx: Do no... |
272 |
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); |
5fe11cc09 spi/xilinx: Suppo... |
273 |
wait_for_completion(&xspi->done); |
eca37c7c1 spi/spi-xilinx: F... |
274 275 276 277 278 279 |
/* 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. */ |
d9f588124 spi/xilinx: Do no... |
280 |
xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, |
eca37c7c1 spi/spi-xilinx: F... |
281 282 283 284 |
xspi->regs + XSPI_CR_OFFSET); sr = XSPI_SR_TX_EMPTY_MASK; } else sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); |
68c315bb9 spi: spi-xilinx: ... |
285 286 |
/* Read out all the data from the Rx FIFO */ |
b563bfb8d spi/xilinx: Remov... |
287 |
rx_words = n_words; |
5a1314fa6 spi: xilinx: Dete... |
288 |
stalled = 10; |
eca37c7c1 spi/spi-xilinx: F... |
289 |
while (rx_words) { |
5a1314fa6 spi: xilinx: Dete... |
290 291 292 293 294 295 296 297 298 |
if (rx_words == n_words && !(stalled--) && !(sr & XSPI_SR_TX_EMPTY_MASK) && (sr & XSPI_SR_RX_EMPTY_MASK)) { dev_err(&spi->dev, "Detected stall. Check C_SPI_MODE and C_SPI_MEMORY "); xspi_init_hw(xspi); return -EIO; } |
eca37c7c1 spi/spi-xilinx: F... |
299 300 301 302 303 304 305 306 307 308 309 310 |
if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) { xilinx_spi_rx(xspi); rx_words--; continue; } sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); if (!(sr & XSPI_SR_RX_EMPTY_MASK)) { xilinx_spi_rx(xspi); rx_words--; } } |
b563bfb8d spi/xilinx: Remov... |
311 312 |
remaining_words -= n_words; |
68c315bb9 spi: spi-xilinx: ... |
313 |
} |
ae918c02d SPI master driver... |
314 |
|
16ea9b8ac spi/spi-xilinx: F... |
315 |
if (use_irq) { |
22417352f spi/xilinx: Use p... |
316 |
xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET); |
16ea9b8ac spi/spi-xilinx: F... |
317 318 |
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); } |
22417352f spi/xilinx: Use p... |
319 |
|
d79b2d073 spi/xilinx: Conve... |
320 |
return t->len; |
ae918c02d SPI master driver... |
321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
} /* 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 Mode * Fault are not to happen. */ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) { struct xilinx_spi *xspi = dev_id; u32 ipif_isr; /* Get the IPIF interrupts, and clear them immediately */ |
86fc59359 xilinx_spi: Switc... |
335 336 |
ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET); xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET); |
ae918c02d SPI master driver... |
337 338 |
if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */ |
68c315bb9 spi: spi-xilinx: ... |
339 |
complete(&xspi->done); |
d33648478 spi: xilinx: Retu... |
340 |
return IRQ_HANDLED; |
ae918c02d SPI master driver... |
341 |
} |
d33648478 spi: xilinx: Retu... |
342 |
return IRQ_NONE; |
ae918c02d SPI master driver... |
343 |
} |
4c9a76140 spi/xilinx: Simpl... |
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi) { u8 sr; int n_words = 0; /* * Before the buffer_size detection we reset the core * to make sure we start with a clean state. */ xspi->write_fn(XIPIF_V123B_RESET_MASK, xspi->regs + XIPIF_V123B_RESETR_OFFSET); /* Fill the Tx FIFO with as many words as possible */ do { xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); n_words++; } while (!(sr & XSPI_SR_TX_FULL_MASK)); return n_words; } |
eae6cb31d spi/xilinx: merge... |
365 |
static const struct of_device_id xilinx_spi_of_match[] = { |
a094c2fa0 spi: xilinx: Add ... |
366 |
{ .compatible = "xlnx,axi-quad-spi-1.00.a", }, |
eae6cb31d spi/xilinx: merge... |
367 368 369 370 371 |
{ .compatible = "xlnx,xps-spi-2.00.a", }, { .compatible = "xlnx,xps-spi-2.00.b", }, {} }; MODULE_DEVICE_TABLE(of, xilinx_spi_of_match); |
eae6cb31d spi/xilinx: merge... |
372 |
|
7cb2abd05 spi/xilinx: Refer... |
373 |
static int xilinx_spi_probe(struct platform_device *pdev) |
ae918c02d SPI master driver... |
374 |
{ |
ae918c02d SPI master driver... |
375 |
struct xilinx_spi *xspi; |
d81c0bbbf spi/xilinx: Remov... |
376 |
struct xspi_platform_data *pdata; |
ad3fdbcaf spi/xilinx: Clean... |
377 |
struct resource *res; |
7b3b7432a spi/xilinx: Simpl... |
378 |
int ret, num_cs = 0, bits_per_word = 8; |
d81c0bbbf spi/xilinx: Remov... |
379 |
struct spi_master *master; |
082339bc6 spi: spi-xilinx: ... |
380 |
u32 tmp; |
d81c0bbbf spi/xilinx: Remov... |
381 |
u8 i; |
8074cf063 spi: use dev_get_... |
382 |
pdata = dev_get_platdata(&pdev->dev); |
d81c0bbbf spi/xilinx: Remov... |
383 384 385 |
if (pdata) { num_cs = pdata->num_chipselect; bits_per_word = pdata->bits_per_word; |
be3acdff9 spi/xilinx: Use o... |
386 387 388 |
} else { of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits", &num_cs); |
d81c0bbbf spi/xilinx: Remov... |
389 |
} |
ae918c02d SPI master driver... |
390 |
|
d81c0bbbf spi/xilinx: Remov... |
391 |
if (!num_cs) { |
7cb2abd05 spi/xilinx: Refer... |
392 393 394 |
dev_err(&pdev->dev, "Missing slave select configuration data "); |
d81c0bbbf spi/xilinx: Remov... |
395 396 |
return -EINVAL; } |
eb25f16c6 spi/xilinx: Check... |
397 398 399 400 401 |
if (num_cs > XILINX_SPI_MAX_CS) { dev_err(&pdev->dev, "Invalid number of spi slaves "); return -EINVAL; } |
7cb2abd05 spi/xilinx: Refer... |
402 |
master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); |
d5af91a1f xilinx_spi: Split... |
403 |
if (!master) |
d81c0bbbf spi/xilinx: Remov... |
404 |
return -ENODEV; |
ae918c02d SPI master driver... |
405 |
|
e7db06b5d spi: move more sp... |
406 |
/* the spi->mode bits understood by this driver: */ |
f9c6ef6cf spi/xilinx: Suppo... |
407 408 |
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH; |
e7db06b5d spi: move more sp... |
409 |
|
ae918c02d SPI master driver... |
410 |
xspi = spi_master_get_devdata(master); |
f9c6ef6cf spi/xilinx: Suppo... |
411 |
xspi->cs_inactive = 0xffffffff; |
94c69f765 spi: bitbang: Let... |
412 |
xspi->bitbang.master = master; |
ae918c02d SPI master driver... |
413 414 415 |
xspi->bitbang.chipselect = xilinx_spi_chipselect; xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; |
ae918c02d SPI master driver... |
416 |
init_completion(&xspi->done); |
ad3fdbcaf spi/xilinx: Clean... |
417 418 |
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); xspi->regs = devm_ioremap_resource(&pdev->dev, res); |
c40537d00 spi/xilinx: Conve... |
419 420 |
if (IS_ERR(xspi->regs)) { ret = PTR_ERR(xspi->regs); |
ae918c02d SPI master driver... |
421 |
goto put_master; |
ae918c02d SPI master driver... |
422 |
} |
4b153a213 spi: xilinx: Use ... |
423 |
master->bus_num = pdev->id; |
91565c406 spi/xilinx: Elimi... |
424 |
master->num_chipselect = num_cs; |
7cb2abd05 spi/xilinx: Refer... |
425 |
master->dev.of_node = pdev->dev.of_node; |
082339bc6 spi: spi-xilinx: ... |
426 427 428 429 430 431 432 433 |
/* * Detect endianess on the IP via loop bit in CR. Detection * must be done before reset is sent because incorrect reset * value generates error interrupt. * Setup little endian helper functions first and try to use them * and check if bit was correctly setup or not. */ |
0635287a3 spi: Revert "spi/... |
434 435 |
xspi->read_fn = xspi_read32; xspi->write_fn = xspi_write32; |
082339bc6 spi: spi-xilinx: ... |
436 437 438 439 440 |
xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET); tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); tmp &= XSPI_CR_LOOP; if (tmp != XSPI_CR_LOOP) { |
0635287a3 spi: Revert "spi/... |
441 442 |
xspi->read_fn = xspi_read32_be; xspi->write_fn = xspi_write32_be; |
86fc59359 xilinx_spi: Switc... |
443 |
} |
082339bc6 spi: spi-xilinx: ... |
444 |
|
9bf46f6df spi: xilinx: Conv... |
445 |
master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); |
17aaaa803 spi/xilinx: Conve... |
446 |
xspi->bytes_per_word = bits_per_word / 8; |
4c9a76140 spi/xilinx: Simpl... |
447 |
xspi->buffer_size = xilinx_spi_find_buffer_size(xspi); |
7b3b7432a spi/xilinx: Simpl... |
448 |
xspi->irq = platform_get_irq(pdev, 0); |
4db9bf548 spi: xilinx: Hand... |
449 450 451 452 |
if (xspi->irq < 0 && xspi->irq != -ENXIO) { ret = xspi->irq; goto put_master; } else if (xspi->irq >= 0) { |
5fe11cc09 spi/xilinx: Suppo... |
453 454 455 456 457 |
/* Register for SPI Interrupt */ ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, dev_name(&pdev->dev), xspi); if (ret) goto put_master; |
7b3b7432a spi/xilinx: Simpl... |
458 |
} |
5fe11cc09 spi/xilinx: Suppo... |
459 460 |
/* SPI controller initializations */ xspi_init_hw(xspi); |
ae918c02d SPI master driver... |
461 |
|
d5af91a1f xilinx_spi: Split... |
462 463 |
ret = spi_bitbang_start(&xspi->bitbang); if (ret) { |
7cb2abd05 spi/xilinx: Refer... |
464 465 |
dev_err(&pdev->dev, "spi_bitbang_start FAILED "); |
7b3b7432a spi/xilinx: Simpl... |
466 |
goto put_master; |
eae6cb31d spi/xilinx: merge... |
467 |
} |
7cb2abd05 spi/xilinx: Refer... |
468 469 |
dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d ", |
ad3fdbcaf spi/xilinx: Clean... |
470 |
(unsigned long long)res->start, xspi->regs, xspi->irq); |
8fd8821b6 spi/xilinx: fold ... |
471 |
|
eae6cb31d spi/xilinx: merge... |
472 473 474 475 |
if (pdata) { for (i = 0; i < pdata->num_devices; i++) spi_new_device(master, pdata->devices + i); } |
8fd8821b6 spi/xilinx: fold ... |
476 |
|
7cb2abd05 spi/xilinx: Refer... |
477 |
platform_set_drvdata(pdev, master); |
8fd8821b6 spi/xilinx: fold ... |
478 |
return 0; |
ae918c02d SPI master driver... |
479 |
|
ae918c02d SPI master driver... |
480 481 |
put_master: spi_master_put(master); |
d81c0bbbf spi/xilinx: Remov... |
482 483 |
return ret; |
8fd8821b6 spi/xilinx: fold ... |
484 |
} |
7cb2abd05 spi/xilinx: Refer... |
485 |
static int xilinx_spi_remove(struct platform_device *pdev) |
8fd8821b6 spi/xilinx: fold ... |
486 |
{ |
7cb2abd05 spi/xilinx: Refer... |
487 |
struct spi_master *master = platform_get_drvdata(pdev); |
d81c0bbbf spi/xilinx: Remov... |
488 |
struct xilinx_spi *xspi = spi_master_get_devdata(master); |
7b3b7432a spi/xilinx: Simpl... |
489 |
void __iomem *regs_base = xspi->regs; |
ae918c02d SPI master driver... |
490 491 |
spi_bitbang_stop(&xspi->bitbang); |
7b3b7432a spi/xilinx: Simpl... |
492 493 494 495 496 |
/* Disable all the interrupts just in case */ xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); /* Disable the global IPIF interrupt */ xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); |
ff82c587a Xilinx: SPI: upda... |
497 |
|
d5af91a1f xilinx_spi: Split... |
498 |
spi_master_put(xspi->bitbang.master); |
8fd8821b6 spi/xilinx: fold ... |
499 500 501 502 503 504 505 506 507 |
return 0; } /* work with hotplug and coldplug */ MODULE_ALIAS("platform:" XILINX_SPI_NAME); static struct platform_driver xilinx_spi_driver = { .probe = xilinx_spi_probe, |
fd4a319bc spi: Remove HOTPL... |
508 |
.remove = xilinx_spi_remove, |
8fd8821b6 spi/xilinx: fold ... |
509 510 |
.driver = { .name = XILINX_SPI_NAME, |
eae6cb31d spi/xilinx: merge... |
511 |
.of_match_table = xilinx_spi_of_match, |
8fd8821b6 spi/xilinx: fold ... |
512 513 |
}, }; |
940ab8896 drivercore: Add h... |
514 |
module_platform_driver(xilinx_spi_driver); |
8fd8821b6 spi/xilinx: fold ... |
515 |
|
ae918c02d SPI master driver... |
516 517 518 |
MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); MODULE_DESCRIPTION("Xilinx SPI driver"); MODULE_LICENSE("GPL"); |