.. | .. |
---|
7 | 7 | #include <linux/bitfield.h> |
---|
8 | 8 | #include <linux/bitops.h> |
---|
9 | 9 | #include <linux/clk.h> |
---|
| 10 | +#include <linux/delay.h> |
---|
| 11 | +#include <linux/dmaengine.h> |
---|
10 | 12 | #include <linux/interrupt.h> |
---|
11 | 13 | #include <linux/io.h> |
---|
12 | 14 | #include <linux/module.h> |
---|
.. | .. |
---|
16 | 18 | #include <asm/unaligned.h> |
---|
17 | 19 | |
---|
18 | 20 | #define SSI_TIMEOUT_MS 2000 |
---|
| 21 | +#define SSI_POLL_TIMEOUT_US 200 |
---|
19 | 22 | #define SSI_MAX_CLK_DIVIDER 254 |
---|
20 | 23 | #define SSI_MIN_CLK_DIVIDER 4 |
---|
21 | 24 | |
---|
22 | 25 | struct uniphier_spi_priv { |
---|
23 | 26 | void __iomem *base; |
---|
| 27 | + dma_addr_t base_dma_addr; |
---|
24 | 28 | struct clk *clk; |
---|
25 | 29 | struct spi_master *master; |
---|
26 | 30 | struct completion xfer_done; |
---|
.. | .. |
---|
30 | 34 | unsigned int rx_bytes; |
---|
31 | 35 | const u8 *tx_buf; |
---|
32 | 36 | u8 *rx_buf; |
---|
| 37 | + atomic_t dma_busy; |
---|
33 | 38 | |
---|
34 | 39 | bool is_save_param; |
---|
35 | 40 | u8 bits_per_word; |
---|
.. | .. |
---|
59 | 64 | #define SSI_FPS_FSTRT BIT(14) |
---|
60 | 65 | |
---|
61 | 66 | #define SSI_SR 0x14 |
---|
| 67 | +#define SSI_SR_BUSY BIT(7) |
---|
62 | 68 | #define SSI_SR_RNE BIT(0) |
---|
63 | 69 | |
---|
64 | 70 | #define SSI_IE 0x18 |
---|
| 71 | +#define SSI_IE_TCIE BIT(4) |
---|
65 | 72 | #define SSI_IE_RCIE BIT(3) |
---|
| 73 | +#define SSI_IE_TXRE BIT(2) |
---|
| 74 | +#define SSI_IE_RXRE BIT(1) |
---|
66 | 75 | #define SSI_IE_RORIE BIT(0) |
---|
| 76 | +#define SSI_IE_ALL_MASK GENMASK(4, 0) |
---|
67 | 77 | |
---|
68 | 78 | #define SSI_IS 0x1c |
---|
69 | 79 | #define SSI_IS_RXRS BIT(9) |
---|
.. | .. |
---|
85 | 95 | #define SSI_RXDR 0x24 |
---|
86 | 96 | |
---|
87 | 97 | #define SSI_FIFO_DEPTH 8U |
---|
| 98 | +#define SSI_FIFO_BURST_NUM 1 |
---|
| 99 | + |
---|
| 100 | +#define SSI_DMA_RX_BUSY BIT(1) |
---|
| 101 | +#define SSI_DMA_TX_BUSY BIT(0) |
---|
88 | 102 | |
---|
89 | 103 | static inline unsigned int bytes_per_word(unsigned int bits) |
---|
90 | 104 | { |
---|
91 | 105 | return bits <= 8 ? 1 : (bits <= 16 ? 2 : 4); |
---|
92 | 106 | } |
---|
93 | 107 | |
---|
94 | | -static inline void uniphier_spi_irq_enable(struct spi_device *spi, u32 mask) |
---|
| 108 | +static inline void uniphier_spi_irq_enable(struct uniphier_spi_priv *priv, |
---|
| 109 | + u32 mask) |
---|
95 | 110 | { |
---|
96 | | - struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); |
---|
97 | 111 | u32 val; |
---|
98 | 112 | |
---|
99 | 113 | val = readl(priv->base + SSI_IE); |
---|
.. | .. |
---|
101 | 115 | writel(val, priv->base + SSI_IE); |
---|
102 | 116 | } |
---|
103 | 117 | |
---|
104 | | -static inline void uniphier_spi_irq_disable(struct spi_device *spi, u32 mask) |
---|
| 118 | +static inline void uniphier_spi_irq_disable(struct uniphier_spi_priv *priv, |
---|
| 119 | + u32 mask) |
---|
105 | 120 | { |
---|
106 | | - struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); |
---|
107 | 121 | u32 val; |
---|
108 | 122 | |
---|
109 | 123 | val = readl(priv->base + SSI_IE); |
---|
.. | .. |
---|
214 | 228 | if (!priv->is_save_param || priv->mode != spi->mode) { |
---|
215 | 229 | uniphier_spi_set_mode(spi); |
---|
216 | 230 | priv->mode = spi->mode; |
---|
| 231 | + priv->is_save_param = false; |
---|
217 | 232 | } |
---|
218 | 233 | |
---|
219 | 234 | if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) { |
---|
.. | .. |
---|
226 | 241 | priv->speed_hz = t->speed_hz; |
---|
227 | 242 | } |
---|
228 | 243 | |
---|
229 | | - if (!priv->is_save_param) |
---|
230 | | - priv->is_save_param = true; |
---|
| 244 | + priv->is_save_param = true; |
---|
231 | 245 | |
---|
232 | 246 | /* reset FIFOs */ |
---|
233 | 247 | val = SSI_FC_TXFFL | SSI_FC_RXFFL; |
---|
.. | .. |
---|
288 | 302 | } |
---|
289 | 303 | } |
---|
290 | 304 | |
---|
291 | | -static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv) |
---|
| 305 | +static void uniphier_spi_set_fifo_threshold(struct uniphier_spi_priv *priv, |
---|
| 306 | + unsigned int threshold) |
---|
292 | 307 | { |
---|
293 | | - unsigned int tx_count; |
---|
294 | 308 | u32 val; |
---|
295 | 309 | |
---|
296 | | - tx_count = DIV_ROUND_UP(priv->tx_bytes, |
---|
297 | | - bytes_per_word(priv->bits_per_word)); |
---|
298 | | - tx_count = min(tx_count, SSI_FIFO_DEPTH); |
---|
299 | | - |
---|
300 | | - /* set fifo threshold */ |
---|
301 | 310 | val = readl(priv->base + SSI_FC); |
---|
302 | 311 | val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK); |
---|
303 | | - val |= FIELD_PREP(SSI_FC_TXFTH_MASK, tx_count); |
---|
304 | | - val |= FIELD_PREP(SSI_FC_RXFTH_MASK, tx_count); |
---|
| 312 | + val |= FIELD_PREP(SSI_FC_TXFTH_MASK, SSI_FIFO_DEPTH - threshold); |
---|
| 313 | + val |= FIELD_PREP(SSI_FC_RXFTH_MASK, threshold); |
---|
305 | 314 | writel(val, priv->base + SSI_FC); |
---|
| 315 | +} |
---|
306 | 316 | |
---|
307 | | - while (tx_count--) |
---|
| 317 | +static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv) |
---|
| 318 | +{ |
---|
| 319 | + unsigned int fifo_threshold, fill_words; |
---|
| 320 | + unsigned int bpw = bytes_per_word(priv->bits_per_word); |
---|
| 321 | + |
---|
| 322 | + fifo_threshold = DIV_ROUND_UP(priv->rx_bytes, bpw); |
---|
| 323 | + fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH); |
---|
| 324 | + |
---|
| 325 | + uniphier_spi_set_fifo_threshold(priv, fifo_threshold); |
---|
| 326 | + |
---|
| 327 | + fill_words = fifo_threshold - |
---|
| 328 | + DIV_ROUND_UP(priv->rx_bytes - priv->tx_bytes, bpw); |
---|
| 329 | + |
---|
| 330 | + while (fill_words--) |
---|
308 | 331 | uniphier_spi_send(priv); |
---|
309 | 332 | } |
---|
310 | 333 | |
---|
.. | .. |
---|
323 | 346 | writel(val, priv->base + SSI_FPS); |
---|
324 | 347 | } |
---|
325 | 348 | |
---|
326 | | -static int uniphier_spi_transfer_one(struct spi_master *master, |
---|
327 | | - struct spi_device *spi, |
---|
328 | | - struct spi_transfer *t) |
---|
| 349 | +static bool uniphier_spi_can_dma(struct spi_master *master, |
---|
| 350 | + struct spi_device *spi, |
---|
| 351 | + struct spi_transfer *t) |
---|
329 | 352 | { |
---|
330 | 353 | struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
331 | | - int status; |
---|
| 354 | + unsigned int bpw = bytes_per_word(priv->bits_per_word); |
---|
332 | 355 | |
---|
333 | | - uniphier_spi_setup_transfer(spi, t); |
---|
| 356 | + if ((!master->dma_tx && !master->dma_rx) |
---|
| 357 | + || (!master->dma_tx && t->tx_buf) |
---|
| 358 | + || (!master->dma_rx && t->rx_buf)) |
---|
| 359 | + return false; |
---|
| 360 | + |
---|
| 361 | + return DIV_ROUND_UP(t->len, bpw) > SSI_FIFO_DEPTH; |
---|
| 362 | +} |
---|
| 363 | + |
---|
| 364 | +static void uniphier_spi_dma_rxcb(void *data) |
---|
| 365 | +{ |
---|
| 366 | + struct spi_master *master = data; |
---|
| 367 | + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
| 368 | + int state = atomic_fetch_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); |
---|
| 369 | + |
---|
| 370 | + uniphier_spi_irq_disable(priv, SSI_IE_RXRE); |
---|
| 371 | + |
---|
| 372 | + if (!(state & SSI_DMA_TX_BUSY)) |
---|
| 373 | + spi_finalize_current_transfer(master); |
---|
| 374 | +} |
---|
| 375 | + |
---|
| 376 | +static void uniphier_spi_dma_txcb(void *data) |
---|
| 377 | +{ |
---|
| 378 | + struct spi_master *master = data; |
---|
| 379 | + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
| 380 | + int state = atomic_fetch_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); |
---|
| 381 | + |
---|
| 382 | + uniphier_spi_irq_disable(priv, SSI_IE_TXRE); |
---|
| 383 | + |
---|
| 384 | + if (!(state & SSI_DMA_RX_BUSY)) |
---|
| 385 | + spi_finalize_current_transfer(master); |
---|
| 386 | +} |
---|
| 387 | + |
---|
| 388 | +static int uniphier_spi_transfer_one_dma(struct spi_master *master, |
---|
| 389 | + struct spi_device *spi, |
---|
| 390 | + struct spi_transfer *t) |
---|
| 391 | +{ |
---|
| 392 | + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
| 393 | + struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; |
---|
| 394 | + int buswidth; |
---|
| 395 | + |
---|
| 396 | + atomic_set(&priv->dma_busy, 0); |
---|
| 397 | + |
---|
| 398 | + uniphier_spi_set_fifo_threshold(priv, SSI_FIFO_BURST_NUM); |
---|
| 399 | + |
---|
| 400 | + if (priv->bits_per_word <= 8) |
---|
| 401 | + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; |
---|
| 402 | + else if (priv->bits_per_word <= 16) |
---|
| 403 | + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; |
---|
| 404 | + else |
---|
| 405 | + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; |
---|
| 406 | + |
---|
| 407 | + if (priv->rx_buf) { |
---|
| 408 | + struct dma_slave_config rxconf = { |
---|
| 409 | + .direction = DMA_DEV_TO_MEM, |
---|
| 410 | + .src_addr = priv->base_dma_addr + SSI_RXDR, |
---|
| 411 | + .src_addr_width = buswidth, |
---|
| 412 | + .src_maxburst = SSI_FIFO_BURST_NUM, |
---|
| 413 | + }; |
---|
| 414 | + |
---|
| 415 | + dmaengine_slave_config(master->dma_rx, &rxconf); |
---|
| 416 | + |
---|
| 417 | + rxdesc = dmaengine_prep_slave_sg( |
---|
| 418 | + master->dma_rx, |
---|
| 419 | + t->rx_sg.sgl, t->rx_sg.nents, |
---|
| 420 | + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
---|
| 421 | + if (!rxdesc) |
---|
| 422 | + goto out_err_prep; |
---|
| 423 | + |
---|
| 424 | + rxdesc->callback = uniphier_spi_dma_rxcb; |
---|
| 425 | + rxdesc->callback_param = master; |
---|
| 426 | + |
---|
| 427 | + uniphier_spi_irq_enable(priv, SSI_IE_RXRE); |
---|
| 428 | + atomic_or(SSI_DMA_RX_BUSY, &priv->dma_busy); |
---|
| 429 | + |
---|
| 430 | + dmaengine_submit(rxdesc); |
---|
| 431 | + dma_async_issue_pending(master->dma_rx); |
---|
| 432 | + } |
---|
| 433 | + |
---|
| 434 | + if (priv->tx_buf) { |
---|
| 435 | + struct dma_slave_config txconf = { |
---|
| 436 | + .direction = DMA_MEM_TO_DEV, |
---|
| 437 | + .dst_addr = priv->base_dma_addr + SSI_TXDR, |
---|
| 438 | + .dst_addr_width = buswidth, |
---|
| 439 | + .dst_maxburst = SSI_FIFO_BURST_NUM, |
---|
| 440 | + }; |
---|
| 441 | + |
---|
| 442 | + dmaengine_slave_config(master->dma_tx, &txconf); |
---|
| 443 | + |
---|
| 444 | + txdesc = dmaengine_prep_slave_sg( |
---|
| 445 | + master->dma_tx, |
---|
| 446 | + t->tx_sg.sgl, t->tx_sg.nents, |
---|
| 447 | + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
---|
| 448 | + if (!txdesc) |
---|
| 449 | + goto out_err_prep; |
---|
| 450 | + |
---|
| 451 | + txdesc->callback = uniphier_spi_dma_txcb; |
---|
| 452 | + txdesc->callback_param = master; |
---|
| 453 | + |
---|
| 454 | + uniphier_spi_irq_enable(priv, SSI_IE_TXRE); |
---|
| 455 | + atomic_or(SSI_DMA_TX_BUSY, &priv->dma_busy); |
---|
| 456 | + |
---|
| 457 | + dmaengine_submit(txdesc); |
---|
| 458 | + dma_async_issue_pending(master->dma_tx); |
---|
| 459 | + } |
---|
| 460 | + |
---|
| 461 | + /* signal that we need to wait for completion */ |
---|
| 462 | + return (priv->tx_buf || priv->rx_buf); |
---|
| 463 | + |
---|
| 464 | +out_err_prep: |
---|
| 465 | + if (rxdesc) |
---|
| 466 | + dmaengine_terminate_sync(master->dma_rx); |
---|
| 467 | + |
---|
| 468 | + return -EINVAL; |
---|
| 469 | +} |
---|
| 470 | + |
---|
| 471 | +static int uniphier_spi_transfer_one_irq(struct spi_master *master, |
---|
| 472 | + struct spi_device *spi, |
---|
| 473 | + struct spi_transfer *t) |
---|
| 474 | +{ |
---|
| 475 | + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
| 476 | + struct device *dev = master->dev.parent; |
---|
| 477 | + unsigned long time_left; |
---|
334 | 478 | |
---|
335 | 479 | reinit_completion(&priv->xfer_done); |
---|
336 | 480 | |
---|
337 | 481 | uniphier_spi_fill_tx_fifo(priv); |
---|
338 | 482 | |
---|
339 | | - uniphier_spi_irq_enable(spi, SSI_IE_RCIE | SSI_IE_RORIE); |
---|
| 483 | + uniphier_spi_irq_enable(priv, SSI_IE_RCIE | SSI_IE_RORIE); |
---|
340 | 484 | |
---|
341 | | - status = wait_for_completion_timeout(&priv->xfer_done, |
---|
342 | | - msecs_to_jiffies(SSI_TIMEOUT_MS)); |
---|
| 485 | + time_left = wait_for_completion_timeout(&priv->xfer_done, |
---|
| 486 | + msecs_to_jiffies(SSI_TIMEOUT_MS)); |
---|
343 | 487 | |
---|
344 | | - uniphier_spi_irq_disable(spi, SSI_IE_RCIE | SSI_IE_RORIE); |
---|
| 488 | + uniphier_spi_irq_disable(priv, SSI_IE_RCIE | SSI_IE_RORIE); |
---|
345 | 489 | |
---|
346 | | - if (status < 0) |
---|
347 | | - return status; |
---|
| 490 | + if (!time_left) { |
---|
| 491 | + dev_err(dev, "transfer timeout.\n"); |
---|
| 492 | + return -ETIMEDOUT; |
---|
| 493 | + } |
---|
348 | 494 | |
---|
349 | 495 | return priv->error; |
---|
| 496 | +} |
---|
| 497 | + |
---|
| 498 | +static int uniphier_spi_transfer_one_poll(struct spi_master *master, |
---|
| 499 | + struct spi_device *spi, |
---|
| 500 | + struct spi_transfer *t) |
---|
| 501 | +{ |
---|
| 502 | + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
| 503 | + int loop = SSI_POLL_TIMEOUT_US * 10; |
---|
| 504 | + |
---|
| 505 | + while (priv->tx_bytes) { |
---|
| 506 | + uniphier_spi_fill_tx_fifo(priv); |
---|
| 507 | + |
---|
| 508 | + while ((priv->rx_bytes - priv->tx_bytes) > 0) { |
---|
| 509 | + while (!(readl(priv->base + SSI_SR) & SSI_SR_RNE) |
---|
| 510 | + && loop--) |
---|
| 511 | + ndelay(100); |
---|
| 512 | + |
---|
| 513 | + if (loop == -1) |
---|
| 514 | + goto irq_transfer; |
---|
| 515 | + |
---|
| 516 | + uniphier_spi_recv(priv); |
---|
| 517 | + } |
---|
| 518 | + } |
---|
| 519 | + |
---|
| 520 | + return 0; |
---|
| 521 | + |
---|
| 522 | +irq_transfer: |
---|
| 523 | + return uniphier_spi_transfer_one_irq(master, spi, t); |
---|
| 524 | +} |
---|
| 525 | + |
---|
| 526 | +static int uniphier_spi_transfer_one(struct spi_master *master, |
---|
| 527 | + struct spi_device *spi, |
---|
| 528 | + struct spi_transfer *t) |
---|
| 529 | +{ |
---|
| 530 | + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
| 531 | + unsigned long threshold; |
---|
| 532 | + bool use_dma; |
---|
| 533 | + |
---|
| 534 | + /* Terminate and return success for 0 byte length transfer */ |
---|
| 535 | + if (!t->len) |
---|
| 536 | + return 0; |
---|
| 537 | + |
---|
| 538 | + uniphier_spi_setup_transfer(spi, t); |
---|
| 539 | + |
---|
| 540 | + use_dma = master->can_dma ? master->can_dma(master, spi, t) : false; |
---|
| 541 | + if (use_dma) |
---|
| 542 | + return uniphier_spi_transfer_one_dma(master, spi, t); |
---|
| 543 | + |
---|
| 544 | + /* |
---|
| 545 | + * If the transfer operation will take longer than |
---|
| 546 | + * SSI_POLL_TIMEOUT_US, it should use irq. |
---|
| 547 | + */ |
---|
| 548 | + threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz, |
---|
| 549 | + USEC_PER_SEC * BITS_PER_BYTE); |
---|
| 550 | + if (t->len > threshold) |
---|
| 551 | + return uniphier_spi_transfer_one_irq(master, spi, t); |
---|
| 552 | + else |
---|
| 553 | + return uniphier_spi_transfer_one_poll(master, spi, t); |
---|
350 | 554 | } |
---|
351 | 555 | |
---|
352 | 556 | static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master) |
---|
.. | .. |
---|
365 | 569 | writel(0, priv->base + SSI_CTL); |
---|
366 | 570 | |
---|
367 | 571 | return 0; |
---|
| 572 | +} |
---|
| 573 | + |
---|
| 574 | +static void uniphier_spi_handle_err(struct spi_master *master, |
---|
| 575 | + struct spi_message *msg) |
---|
| 576 | +{ |
---|
| 577 | + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
| 578 | + u32 val; |
---|
| 579 | + |
---|
| 580 | + /* stop running spi transfer */ |
---|
| 581 | + writel(0, priv->base + SSI_CTL); |
---|
| 582 | + |
---|
| 583 | + /* reset FIFOs */ |
---|
| 584 | + val = SSI_FC_TXFFL | SSI_FC_RXFFL; |
---|
| 585 | + writel(val, priv->base + SSI_FC); |
---|
| 586 | + |
---|
| 587 | + uniphier_spi_irq_disable(priv, SSI_IE_ALL_MASK); |
---|
| 588 | + |
---|
| 589 | + if (atomic_read(&priv->dma_busy) & SSI_DMA_TX_BUSY) { |
---|
| 590 | + dmaengine_terminate_async(master->dma_tx); |
---|
| 591 | + atomic_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); |
---|
| 592 | + } |
---|
| 593 | + |
---|
| 594 | + if (atomic_read(&priv->dma_busy) & SSI_DMA_RX_BUSY) { |
---|
| 595 | + dmaengine_terminate_async(master->dma_rx); |
---|
| 596 | + atomic_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); |
---|
| 597 | + } |
---|
368 | 598 | } |
---|
369 | 599 | |
---|
370 | 600 | static irqreturn_t uniphier_spi_handler(int irq, void *dev_id) |
---|
.. | .. |
---|
413 | 643 | struct uniphier_spi_priv *priv; |
---|
414 | 644 | struct spi_master *master; |
---|
415 | 645 | struct resource *res; |
---|
| 646 | + struct dma_slave_caps caps; |
---|
| 647 | + u32 dma_tx_burst = 0, dma_rx_burst = 0; |
---|
416 | 648 | unsigned long clk_rate; |
---|
417 | 649 | int irq; |
---|
418 | 650 | int ret; |
---|
.. | .. |
---|
427 | 659 | priv->master = master; |
---|
428 | 660 | priv->is_save_param = false; |
---|
429 | 661 | |
---|
430 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
431 | | - priv->base = devm_ioremap_resource(&pdev->dev, res); |
---|
| 662 | + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); |
---|
432 | 663 | if (IS_ERR(priv->base)) { |
---|
433 | 664 | ret = PTR_ERR(priv->base); |
---|
434 | 665 | goto out_master_put; |
---|
435 | 666 | } |
---|
| 667 | + priv->base_dma_addr = res->start; |
---|
436 | 668 | |
---|
437 | 669 | priv->clk = devm_clk_get(&pdev->dev, NULL); |
---|
438 | 670 | if (IS_ERR(priv->clk)) { |
---|
.. | .. |
---|
447 | 679 | |
---|
448 | 680 | irq = platform_get_irq(pdev, 0); |
---|
449 | 681 | if (irq < 0) { |
---|
450 | | - dev_err(&pdev->dev, "failed to get IRQ\n"); |
---|
451 | 682 | ret = irq; |
---|
452 | 683 | goto out_disable_clk; |
---|
453 | 684 | } |
---|
.. | .. |
---|
476 | 707 | = uniphier_spi_prepare_transfer_hardware; |
---|
477 | 708 | master->unprepare_transfer_hardware |
---|
478 | 709 | = uniphier_spi_unprepare_transfer_hardware; |
---|
| 710 | + master->handle_err = uniphier_spi_handle_err; |
---|
| 711 | + master->can_dma = uniphier_spi_can_dma; |
---|
| 712 | + |
---|
479 | 713 | master->num_chipselect = 1; |
---|
| 714 | + master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; |
---|
| 715 | + |
---|
| 716 | + master->dma_tx = dma_request_chan(&pdev->dev, "tx"); |
---|
| 717 | + if (IS_ERR_OR_NULL(master->dma_tx)) { |
---|
| 718 | + if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) { |
---|
| 719 | + ret = -EPROBE_DEFER; |
---|
| 720 | + goto out_disable_clk; |
---|
| 721 | + } |
---|
| 722 | + master->dma_tx = NULL; |
---|
| 723 | + dma_tx_burst = INT_MAX; |
---|
| 724 | + } else { |
---|
| 725 | + ret = dma_get_slave_caps(master->dma_tx, &caps); |
---|
| 726 | + if (ret) { |
---|
| 727 | + dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n", |
---|
| 728 | + ret); |
---|
| 729 | + goto out_release_dma; |
---|
| 730 | + } |
---|
| 731 | + dma_tx_burst = caps.max_burst; |
---|
| 732 | + } |
---|
| 733 | + |
---|
| 734 | + master->dma_rx = dma_request_chan(&pdev->dev, "rx"); |
---|
| 735 | + if (IS_ERR_OR_NULL(master->dma_rx)) { |
---|
| 736 | + if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) { |
---|
| 737 | + ret = -EPROBE_DEFER; |
---|
| 738 | + goto out_release_dma; |
---|
| 739 | + } |
---|
| 740 | + master->dma_rx = NULL; |
---|
| 741 | + dma_rx_burst = INT_MAX; |
---|
| 742 | + } else { |
---|
| 743 | + ret = dma_get_slave_caps(master->dma_rx, &caps); |
---|
| 744 | + if (ret) { |
---|
| 745 | + dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n", |
---|
| 746 | + ret); |
---|
| 747 | + goto out_release_dma; |
---|
| 748 | + } |
---|
| 749 | + dma_rx_burst = caps.max_burst; |
---|
| 750 | + } |
---|
| 751 | + |
---|
| 752 | + master->max_dma_len = min(dma_tx_burst, dma_rx_burst); |
---|
480 | 753 | |
---|
481 | 754 | ret = devm_spi_register_master(&pdev->dev, master); |
---|
482 | 755 | if (ret) |
---|
483 | | - goto out_disable_clk; |
---|
| 756 | + goto out_release_dma; |
---|
484 | 757 | |
---|
485 | 758 | return 0; |
---|
| 759 | + |
---|
| 760 | +out_release_dma: |
---|
| 761 | + if (!IS_ERR_OR_NULL(master->dma_rx)) { |
---|
| 762 | + dma_release_channel(master->dma_rx); |
---|
| 763 | + master->dma_rx = NULL; |
---|
| 764 | + } |
---|
| 765 | + if (!IS_ERR_OR_NULL(master->dma_tx)) { |
---|
| 766 | + dma_release_channel(master->dma_tx); |
---|
| 767 | + master->dma_tx = NULL; |
---|
| 768 | + } |
---|
486 | 769 | |
---|
487 | 770 | out_disable_clk: |
---|
488 | 771 | clk_disable_unprepare(priv->clk); |
---|
.. | .. |
---|
494 | 777 | |
---|
495 | 778 | static int uniphier_spi_remove(struct platform_device *pdev) |
---|
496 | 779 | { |
---|
497 | | - struct uniphier_spi_priv *priv = platform_get_drvdata(pdev); |
---|
| 780 | + struct spi_master *master = platform_get_drvdata(pdev); |
---|
| 781 | + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); |
---|
| 782 | + |
---|
| 783 | + if (master->dma_tx) |
---|
| 784 | + dma_release_channel(master->dma_tx); |
---|
| 785 | + if (master->dma_rx) |
---|
| 786 | + dma_release_channel(master->dma_rx); |
---|
498 | 787 | |
---|
499 | 788 | clk_disable_unprepare(priv->clk); |
---|
500 | 789 | |
---|