Loading drivers/spi/Kconfig +1 −1 Original line number Original line Diff line number Diff line Loading @@ -446,7 +446,7 @@ config SPI_SC18IS602 config SPI_SH_MSIOF config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" tristate "SuperH MSIOF SPI controller" depends on HAVE_CLK depends on HAVE_CLK && HAS_DMA depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST help help SPI driver for SuperH and SH Mobile MSIOF blocks. SPI driver for SuperH and SH Mobile MSIOF blocks. Loading drivers/spi/spi-sh-msiof.c +480 −49 Original line number Original line Diff line number Diff line Loading @@ -2,6 +2,7 @@ * SuperH MSIOF SPI Master Interface * SuperH MSIOF SPI Master Interface * * * Copyright (c) 2009 Magnus Damm * Copyright (c) 2009 Magnus Damm * Copyright (C) 2014 Glider bvba * * * This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as Loading @@ -13,6 +14,8 @@ #include <linux/clk.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/err.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/interrupt.h> Loading @@ -23,6 +26,7 @@ #include <linux/of_device.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/pm_runtime.h> #include <linux/sh_dma.h> #include <linux/spi/sh_msiof.h> #include <linux/spi/sh_msiof.h> #include <linux/spi/spi.h> #include <linux/spi/spi.h> Loading @@ -37,6 +41,7 @@ struct sh_msiof_chipdata { }; }; struct sh_msiof_spi_priv { struct sh_msiof_spi_priv { struct spi_master *master; void __iomem *mapbase; void __iomem *mapbase; struct clk *clk; struct clk *clk; struct platform_device *pdev; struct platform_device *pdev; Loading @@ -45,6 +50,10 @@ struct sh_msiof_spi_priv { struct completion done; struct completion done; int tx_fifo_size; int tx_fifo_size; int rx_fifo_size; int rx_fifo_size; void *tx_dma_page; void *rx_dma_page; dma_addr_t tx_dma_addr; dma_addr_t rx_dma_addr; }; }; #define TMDR1 0x00 /* Transmit Mode Register 1 */ #define TMDR1 0x00 /* Transmit Mode Register 1 */ Loading Loading @@ -84,6 +93,8 @@ struct sh_msiof_spi_priv { #define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ #define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ #define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ #define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ #define MAX_WDLEN 256U /* TSCR and RSCR */ /* TSCR and RSCR */ #define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ #define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ #define SCR_BRPS(i) (((i) - 1) << 8) #define SCR_BRPS(i) (((i) - 1) << 8) Loading Loading @@ -113,9 +124,61 @@ struct sh_msiof_spi_priv { #define CTR_TXE 0x00000200 /* Transmit Enable */ #define CTR_TXE 0x00000200 /* Transmit Enable */ #define CTR_RXE 0x00000100 /* Receive Enable */ #define CTR_RXE 0x00000100 /* Receive Enable */ /* STR and IER */ /* FCTR */ #define FCTR_TFWM_MASK 0xe0000000 /* Transmit FIFO Watermark */ #define FCTR_TFWM_64 0x00000000 /* Transfer Request when 64 empty stages */ #define FCTR_TFWM_32 0x20000000 /* Transfer Request when 32 empty stages */ #define FCTR_TFWM_24 0x40000000 /* Transfer Request when 24 empty stages */ #define FCTR_TFWM_16 0x60000000 /* Transfer Request when 16 empty stages */ #define FCTR_TFWM_12 0x80000000 /* Transfer Request when 12 empty stages */ #define FCTR_TFWM_8 0xa0000000 /* Transfer Request when 8 empty stages */ #define FCTR_TFWM_4 0xc0000000 /* Transfer Request when 4 empty stages */ #define FCTR_TFWM_1 0xe0000000 /* Transfer Request when 1 empty stage */ #define FCTR_TFUA_MASK 0x07f00000 /* Transmit FIFO Usable Area */ #define FCTR_TFUA_SHIFT 20 #define FCTR_TFUA(i) ((i) << FCTR_TFUA_SHIFT) #define FCTR_RFWM_MASK 0x0000e000 /* Receive FIFO Watermark */ #define FCTR_RFWM_1 0x00000000 /* Transfer Request when 1 valid stages */ #define FCTR_RFWM_4 0x00002000 /* Transfer Request when 4 valid stages */ #define FCTR_RFWM_8 0x00004000 /* Transfer Request when 8 valid stages */ #define FCTR_RFWM_16 0x00006000 /* Transfer Request when 16 valid stages */ #define FCTR_RFWM_32 0x00008000 /* Transfer Request when 32 valid stages */ #define FCTR_RFWM_64 0x0000a000 /* Transfer Request when 64 valid stages */ #define FCTR_RFWM_128 0x0000c000 /* Transfer Request when 128 valid stages */ #define FCTR_RFWM_256 0x0000e000 /* Transfer Request when 256 valid stages */ #define FCTR_RFUA_MASK 0x00001ff0 /* Receive FIFO Usable Area (0x40 = full) */ #define FCTR_RFUA_SHIFT 4 #define FCTR_RFUA(i) ((i) << FCTR_RFUA_SHIFT) /* STR */ #define STR_TFEMP 0x20000000 /* Transmit FIFO Empty */ #define STR_TDREQ 0x10000000 /* Transmit Data Transfer Request */ #define STR_TEOF 0x00800000 /* Frame Transmission End */ #define STR_TEOF 0x00800000 /* Frame Transmission End */ #define STR_TFSERR 0x00200000 /* Transmit Frame Synchronization Error */ #define STR_TFOVF 0x00100000 /* Transmit FIFO Overflow */ #define STR_TFUDF 0x00080000 /* Transmit FIFO Underflow */ #define STR_RFFUL 0x00002000 /* Receive FIFO Full */ #define STR_RDREQ 0x00001000 /* Receive Data Transfer Request */ #define STR_REOF 0x00000080 /* Frame Reception End */ #define STR_REOF 0x00000080 /* Frame Reception End */ #define STR_RFSERR 0x00000020 /* Receive Frame Synchronization Error */ #define STR_RFUDF 0x00000010 /* Receive FIFO Underflow */ #define STR_RFOVF 0x00000008 /* Receive FIFO Overflow */ /* IER */ #define IER_TDMAE 0x80000000 /* Transmit Data DMA Transfer Req. Enable */ #define IER_TFEMPE 0x20000000 /* Transmit FIFO Empty Enable */ #define IER_TDREQE 0x10000000 /* Transmit Data Transfer Request Enable */ #define IER_TEOFE 0x00800000 /* Frame Transmission End Enable */ #define IER_TFSERRE 0x00200000 /* Transmit Frame Sync Error Enable */ #define IER_TFOVFE 0x00100000 /* Transmit FIFO Overflow Enable */ #define IER_TFUDFE 0x00080000 /* Transmit FIFO Underflow Enable */ #define IER_RDMAE 0x00008000 /* Receive Data DMA Transfer Req. Enable */ #define IER_RFFULE 0x00002000 /* Receive FIFO Full Enable */ #define IER_RDREQE 0x00001000 /* Receive Data Transfer Request Enable */ #define IER_REOFE 0x00000080 /* Frame Reception End Enable */ #define IER_RFSERRE 0x00000020 /* Receive Frame Sync Error Enable */ #define IER_RFUDFE 0x00000010 /* Receive FIFO Underflow Enable */ #define IER_RFOVFE 0x00000008 /* Receive FIFO Overflow Enable */ static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) Loading Loading @@ -230,8 +293,6 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, * 1 0 11 11 0 0 * 1 0 11 11 0 0 * 1 1 11 11 1 1 * 1 1 11 11 1 1 */ */ sh_msiof_write(p, FCTR, 0); tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; Loading Loading @@ -267,8 +328,6 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, if (rx_buf) if (rx_buf) sh_msiof_write(p, RMDR2, dr2); sh_msiof_write(p, RMDR2, dr2); sh_msiof_write(p, IER, STR_TEOF | STR_REOF); } } static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p) static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p) Loading Loading @@ -457,6 +516,40 @@ static int sh_msiof_prepare_message(struct spi_master *master, return 0; return 0; } } static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) { int ret; /* setup clock and rx/tx signals */ ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); if (rx_buf && !ret) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); if (!ret) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); /* start by setting frame bit */ if (!ret) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); return ret; } static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf) { int ret; /* shut down frame, rx/tx and clock signals */ ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); if (!ret) ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); if (rx_buf && !ret) ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); if (!ret) ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); return ret; } static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, void (*tx_fifo)(struct sh_msiof_spi_priv *, void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int), const void *, int, int), Loading @@ -477,29 +570,32 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, /* the fifo contents need shifting */ /* the fifo contents need shifting */ fifo_shift = 32 - bits; fifo_shift = 32 - bits; /* default FIFO watermarks for PIO */ sh_msiof_write(p, FCTR, 0); /* setup msiof transfer mode registers */ /* setup msiof transfer mode registers */ sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words); sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words); sh_msiof_write(p, IER, IER_TEOFE | IER_REOFE); /* write tx fifo */ /* write tx fifo */ if (tx_buf) if (tx_buf) tx_fifo(p, tx_buf, words, fifo_shift); tx_fifo(p, tx_buf, words, fifo_shift); /* setup clock and rx/tx signals */ ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); if (rx_buf) ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); /* start by setting frame bit */ reinit_completion(&p->done); reinit_completion(&p->done); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); ret = sh_msiof_spi_start(p, rx_buf); if (ret) { if (ret) { dev_err(&p->pdev->dev, "failed to start hardware\n"); dev_err(&p->pdev->dev, "failed to start hardware\n"); goto err; goto stop_ier; } } /* wait for tx fifo to be emptied / rx fifo to be filled */ /* wait for tx fifo to be emptied / rx fifo to be filled */ wait_for_completion(&p->done); ret = wait_for_completion_timeout(&p->done, HZ); if (!ret) { dev_err(&p->pdev->dev, "PIO timeout\n"); ret = -ETIMEDOUT; goto stop_reset; } /* read rx fifo */ /* read rx fifo */ if (rx_buf) if (rx_buf) Loading @@ -508,41 +604,248 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, /* clear status bits */ /* clear status bits */ sh_msiof_reset_str(p); sh_msiof_reset_str(p); /* shut down frame, rx/tx and clock signals */ ret = sh_msiof_spi_stop(p, rx_buf); ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); if (rx_buf) ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); if (ret) { if (ret) { dev_err(&p->pdev->dev, "failed to shut down hardware\n"); dev_err(&p->pdev->dev, "failed to shut down hardware\n"); goto err; return ret; } } return words; return words; err: stop_reset: sh_msiof_reset_str(p); sh_msiof_spi_stop(p, rx_buf); stop_ier: sh_msiof_write(p, IER, 0); return ret; } static void sh_msiof_dma_complete(void *arg) { struct sh_msiof_spi_priv *p = arg; sh_msiof_write(p, IER, 0); complete(&p->done); } static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, void *rx, unsigned int len) { u32 ier_bits = 0; struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL; dma_cookie_t cookie; int ret; if (tx) { ier_bits |= IER_TDREQE | IER_TDMAE; dma_sync_single_for_device(p->master->dma_tx->device->dev, p->tx_dma_addr, len, DMA_TO_DEVICE); desc_tx = dmaengine_prep_slave_single(p->master->dma_tx, p->tx_dma_addr, len, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) return -EAGAIN; } if (rx) { ier_bits |= IER_RDREQE | IER_RDMAE; desc_rx = dmaengine_prep_slave_single(p->master->dma_rx, p->rx_dma_addr, len, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) return -EAGAIN; } /* 1 stage FIFO watermarks for DMA */ sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); /* setup msiof transfer mode registers (32-bit words) */ sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); sh_msiof_write(p, IER, ier_bits); reinit_completion(&p->done); if (rx) { desc_rx->callback = sh_msiof_dma_complete; desc_rx->callback_param = p; cookie = dmaengine_submit(desc_rx); if (dma_submit_error(cookie)) { ret = cookie; goto stop_ier; } dma_async_issue_pending(p->master->dma_rx); } if (tx) { if (rx) { /* No callback */ desc_tx->callback = NULL; } else { desc_tx->callback = sh_msiof_dma_complete; desc_tx->callback_param = p; } cookie = dmaengine_submit(desc_tx); if (dma_submit_error(cookie)) { ret = cookie; goto stop_rx; } dma_async_issue_pending(p->master->dma_tx); } ret = sh_msiof_spi_start(p, rx); if (ret) { dev_err(&p->pdev->dev, "failed to start hardware\n"); goto stop_tx; } /* wait for tx fifo to be emptied / rx fifo to be filled */ ret = wait_for_completion_timeout(&p->done, HZ); if (!ret) { dev_err(&p->pdev->dev, "DMA timeout\n"); ret = -ETIMEDOUT; goto stop_reset; } /* clear status bits */ sh_msiof_reset_str(p); ret = sh_msiof_spi_stop(p, rx); if (ret) { dev_err(&p->pdev->dev, "failed to shut down hardware\n"); return ret; } if (rx) dma_sync_single_for_cpu(p->master->dma_rx->device->dev, p->rx_dma_addr, len, DMA_FROM_DEVICE); return 0; stop_reset: sh_msiof_reset_str(p); sh_msiof_spi_stop(p, rx); stop_tx: if (tx) dmaengine_terminate_all(p->master->dma_tx); stop_rx: if (rx) dmaengine_terminate_all(p->master->dma_rx); stop_ier: sh_msiof_write(p, IER, 0); sh_msiof_write(p, IER, 0); return ret; return ret; } } static void copy_bswap32(u32 *dst, const u32 *src, unsigned int words) { /* src or dst can be unaligned, but not both */ if ((unsigned long)src & 3) { while (words--) { *dst++ = swab32(get_unaligned(src)); src++; } } else if ((unsigned long)dst & 3) { while (words--) { put_unaligned(swab32(*src++), dst); dst++; } } else { while (words--) *dst++ = swab32(*src++); } } static void copy_wswap32(u32 *dst, const u32 *src, unsigned int words) { /* src or dst can be unaligned, but not both */ if ((unsigned long)src & 3) { while (words--) { *dst++ = swahw32(get_unaligned(src)); src++; } } else if ((unsigned long)dst & 3) { while (words--) { put_unaligned(swahw32(*src++), dst); dst++; } } else { while (words--) *dst++ = swahw32(*src++); } } static void copy_plain32(u32 *dst, const u32 *src, unsigned int words) { memcpy(dst, src, words * 4); } static int sh_msiof_transfer_one(struct spi_master *master, static int sh_msiof_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_device *spi, struct spi_transfer *t) struct spi_transfer *t) { { struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); void (*copy32)(u32 *, const u32 *, unsigned int); void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int); void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int); void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int); void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int); int bits; const void *tx_buf = t->tx_buf; int bytes_per_word; void *rx_buf = t->rx_buf; int bytes_done; unsigned int len = t->len; int words; unsigned int bits = t->bits_per_word; unsigned int bytes_per_word; unsigned int words; int n; int n; bool swab; bool swab; int ret; /* setup clocks (clock already enabled in chipselect()) */ sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); while (master->dma_tx && len > 15) { /* * DMA supports 32-bit words only, hence pack 8-bit and 16-bit * words, with byte resp. word swapping. */ unsigned int l = min(len, MAX_WDLEN * 4); if (bits <= 8) { if (l & 3) break; copy32 = copy_bswap32; } else if (bits <= 16) { if (l & 1) break; copy32 = copy_wswap32; } else { copy32 = copy_plain32; } if (tx_buf) copy32(p->tx_dma_page, tx_buf, l / 4); ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l); if (ret == -EAGAIN) { pr_warn_once("%s %s: DMA not available, falling back to PIO\n", dev_driver_string(&p->pdev->dev), dev_name(&p->pdev->dev)); break; } if (ret) return ret; bits = t->bits_per_word; if (rx_buf) { copy32(rx_buf, p->rx_dma_page, l / 4); rx_buf += l; } if (tx_buf) tx_buf += l; if (bits <= 8 && t->len > 15 && !(t->len & 3)) { len -= l; if (!len) return 0; } if (bits <= 8 && len > 15 && !(len & 3)) { bits = 32; bits = 32; swab = true; swab = true; } else { } else { Loading @@ -556,57 +859,52 @@ static int sh_msiof_transfer_one(struct spi_master *master, rx_fifo = sh_msiof_spi_read_fifo_8; rx_fifo = sh_msiof_spi_read_fifo_8; } else if (bits <= 16) { } else if (bits <= 16) { bytes_per_word = 2; bytes_per_word = 2; if ((unsigned long)t->tx_buf & 0x01) if ((unsigned long)tx_buf & 0x01) tx_fifo = sh_msiof_spi_write_fifo_16u; tx_fifo = sh_msiof_spi_write_fifo_16u; else else tx_fifo = sh_msiof_spi_write_fifo_16; tx_fifo = sh_msiof_spi_write_fifo_16; if ((unsigned long)t->rx_buf & 0x01) if ((unsigned long)rx_buf & 0x01) rx_fifo = sh_msiof_spi_read_fifo_16u; rx_fifo = sh_msiof_spi_read_fifo_16u; else else rx_fifo = sh_msiof_spi_read_fifo_16; rx_fifo = sh_msiof_spi_read_fifo_16; } else if (swab) { } else if (swab) { bytes_per_word = 4; bytes_per_word = 4; if ((unsigned long)t->tx_buf & 0x03) if ((unsigned long)tx_buf & 0x03) tx_fifo = sh_msiof_spi_write_fifo_s32u; tx_fifo = sh_msiof_spi_write_fifo_s32u; else else tx_fifo = sh_msiof_spi_write_fifo_s32; tx_fifo = sh_msiof_spi_write_fifo_s32; if ((unsigned long)t->rx_buf & 0x03) if ((unsigned long)rx_buf & 0x03) rx_fifo = sh_msiof_spi_read_fifo_s32u; rx_fifo = sh_msiof_spi_read_fifo_s32u; else else rx_fifo = sh_msiof_spi_read_fifo_s32; rx_fifo = sh_msiof_spi_read_fifo_s32; } else { } else { bytes_per_word = 4; bytes_per_word = 4; if ((unsigned long)t->tx_buf & 0x03) if ((unsigned long)tx_buf & 0x03) tx_fifo = sh_msiof_spi_write_fifo_32u; tx_fifo = sh_msiof_spi_write_fifo_32u; else else tx_fifo = sh_msiof_spi_write_fifo_32; tx_fifo = sh_msiof_spi_write_fifo_32; if ((unsigned long)t->rx_buf & 0x03) if ((unsigned long)rx_buf & 0x03) rx_fifo = sh_msiof_spi_read_fifo_32u; rx_fifo = sh_msiof_spi_read_fifo_32u; else else rx_fifo = sh_msiof_spi_read_fifo_32; rx_fifo = sh_msiof_spi_read_fifo_32; } } /* setup clocks (clock already enabled in chipselect()) */ sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); /* transfer in fifo sized chunks */ /* transfer in fifo sized chunks */ words = t->len / bytes_per_word; words = len / bytes_per_word; bytes_done = 0; while (words > 0) { while (bytes_done < t->len) { n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo, tx_buf, rx_buf, void *rx_buf = t->rx_buf ? t->rx_buf + bytes_done : NULL; const void *tx_buf = t->tx_buf ? t->tx_buf + bytes_done : NULL; n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo, tx_buf, rx_buf, words, bits); words, bits); if (n < 0) if (n < 0) break; return n; bytes_done += n * bytes_per_word; if (tx_buf) tx_buf += n * bytes_per_word; if (rx_buf) rx_buf += n * bytes_per_word; words -= n; words -= n; } } Loading Loading @@ -663,6 +961,128 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) } } #endif #endif static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev, enum dma_transfer_direction dir, unsigned int id, dma_addr_t port_addr) { dma_cap_mask_t mask; struct dma_chan *chan; struct dma_slave_config cfg; int ret; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); chan = dma_request_channel(mask, shdma_chan_filter, (void *)(unsigned long)id); if (!chan) { dev_warn(dev, "dma_request_channel failed\n"); return NULL; } memset(&cfg, 0, sizeof(cfg)); cfg.slave_id = id; cfg.direction = dir; if (dir == DMA_MEM_TO_DEV) cfg.dst_addr = port_addr; else cfg.src_addr = port_addr; ret = dmaengine_slave_config(chan, &cfg); if (ret) { dev_warn(dev, "dmaengine_slave_config failed %d\n", ret); dma_release_channel(chan); return NULL; } return chan; } static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p) { struct platform_device *pdev = p->pdev; struct device *dev = &pdev->dev; const struct sh_msiof_spi_info *info = dev_get_platdata(dev); const struct resource *res; struct spi_master *master; struct device *tx_dev, *rx_dev; if (!info || !info->dma_tx_id || !info->dma_rx_id) return 0; /* The driver assumes no error */ /* The DMA engine uses the second register set, if present */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); master = p->master; master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV, info->dma_tx_id, res->start + TFDR); if (!master->dma_tx) return -ENODEV; master->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM, info->dma_rx_id, res->start + RFDR); if (!master->dma_rx) goto free_tx_chan; p->tx_dma_page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); if (!p->tx_dma_page) goto free_rx_chan; p->rx_dma_page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); if (!p->rx_dma_page) goto free_tx_page; tx_dev = master->dma_tx->device->dev; p->tx_dma_addr = dma_map_single(tx_dev, p->tx_dma_page, PAGE_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(tx_dev, p->tx_dma_addr)) goto free_rx_page; rx_dev = master->dma_rx->device->dev; p->rx_dma_addr = dma_map_single(rx_dev, p->rx_dma_page, PAGE_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(rx_dev, p->rx_dma_addr)) goto unmap_tx_page; dev_info(dev, "DMA available"); return 0; unmap_tx_page: dma_unmap_single(tx_dev, p->tx_dma_addr, PAGE_SIZE, DMA_TO_DEVICE); free_rx_page: free_page((unsigned long)p->rx_dma_page); free_tx_page: free_page((unsigned long)p->tx_dma_page); free_rx_chan: dma_release_channel(master->dma_rx); free_tx_chan: dma_release_channel(master->dma_tx); master->dma_tx = NULL; return -ENODEV; } static void sh_msiof_release_dma(struct sh_msiof_spi_priv *p) { struct spi_master *master = p->master; struct device *dev; if (!master->dma_tx) return; dev = &p->pdev->dev; dma_unmap_single(master->dma_rx->device->dev, p->rx_dma_addr, PAGE_SIZE, DMA_FROM_DEVICE); dma_unmap_single(master->dma_tx->device->dev, p->tx_dma_addr, PAGE_SIZE, DMA_TO_DEVICE); free_page((unsigned long)p->rx_dma_page); free_page((unsigned long)p->tx_dma_page); dma_release_channel(master->dma_rx); dma_release_channel(master->dma_tx); } static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_probe(struct platform_device *pdev) { { struct resource *r; struct resource *r; Loading @@ -680,6 +1100,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p = spi_master_get_devdata(master); p = spi_master_get_devdata(master); platform_set_drvdata(pdev, p); p->master = master; of_id = of_match_device(sh_msiof_match, &pdev->dev); of_id = of_match_device(sh_msiof_match, &pdev->dev); if (of_id) { if (of_id) { p->chipdata = of_id->data; p->chipdata = of_id->data; Loading Loading @@ -749,6 +1172,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; master->auto_runtime_pm = true; master->transfer_one = sh_msiof_transfer_one; master->transfer_one = sh_msiof_transfer_one; ret = sh_msiof_request_dma(p); if (ret < 0) dev_warn(&pdev->dev, "DMA not available, using PIO\n"); ret = devm_spi_register_master(&pdev->dev, master); ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); dev_err(&pdev->dev, "spi_register_master error.\n"); Loading @@ -758,6 +1185,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) return 0; return 0; err2: err2: sh_msiof_release_dma(p); pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev); err1: err1: spi_master_put(master); spi_master_put(master); Loading @@ -766,6 +1194,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) { { struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); sh_msiof_release_dma(p); pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; return 0; } } Loading drivers/spi/spi-sh.c +6 −9 Original line number Original line Diff line number Diff line Loading @@ -432,7 +432,6 @@ static int spi_sh_remove(struct platform_device *pdev) spi_unregister_master(ss->master); spi_unregister_master(ss->master); destroy_workqueue(ss->workqueue); destroy_workqueue(ss->workqueue); free_irq(ss->irq, ss); free_irq(ss->irq, ss); iounmap(ss->addr); return 0; return 0; } } Loading Loading @@ -480,7 +479,7 @@ static int spi_sh_probe(struct platform_device *pdev) } } ss->irq = irq; ss->irq = irq; ss->master = master; ss->master = master; ss->addr = ioremap(res->start, resource_size(res)); ss->addr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (ss->addr == NULL) { if (ss->addr == NULL) { dev_err(&pdev->dev, "ioremap error.\n"); dev_err(&pdev->dev, "ioremap error.\n"); ret = -ENOMEM; ret = -ENOMEM; Loading @@ -495,13 +494,13 @@ static int spi_sh_probe(struct platform_device *pdev) if (ss->workqueue == NULL) { if (ss->workqueue == NULL) { dev_err(&pdev->dev, "create workqueue error\n"); dev_err(&pdev->dev, "create workqueue error\n"); ret = -EBUSY; ret = -EBUSY; goto error2; goto error1; } } ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss); ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss); if (ret < 0) { if (ret < 0) { dev_err(&pdev->dev, "request_irq error\n"); dev_err(&pdev->dev, "request_irq error\n"); goto error3; goto error2; } } master->num_chipselect = 2; master->num_chipselect = 2; Loading @@ -513,17 +512,15 @@ static int spi_sh_probe(struct platform_device *pdev) ret = spi_register_master(master); ret = spi_register_master(master); if (ret < 0) { if (ret < 0) { printk(KERN_ERR "spi_register_master error.\n"); printk(KERN_ERR "spi_register_master error.\n"); goto error4; goto error3; } } return 0; return 0; error4: free_irq(irq, ss); error3: error3: destroy_workqueue(ss->workqueue); free_irq(irq, ss); error2: error2: iounmap(ss->addr); destroy_workqueue(ss->workqueue); error1: error1: spi_master_put(master); spi_master_put(master); Loading drivers/spi/spi-topcliff-pch.c +6 −6 Original line number Original line Diff line number Diff line Loading @@ -874,8 +874,8 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask); /* Get DMA's dev information */ /* Get DMA's dev information */ dma_dev = pci_get_bus_and_slot(data->board_dat->pdev->bus->number, dma_dev = pci_get_slot(data->board_dat->pdev->bus, PCI_DEVFN(12, 0)); PCI_DEVFN(PCI_SLOT(data->board_dat->pdev->devfn), 0)); /* Set Tx DMA */ /* Set Tx DMA */ param = &dma->param_tx; param = &dma->param_tx; Loading Loading @@ -1047,8 +1047,8 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) num, DMA_DEV_TO_MEM, num, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) { if (!desc_rx) { dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n", dev_err(&data->master->dev, __func__); "%s:dmaengine_prep_slave_sg Failed\n", __func__); return; return; } } dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_FROM_DEVICE); dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_FROM_DEVICE); Loading Loading @@ -1106,8 +1106,8 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) sg, num, DMA_MEM_TO_DEV, sg, num, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { if (!desc_tx) { dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n", dev_err(&data->master->dev, __func__); "%s:dmaengine_prep_slave_sg Failed\n", __func__); return; return; } } dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_TO_DEVICE); dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_TO_DEVICE); Loading include/linux/spi/sh_msiof.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -5,6 +5,8 @@ struct sh_msiof_spi_info { int tx_fifo_override; int tx_fifo_override; int rx_fifo_override; int rx_fifo_override; u16 num_chipselect; u16 num_chipselect; unsigned int dma_tx_id; unsigned int dma_rx_id; }; }; #endif /* __SPI_SH_MSIOF_H__ */ #endif /* __SPI_SH_MSIOF_H__ */ Loading
drivers/spi/Kconfig +1 −1 Original line number Original line Diff line number Diff line Loading @@ -446,7 +446,7 @@ config SPI_SC18IS602 config SPI_SH_MSIOF config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" tristate "SuperH MSIOF SPI controller" depends on HAVE_CLK depends on HAVE_CLK && HAS_DMA depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST help help SPI driver for SuperH and SH Mobile MSIOF blocks. SPI driver for SuperH and SH Mobile MSIOF blocks. Loading
drivers/spi/spi-sh-msiof.c +480 −49 Original line number Original line Diff line number Diff line Loading @@ -2,6 +2,7 @@ * SuperH MSIOF SPI Master Interface * SuperH MSIOF SPI Master Interface * * * Copyright (c) 2009 Magnus Damm * Copyright (c) 2009 Magnus Damm * Copyright (C) 2014 Glider bvba * * * This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as Loading @@ -13,6 +14,8 @@ #include <linux/clk.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/err.h> #include <linux/err.h> #include <linux/gpio.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/interrupt.h> Loading @@ -23,6 +26,7 @@ #include <linux/of_device.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/pm_runtime.h> #include <linux/sh_dma.h> #include <linux/spi/sh_msiof.h> #include <linux/spi/sh_msiof.h> #include <linux/spi/spi.h> #include <linux/spi/spi.h> Loading @@ -37,6 +41,7 @@ struct sh_msiof_chipdata { }; }; struct sh_msiof_spi_priv { struct sh_msiof_spi_priv { struct spi_master *master; void __iomem *mapbase; void __iomem *mapbase; struct clk *clk; struct clk *clk; struct platform_device *pdev; struct platform_device *pdev; Loading @@ -45,6 +50,10 @@ struct sh_msiof_spi_priv { struct completion done; struct completion done; int tx_fifo_size; int tx_fifo_size; int rx_fifo_size; int rx_fifo_size; void *tx_dma_page; void *rx_dma_page; dma_addr_t tx_dma_addr; dma_addr_t rx_dma_addr; }; }; #define TMDR1 0x00 /* Transmit Mode Register 1 */ #define TMDR1 0x00 /* Transmit Mode Register 1 */ Loading Loading @@ -84,6 +93,8 @@ struct sh_msiof_spi_priv { #define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ #define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ #define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ #define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ #define MAX_WDLEN 256U /* TSCR and RSCR */ /* TSCR and RSCR */ #define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ #define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ #define SCR_BRPS(i) (((i) - 1) << 8) #define SCR_BRPS(i) (((i) - 1) << 8) Loading Loading @@ -113,9 +124,61 @@ struct sh_msiof_spi_priv { #define CTR_TXE 0x00000200 /* Transmit Enable */ #define CTR_TXE 0x00000200 /* Transmit Enable */ #define CTR_RXE 0x00000100 /* Receive Enable */ #define CTR_RXE 0x00000100 /* Receive Enable */ /* STR and IER */ /* FCTR */ #define FCTR_TFWM_MASK 0xe0000000 /* Transmit FIFO Watermark */ #define FCTR_TFWM_64 0x00000000 /* Transfer Request when 64 empty stages */ #define FCTR_TFWM_32 0x20000000 /* Transfer Request when 32 empty stages */ #define FCTR_TFWM_24 0x40000000 /* Transfer Request when 24 empty stages */ #define FCTR_TFWM_16 0x60000000 /* Transfer Request when 16 empty stages */ #define FCTR_TFWM_12 0x80000000 /* Transfer Request when 12 empty stages */ #define FCTR_TFWM_8 0xa0000000 /* Transfer Request when 8 empty stages */ #define FCTR_TFWM_4 0xc0000000 /* Transfer Request when 4 empty stages */ #define FCTR_TFWM_1 0xe0000000 /* Transfer Request when 1 empty stage */ #define FCTR_TFUA_MASK 0x07f00000 /* Transmit FIFO Usable Area */ #define FCTR_TFUA_SHIFT 20 #define FCTR_TFUA(i) ((i) << FCTR_TFUA_SHIFT) #define FCTR_RFWM_MASK 0x0000e000 /* Receive FIFO Watermark */ #define FCTR_RFWM_1 0x00000000 /* Transfer Request when 1 valid stages */ #define FCTR_RFWM_4 0x00002000 /* Transfer Request when 4 valid stages */ #define FCTR_RFWM_8 0x00004000 /* Transfer Request when 8 valid stages */ #define FCTR_RFWM_16 0x00006000 /* Transfer Request when 16 valid stages */ #define FCTR_RFWM_32 0x00008000 /* Transfer Request when 32 valid stages */ #define FCTR_RFWM_64 0x0000a000 /* Transfer Request when 64 valid stages */ #define FCTR_RFWM_128 0x0000c000 /* Transfer Request when 128 valid stages */ #define FCTR_RFWM_256 0x0000e000 /* Transfer Request when 256 valid stages */ #define FCTR_RFUA_MASK 0x00001ff0 /* Receive FIFO Usable Area (0x40 = full) */ #define FCTR_RFUA_SHIFT 4 #define FCTR_RFUA(i) ((i) << FCTR_RFUA_SHIFT) /* STR */ #define STR_TFEMP 0x20000000 /* Transmit FIFO Empty */ #define STR_TDREQ 0x10000000 /* Transmit Data Transfer Request */ #define STR_TEOF 0x00800000 /* Frame Transmission End */ #define STR_TEOF 0x00800000 /* Frame Transmission End */ #define STR_TFSERR 0x00200000 /* Transmit Frame Synchronization Error */ #define STR_TFOVF 0x00100000 /* Transmit FIFO Overflow */ #define STR_TFUDF 0x00080000 /* Transmit FIFO Underflow */ #define STR_RFFUL 0x00002000 /* Receive FIFO Full */ #define STR_RDREQ 0x00001000 /* Receive Data Transfer Request */ #define STR_REOF 0x00000080 /* Frame Reception End */ #define STR_REOF 0x00000080 /* Frame Reception End */ #define STR_RFSERR 0x00000020 /* Receive Frame Synchronization Error */ #define STR_RFUDF 0x00000010 /* Receive FIFO Underflow */ #define STR_RFOVF 0x00000008 /* Receive FIFO Overflow */ /* IER */ #define IER_TDMAE 0x80000000 /* Transmit Data DMA Transfer Req. Enable */ #define IER_TFEMPE 0x20000000 /* Transmit FIFO Empty Enable */ #define IER_TDREQE 0x10000000 /* Transmit Data Transfer Request Enable */ #define IER_TEOFE 0x00800000 /* Frame Transmission End Enable */ #define IER_TFSERRE 0x00200000 /* Transmit Frame Sync Error Enable */ #define IER_TFOVFE 0x00100000 /* Transmit FIFO Overflow Enable */ #define IER_TFUDFE 0x00080000 /* Transmit FIFO Underflow Enable */ #define IER_RDMAE 0x00008000 /* Receive Data DMA Transfer Req. Enable */ #define IER_RFFULE 0x00002000 /* Receive FIFO Full Enable */ #define IER_RDREQE 0x00001000 /* Receive Data Transfer Request Enable */ #define IER_REOFE 0x00000080 /* Frame Reception End Enable */ #define IER_RFSERRE 0x00000020 /* Receive Frame Sync Error Enable */ #define IER_RFUDFE 0x00000010 /* Receive FIFO Underflow Enable */ #define IER_RFOVFE 0x00000008 /* Receive FIFO Overflow Enable */ static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) Loading Loading @@ -230,8 +293,6 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, * 1 0 11 11 0 0 * 1 0 11 11 0 0 * 1 1 11 11 1 1 * 1 1 11 11 1 1 */ */ sh_msiof_write(p, FCTR, 0); tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; Loading Loading @@ -267,8 +328,6 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, if (rx_buf) if (rx_buf) sh_msiof_write(p, RMDR2, dr2); sh_msiof_write(p, RMDR2, dr2); sh_msiof_write(p, IER, STR_TEOF | STR_REOF); } } static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p) static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p) Loading Loading @@ -457,6 +516,40 @@ static int sh_msiof_prepare_message(struct spi_master *master, return 0; return 0; } } static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) { int ret; /* setup clock and rx/tx signals */ ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); if (rx_buf && !ret) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); if (!ret) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); /* start by setting frame bit */ if (!ret) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); return ret; } static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf) { int ret; /* shut down frame, rx/tx and clock signals */ ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); if (!ret) ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); if (rx_buf && !ret) ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); if (!ret) ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); return ret; } static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, void (*tx_fifo)(struct sh_msiof_spi_priv *, void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int), const void *, int, int), Loading @@ -477,29 +570,32 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, /* the fifo contents need shifting */ /* the fifo contents need shifting */ fifo_shift = 32 - bits; fifo_shift = 32 - bits; /* default FIFO watermarks for PIO */ sh_msiof_write(p, FCTR, 0); /* setup msiof transfer mode registers */ /* setup msiof transfer mode registers */ sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words); sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words); sh_msiof_write(p, IER, IER_TEOFE | IER_REOFE); /* write tx fifo */ /* write tx fifo */ if (tx_buf) if (tx_buf) tx_fifo(p, tx_buf, words, fifo_shift); tx_fifo(p, tx_buf, words, fifo_shift); /* setup clock and rx/tx signals */ ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); if (rx_buf) ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); /* start by setting frame bit */ reinit_completion(&p->done); reinit_completion(&p->done); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); ret = sh_msiof_spi_start(p, rx_buf); if (ret) { if (ret) { dev_err(&p->pdev->dev, "failed to start hardware\n"); dev_err(&p->pdev->dev, "failed to start hardware\n"); goto err; goto stop_ier; } } /* wait for tx fifo to be emptied / rx fifo to be filled */ /* wait for tx fifo to be emptied / rx fifo to be filled */ wait_for_completion(&p->done); ret = wait_for_completion_timeout(&p->done, HZ); if (!ret) { dev_err(&p->pdev->dev, "PIO timeout\n"); ret = -ETIMEDOUT; goto stop_reset; } /* read rx fifo */ /* read rx fifo */ if (rx_buf) if (rx_buf) Loading @@ -508,41 +604,248 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, /* clear status bits */ /* clear status bits */ sh_msiof_reset_str(p); sh_msiof_reset_str(p); /* shut down frame, rx/tx and clock signals */ ret = sh_msiof_spi_stop(p, rx_buf); ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); if (rx_buf) ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); if (ret) { if (ret) { dev_err(&p->pdev->dev, "failed to shut down hardware\n"); dev_err(&p->pdev->dev, "failed to shut down hardware\n"); goto err; return ret; } } return words; return words; err: stop_reset: sh_msiof_reset_str(p); sh_msiof_spi_stop(p, rx_buf); stop_ier: sh_msiof_write(p, IER, 0); return ret; } static void sh_msiof_dma_complete(void *arg) { struct sh_msiof_spi_priv *p = arg; sh_msiof_write(p, IER, 0); complete(&p->done); } static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, void *rx, unsigned int len) { u32 ier_bits = 0; struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL; dma_cookie_t cookie; int ret; if (tx) { ier_bits |= IER_TDREQE | IER_TDMAE; dma_sync_single_for_device(p->master->dma_tx->device->dev, p->tx_dma_addr, len, DMA_TO_DEVICE); desc_tx = dmaengine_prep_slave_single(p->master->dma_tx, p->tx_dma_addr, len, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) return -EAGAIN; } if (rx) { ier_bits |= IER_RDREQE | IER_RDMAE; desc_rx = dmaengine_prep_slave_single(p->master->dma_rx, p->rx_dma_addr, len, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) return -EAGAIN; } /* 1 stage FIFO watermarks for DMA */ sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); /* setup msiof transfer mode registers (32-bit words) */ sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); sh_msiof_write(p, IER, ier_bits); reinit_completion(&p->done); if (rx) { desc_rx->callback = sh_msiof_dma_complete; desc_rx->callback_param = p; cookie = dmaengine_submit(desc_rx); if (dma_submit_error(cookie)) { ret = cookie; goto stop_ier; } dma_async_issue_pending(p->master->dma_rx); } if (tx) { if (rx) { /* No callback */ desc_tx->callback = NULL; } else { desc_tx->callback = sh_msiof_dma_complete; desc_tx->callback_param = p; } cookie = dmaengine_submit(desc_tx); if (dma_submit_error(cookie)) { ret = cookie; goto stop_rx; } dma_async_issue_pending(p->master->dma_tx); } ret = sh_msiof_spi_start(p, rx); if (ret) { dev_err(&p->pdev->dev, "failed to start hardware\n"); goto stop_tx; } /* wait for tx fifo to be emptied / rx fifo to be filled */ ret = wait_for_completion_timeout(&p->done, HZ); if (!ret) { dev_err(&p->pdev->dev, "DMA timeout\n"); ret = -ETIMEDOUT; goto stop_reset; } /* clear status bits */ sh_msiof_reset_str(p); ret = sh_msiof_spi_stop(p, rx); if (ret) { dev_err(&p->pdev->dev, "failed to shut down hardware\n"); return ret; } if (rx) dma_sync_single_for_cpu(p->master->dma_rx->device->dev, p->rx_dma_addr, len, DMA_FROM_DEVICE); return 0; stop_reset: sh_msiof_reset_str(p); sh_msiof_spi_stop(p, rx); stop_tx: if (tx) dmaengine_terminate_all(p->master->dma_tx); stop_rx: if (rx) dmaengine_terminate_all(p->master->dma_rx); stop_ier: sh_msiof_write(p, IER, 0); sh_msiof_write(p, IER, 0); return ret; return ret; } } static void copy_bswap32(u32 *dst, const u32 *src, unsigned int words) { /* src or dst can be unaligned, but not both */ if ((unsigned long)src & 3) { while (words--) { *dst++ = swab32(get_unaligned(src)); src++; } } else if ((unsigned long)dst & 3) { while (words--) { put_unaligned(swab32(*src++), dst); dst++; } } else { while (words--) *dst++ = swab32(*src++); } } static void copy_wswap32(u32 *dst, const u32 *src, unsigned int words) { /* src or dst can be unaligned, but not both */ if ((unsigned long)src & 3) { while (words--) { *dst++ = swahw32(get_unaligned(src)); src++; } } else if ((unsigned long)dst & 3) { while (words--) { put_unaligned(swahw32(*src++), dst); dst++; } } else { while (words--) *dst++ = swahw32(*src++); } } static void copy_plain32(u32 *dst, const u32 *src, unsigned int words) { memcpy(dst, src, words * 4); } static int sh_msiof_transfer_one(struct spi_master *master, static int sh_msiof_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_device *spi, struct spi_transfer *t) struct spi_transfer *t) { { struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); void (*copy32)(u32 *, const u32 *, unsigned int); void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int); void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int); void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int); void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int); int bits; const void *tx_buf = t->tx_buf; int bytes_per_word; void *rx_buf = t->rx_buf; int bytes_done; unsigned int len = t->len; int words; unsigned int bits = t->bits_per_word; unsigned int bytes_per_word; unsigned int words; int n; int n; bool swab; bool swab; int ret; /* setup clocks (clock already enabled in chipselect()) */ sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); while (master->dma_tx && len > 15) { /* * DMA supports 32-bit words only, hence pack 8-bit and 16-bit * words, with byte resp. word swapping. */ unsigned int l = min(len, MAX_WDLEN * 4); if (bits <= 8) { if (l & 3) break; copy32 = copy_bswap32; } else if (bits <= 16) { if (l & 1) break; copy32 = copy_wswap32; } else { copy32 = copy_plain32; } if (tx_buf) copy32(p->tx_dma_page, tx_buf, l / 4); ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l); if (ret == -EAGAIN) { pr_warn_once("%s %s: DMA not available, falling back to PIO\n", dev_driver_string(&p->pdev->dev), dev_name(&p->pdev->dev)); break; } if (ret) return ret; bits = t->bits_per_word; if (rx_buf) { copy32(rx_buf, p->rx_dma_page, l / 4); rx_buf += l; } if (tx_buf) tx_buf += l; if (bits <= 8 && t->len > 15 && !(t->len & 3)) { len -= l; if (!len) return 0; } if (bits <= 8 && len > 15 && !(len & 3)) { bits = 32; bits = 32; swab = true; swab = true; } else { } else { Loading @@ -556,57 +859,52 @@ static int sh_msiof_transfer_one(struct spi_master *master, rx_fifo = sh_msiof_spi_read_fifo_8; rx_fifo = sh_msiof_spi_read_fifo_8; } else if (bits <= 16) { } else if (bits <= 16) { bytes_per_word = 2; bytes_per_word = 2; if ((unsigned long)t->tx_buf & 0x01) if ((unsigned long)tx_buf & 0x01) tx_fifo = sh_msiof_spi_write_fifo_16u; tx_fifo = sh_msiof_spi_write_fifo_16u; else else tx_fifo = sh_msiof_spi_write_fifo_16; tx_fifo = sh_msiof_spi_write_fifo_16; if ((unsigned long)t->rx_buf & 0x01) if ((unsigned long)rx_buf & 0x01) rx_fifo = sh_msiof_spi_read_fifo_16u; rx_fifo = sh_msiof_spi_read_fifo_16u; else else rx_fifo = sh_msiof_spi_read_fifo_16; rx_fifo = sh_msiof_spi_read_fifo_16; } else if (swab) { } else if (swab) { bytes_per_word = 4; bytes_per_word = 4; if ((unsigned long)t->tx_buf & 0x03) if ((unsigned long)tx_buf & 0x03) tx_fifo = sh_msiof_spi_write_fifo_s32u; tx_fifo = sh_msiof_spi_write_fifo_s32u; else else tx_fifo = sh_msiof_spi_write_fifo_s32; tx_fifo = sh_msiof_spi_write_fifo_s32; if ((unsigned long)t->rx_buf & 0x03) if ((unsigned long)rx_buf & 0x03) rx_fifo = sh_msiof_spi_read_fifo_s32u; rx_fifo = sh_msiof_spi_read_fifo_s32u; else else rx_fifo = sh_msiof_spi_read_fifo_s32; rx_fifo = sh_msiof_spi_read_fifo_s32; } else { } else { bytes_per_word = 4; bytes_per_word = 4; if ((unsigned long)t->tx_buf & 0x03) if ((unsigned long)tx_buf & 0x03) tx_fifo = sh_msiof_spi_write_fifo_32u; tx_fifo = sh_msiof_spi_write_fifo_32u; else else tx_fifo = sh_msiof_spi_write_fifo_32; tx_fifo = sh_msiof_spi_write_fifo_32; if ((unsigned long)t->rx_buf & 0x03) if ((unsigned long)rx_buf & 0x03) rx_fifo = sh_msiof_spi_read_fifo_32u; rx_fifo = sh_msiof_spi_read_fifo_32u; else else rx_fifo = sh_msiof_spi_read_fifo_32; rx_fifo = sh_msiof_spi_read_fifo_32; } } /* setup clocks (clock already enabled in chipselect()) */ sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); /* transfer in fifo sized chunks */ /* transfer in fifo sized chunks */ words = t->len / bytes_per_word; words = len / bytes_per_word; bytes_done = 0; while (words > 0) { while (bytes_done < t->len) { n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo, tx_buf, rx_buf, void *rx_buf = t->rx_buf ? t->rx_buf + bytes_done : NULL; const void *tx_buf = t->tx_buf ? t->tx_buf + bytes_done : NULL; n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo, tx_buf, rx_buf, words, bits); words, bits); if (n < 0) if (n < 0) break; return n; bytes_done += n * bytes_per_word; if (tx_buf) tx_buf += n * bytes_per_word; if (rx_buf) rx_buf += n * bytes_per_word; words -= n; words -= n; } } Loading Loading @@ -663,6 +961,128 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) } } #endif #endif static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev, enum dma_transfer_direction dir, unsigned int id, dma_addr_t port_addr) { dma_cap_mask_t mask; struct dma_chan *chan; struct dma_slave_config cfg; int ret; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); chan = dma_request_channel(mask, shdma_chan_filter, (void *)(unsigned long)id); if (!chan) { dev_warn(dev, "dma_request_channel failed\n"); return NULL; } memset(&cfg, 0, sizeof(cfg)); cfg.slave_id = id; cfg.direction = dir; if (dir == DMA_MEM_TO_DEV) cfg.dst_addr = port_addr; else cfg.src_addr = port_addr; ret = dmaengine_slave_config(chan, &cfg); if (ret) { dev_warn(dev, "dmaengine_slave_config failed %d\n", ret); dma_release_channel(chan); return NULL; } return chan; } static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p) { struct platform_device *pdev = p->pdev; struct device *dev = &pdev->dev; const struct sh_msiof_spi_info *info = dev_get_platdata(dev); const struct resource *res; struct spi_master *master; struct device *tx_dev, *rx_dev; if (!info || !info->dma_tx_id || !info->dma_rx_id) return 0; /* The driver assumes no error */ /* The DMA engine uses the second register set, if present */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); master = p->master; master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV, info->dma_tx_id, res->start + TFDR); if (!master->dma_tx) return -ENODEV; master->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM, info->dma_rx_id, res->start + RFDR); if (!master->dma_rx) goto free_tx_chan; p->tx_dma_page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); if (!p->tx_dma_page) goto free_rx_chan; p->rx_dma_page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); if (!p->rx_dma_page) goto free_tx_page; tx_dev = master->dma_tx->device->dev; p->tx_dma_addr = dma_map_single(tx_dev, p->tx_dma_page, PAGE_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(tx_dev, p->tx_dma_addr)) goto free_rx_page; rx_dev = master->dma_rx->device->dev; p->rx_dma_addr = dma_map_single(rx_dev, p->rx_dma_page, PAGE_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(rx_dev, p->rx_dma_addr)) goto unmap_tx_page; dev_info(dev, "DMA available"); return 0; unmap_tx_page: dma_unmap_single(tx_dev, p->tx_dma_addr, PAGE_SIZE, DMA_TO_DEVICE); free_rx_page: free_page((unsigned long)p->rx_dma_page); free_tx_page: free_page((unsigned long)p->tx_dma_page); free_rx_chan: dma_release_channel(master->dma_rx); free_tx_chan: dma_release_channel(master->dma_tx); master->dma_tx = NULL; return -ENODEV; } static void sh_msiof_release_dma(struct sh_msiof_spi_priv *p) { struct spi_master *master = p->master; struct device *dev; if (!master->dma_tx) return; dev = &p->pdev->dev; dma_unmap_single(master->dma_rx->device->dev, p->rx_dma_addr, PAGE_SIZE, DMA_FROM_DEVICE); dma_unmap_single(master->dma_tx->device->dev, p->tx_dma_addr, PAGE_SIZE, DMA_TO_DEVICE); free_page((unsigned long)p->rx_dma_page); free_page((unsigned long)p->tx_dma_page); dma_release_channel(master->dma_rx); dma_release_channel(master->dma_tx); } static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_probe(struct platform_device *pdev) { { struct resource *r; struct resource *r; Loading @@ -680,6 +1100,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p = spi_master_get_devdata(master); p = spi_master_get_devdata(master); platform_set_drvdata(pdev, p); p->master = master; of_id = of_match_device(sh_msiof_match, &pdev->dev); of_id = of_match_device(sh_msiof_match, &pdev->dev); if (of_id) { if (of_id) { p->chipdata = of_id->data; p->chipdata = of_id->data; Loading Loading @@ -749,6 +1172,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; master->auto_runtime_pm = true; master->transfer_one = sh_msiof_transfer_one; master->transfer_one = sh_msiof_transfer_one; ret = sh_msiof_request_dma(p); if (ret < 0) dev_warn(&pdev->dev, "DMA not available, using PIO\n"); ret = devm_spi_register_master(&pdev->dev, master); ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); dev_err(&pdev->dev, "spi_register_master error.\n"); Loading @@ -758,6 +1185,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) return 0; return 0; err2: err2: sh_msiof_release_dma(p); pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev); err1: err1: spi_master_put(master); spi_master_put(master); Loading @@ -766,6 +1194,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) { { struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); sh_msiof_release_dma(p); pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; return 0; } } Loading
drivers/spi/spi-sh.c +6 −9 Original line number Original line Diff line number Diff line Loading @@ -432,7 +432,6 @@ static int spi_sh_remove(struct platform_device *pdev) spi_unregister_master(ss->master); spi_unregister_master(ss->master); destroy_workqueue(ss->workqueue); destroy_workqueue(ss->workqueue); free_irq(ss->irq, ss); free_irq(ss->irq, ss); iounmap(ss->addr); return 0; return 0; } } Loading Loading @@ -480,7 +479,7 @@ static int spi_sh_probe(struct platform_device *pdev) } } ss->irq = irq; ss->irq = irq; ss->master = master; ss->master = master; ss->addr = ioremap(res->start, resource_size(res)); ss->addr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (ss->addr == NULL) { if (ss->addr == NULL) { dev_err(&pdev->dev, "ioremap error.\n"); dev_err(&pdev->dev, "ioremap error.\n"); ret = -ENOMEM; ret = -ENOMEM; Loading @@ -495,13 +494,13 @@ static int spi_sh_probe(struct platform_device *pdev) if (ss->workqueue == NULL) { if (ss->workqueue == NULL) { dev_err(&pdev->dev, "create workqueue error\n"); dev_err(&pdev->dev, "create workqueue error\n"); ret = -EBUSY; ret = -EBUSY; goto error2; goto error1; } } ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss); ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss); if (ret < 0) { if (ret < 0) { dev_err(&pdev->dev, "request_irq error\n"); dev_err(&pdev->dev, "request_irq error\n"); goto error3; goto error2; } } master->num_chipselect = 2; master->num_chipselect = 2; Loading @@ -513,17 +512,15 @@ static int spi_sh_probe(struct platform_device *pdev) ret = spi_register_master(master); ret = spi_register_master(master); if (ret < 0) { if (ret < 0) { printk(KERN_ERR "spi_register_master error.\n"); printk(KERN_ERR "spi_register_master error.\n"); goto error4; goto error3; } } return 0; return 0; error4: free_irq(irq, ss); error3: error3: destroy_workqueue(ss->workqueue); free_irq(irq, ss); error2: error2: iounmap(ss->addr); destroy_workqueue(ss->workqueue); error1: error1: spi_master_put(master); spi_master_put(master); Loading
drivers/spi/spi-topcliff-pch.c +6 −6 Original line number Original line Diff line number Diff line Loading @@ -874,8 +874,8 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask); /* Get DMA's dev information */ /* Get DMA's dev information */ dma_dev = pci_get_bus_and_slot(data->board_dat->pdev->bus->number, dma_dev = pci_get_slot(data->board_dat->pdev->bus, PCI_DEVFN(12, 0)); PCI_DEVFN(PCI_SLOT(data->board_dat->pdev->devfn), 0)); /* Set Tx DMA */ /* Set Tx DMA */ param = &dma->param_tx; param = &dma->param_tx; Loading Loading @@ -1047,8 +1047,8 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) num, DMA_DEV_TO_MEM, num, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) { if (!desc_rx) { dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n", dev_err(&data->master->dev, __func__); "%s:dmaengine_prep_slave_sg Failed\n", __func__); return; return; } } dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_FROM_DEVICE); dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_FROM_DEVICE); Loading Loading @@ -1106,8 +1106,8 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) sg, num, DMA_MEM_TO_DEV, sg, num, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { if (!desc_tx) { dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n", dev_err(&data->master->dev, __func__); "%s:dmaengine_prep_slave_sg Failed\n", __func__); return; return; } } dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_TO_DEVICE); dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_TO_DEVICE); Loading
include/linux/spi/sh_msiof.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -5,6 +5,8 @@ struct sh_msiof_spi_info { int tx_fifo_override; int tx_fifo_override; int rx_fifo_override; int rx_fifo_override; u16 num_chipselect; u16 num_chipselect; unsigned int dma_tx_id; unsigned int dma_rx_id; }; }; #endif /* __SPI_SH_MSIOF_H__ */ #endif /* __SPI_SH_MSIOF_H__ */