diff options
| -rw-r--r-- | Documentation/devicetree/bindings/spi/spi-sun4i.txt | 24 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/spi/spi-sun6i.txt | 24 | ||||
| -rw-r--r-- | drivers/spi/Kconfig | 20 | ||||
| -rw-r--r-- | drivers/spi/Makefile | 3 | ||||
| -rw-r--r-- | drivers/spi/spi-sun4i.c | 478 | ||||
| -rw-r--r-- | drivers/spi/spi-sun6i.c | 484 | ||||
| -rw-r--r-- | drivers/spi/spi-tegra114.c | 4 | ||||
| -rw-r--r-- | drivers/spi/spi-ti-qspi.c | 1 | ||||
| -rw-r--r-- | drivers/spi/spi-ti-ssp.c | 378 | ||||
| -rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 47 | ||||
| -rw-r--r-- | drivers/spi/spi-txx9.c | 25 | ||||
| -rw-r--r-- | drivers/spi/spi-xcomm.c | 12 | ||||
| -rw-r--r-- | drivers/spi/spi.c | 12 |
13 files changed, 1053 insertions, 459 deletions
diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt new file mode 100644 index 000000000000..de827f5a301e --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sun4i.txt | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | Allwinner A10 SPI controller | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "allwinner,sun4-a10-spi". | ||
| 5 | - reg: Should contain register location and length. | ||
| 6 | - interrupts: Should contain interrupt. | ||
| 7 | - clocks: phandle to the clocks feeding the SPI controller. Two are | ||
| 8 | needed: | ||
| 9 | - "ahb": the gated AHB parent clock | ||
| 10 | - "mod": the parent module clock | ||
| 11 | - clock-names: Must contain the clock names described just above | ||
| 12 | |||
| 13 | Example: | ||
| 14 | |||
| 15 | spi1: spi@01c06000 { | ||
| 16 | compatible = "allwinner,sun4i-a10-spi"; | ||
| 17 | reg = <0x01c06000 0x1000>; | ||
| 18 | interrupts = <11>; | ||
| 19 | clocks = <&ahb_gates 21>, <&spi1_clk>; | ||
| 20 | clock-names = "ahb", "mod"; | ||
| 21 | status = "disabled"; | ||
| 22 | #address-cells = <1>; | ||
| 23 | #size-cells = <0>; | ||
| 24 | }; | ||
diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt new file mode 100644 index 000000000000..21de73db6a05 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sun6i.txt | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | Allwinner A31 SPI controller | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "allwinner,sun6i-a31-spi". | ||
| 5 | - reg: Should contain register location and length. | ||
| 6 | - interrupts: Should contain interrupt. | ||
| 7 | - clocks: phandle to the clocks feeding the SPI controller. Two are | ||
| 8 | needed: | ||
| 9 | - "ahb": the gated AHB parent clock | ||
| 10 | - "mod": the parent module clock | ||
| 11 | - clock-names: Must contain the clock names described just above | ||
| 12 | - resets: phandle to the reset controller asserting this device in | ||
| 13 | reset | ||
| 14 | |||
| 15 | Example: | ||
| 16 | |||
| 17 | spi1: spi@01c69000 { | ||
| 18 | compatible = "allwinner,sun6i-a31-spi"; | ||
| 19 | reg = <0x01c69000 0x1000>; | ||
| 20 | interrupts = <0 66 4>; | ||
| 21 | clocks = <&ahb1_gates 21>, <&spi1_clk>; | ||
| 22 | clock-names = "ahb", "mod"; | ||
| 23 | resets = <&ahb1_rst 21>; | ||
| 24 | }; | ||
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 2a1b0a7d9415..756b5b3ca200 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
| @@ -458,6 +458,19 @@ config SPI_SIRF | |||
| 458 | help | 458 | help |
| 459 | SPI driver for CSR SiRFprimaII SoCs | 459 | SPI driver for CSR SiRFprimaII SoCs |
| 460 | 460 | ||
| 461 | config SPI_SUN4I | ||
| 462 | tristate "Allwinner A10 SoCs SPI controller" | ||
| 463 | depends on ARCH_SUNXI || COMPILE_TEST | ||
| 464 | help | ||
| 465 | SPI driver for Allwinner sun4i, sun5i and sun7i SoCs | ||
| 466 | |||
| 467 | config SPI_SUN6I | ||
| 468 | tristate "Allwinner A31 SPI controller" | ||
| 469 | depends on ARCH_SUNXI || COMPILE_TEST | ||
| 470 | depends on RESET_CONTROLLER | ||
| 471 | help | ||
| 472 | This enables using the SPI controller on the Allwinner A31 SoCs. | ||
| 473 | |||
| 461 | config SPI_MXS | 474 | config SPI_MXS |
| 462 | tristate "Freescale MXS SPI controller" | 475 | tristate "Freescale MXS SPI controller" |
| 463 | depends on ARCH_MXS | 476 | depends on ARCH_MXS |
| @@ -490,13 +503,6 @@ config SPI_TEGRA20_SLINK | |||
| 490 | help | 503 | help |
| 491 | SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. | 504 | SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. |
| 492 | 505 | ||
| 493 | config SPI_TI_SSP | ||
| 494 | tristate "TI Sequencer Serial Port - SPI Support" | ||
| 495 | depends on MFD_TI_SSP | ||
| 496 | help | ||
| 497 | This selects an SPI master implementation using a TI sequencer | ||
| 498 | serial port. | ||
| 499 | |||
| 500 | config SPI_TOPCLIFF_PCH | 506 | config SPI_TOPCLIFF_PCH |
| 501 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" | 507 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" |
| 502 | depends on PCI | 508 | depends on PCI |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index e598147b06ef..e245b94d07d8 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
| @@ -71,10 +71,11 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o | |||
| 71 | obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o | 71 | obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o |
| 72 | obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o | 72 | obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o |
| 73 | obj-$(CONFIG_SPI_SIRF) += spi-sirf.o | 73 | obj-$(CONFIG_SPI_SIRF) += spi-sirf.o |
| 74 | obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o | ||
| 75 | obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o | ||
| 74 | obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o | 76 | obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o |
| 75 | obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o | 77 | obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o |
| 76 | obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o | 78 | obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o |
| 77 | obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o | ||
| 78 | obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o | 79 | obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o |
| 79 | obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o | 80 | obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o |
| 80 | obj-$(CONFIG_SPI_TXX9) += spi-txx9.o | 81 | obj-$(CONFIG_SPI_TXX9) += spi-txx9.o |
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c new file mode 100644 index 000000000000..d266a8702067 --- /dev/null +++ b/drivers/spi/spi-sun4i.c | |||
| @@ -0,0 +1,478 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 - 2014 Allwinner Tech | ||
| 3 | * Pan Nan <pannan@allwinnertech.com> | ||
| 4 | * | ||
| 5 | * Copyright (C) 2014 Maxime Ripard | ||
| 6 | * Maxime Ripard <maxime.ripard@free-electrons.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License as | ||
| 10 | * published by the Free Software Foundation; either version 2 of | ||
| 11 | * the License, or (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/clk.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/device.h> | ||
| 17 | #include <linux/interrupt.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/pm_runtime.h> | ||
| 22 | #include <linux/workqueue.h> | ||
| 23 | |||
| 24 | #include <linux/spi/spi.h> | ||
| 25 | |||
| 26 | #define SUN4I_FIFO_DEPTH 64 | ||
| 27 | |||
| 28 | #define SUN4I_RXDATA_REG 0x00 | ||
| 29 | |||
| 30 | #define SUN4I_TXDATA_REG 0x04 | ||
| 31 | |||
| 32 | #define SUN4I_CTL_REG 0x08 | ||
| 33 | #define SUN4I_CTL_ENABLE BIT(0) | ||
| 34 | #define SUN4I_CTL_MASTER BIT(1) | ||
| 35 | #define SUN4I_CTL_CPHA BIT(2) | ||
| 36 | #define SUN4I_CTL_CPOL BIT(3) | ||
| 37 | #define SUN4I_CTL_CS_ACTIVE_LOW BIT(4) | ||
| 38 | #define SUN4I_CTL_LMTF BIT(6) | ||
| 39 | #define SUN4I_CTL_TF_RST BIT(8) | ||
| 40 | #define SUN4I_CTL_RF_RST BIT(9) | ||
| 41 | #define SUN4I_CTL_XCH BIT(10) | ||
| 42 | #define SUN4I_CTL_CS_MASK 0x3000 | ||
| 43 | #define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK) | ||
| 44 | #define SUN4I_CTL_DHB BIT(15) | ||
| 45 | #define SUN4I_CTL_CS_MANUAL BIT(16) | ||
| 46 | #define SUN4I_CTL_CS_LEVEL BIT(17) | ||
| 47 | #define SUN4I_CTL_TP BIT(18) | ||
| 48 | |||
| 49 | #define SUN4I_INT_CTL_REG 0x0c | ||
| 50 | #define SUN4I_INT_CTL_TC BIT(16) | ||
| 51 | |||
| 52 | #define SUN4I_INT_STA_REG 0x10 | ||
| 53 | |||
| 54 | #define SUN4I_DMA_CTL_REG 0x14 | ||
| 55 | |||
| 56 | #define SUN4I_WAIT_REG 0x18 | ||
| 57 | |||
| 58 | #define SUN4I_CLK_CTL_REG 0x1c | ||
| 59 | #define SUN4I_CLK_CTL_CDR2_MASK 0xff | ||
| 60 | #define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK) | ||
| 61 | #define SUN4I_CLK_CTL_CDR1_MASK 0xf | ||
| 62 | #define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8) | ||
| 63 | #define SUN4I_CLK_CTL_DRS BIT(12) | ||
| 64 | |||
| 65 | #define SUN4I_BURST_CNT_REG 0x20 | ||
| 66 | #define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff) | ||
| 67 | |||
| 68 | #define SUN4I_XMIT_CNT_REG 0x24 | ||
| 69 | #define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff) | ||
| 70 | |||
| 71 | #define SUN4I_FIFO_STA_REG 0x28 | ||
| 72 | #define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f | ||
| 73 | #define SUN4I_FIFO_STA_RF_CNT_BITS 0 | ||
| 74 | #define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f | ||
| 75 | #define SUN4I_FIFO_STA_TF_CNT_BITS 16 | ||
| 76 | |||
| 77 | struct sun4i_spi { | ||
| 78 | struct spi_master *master; | ||
| 79 | void __iomem *base_addr; | ||
| 80 | struct clk *hclk; | ||
| 81 | struct clk *mclk; | ||
| 82 | |||
| 83 | struct completion done; | ||
| 84 | |||
| 85 | const u8 *tx_buf; | ||
| 86 | u8 *rx_buf; | ||
| 87 | int len; | ||
| 88 | }; | ||
| 89 | |||
| 90 | static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg) | ||
| 91 | { | ||
| 92 | return readl(sspi->base_addr + reg); | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value) | ||
| 96 | { | ||
| 97 | writel(value, sspi->base_addr + reg); | ||
| 98 | } | ||
| 99 | |||
| 100 | static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) | ||
| 101 | { | ||
| 102 | u32 reg, cnt; | ||
| 103 | u8 byte; | ||
| 104 | |||
| 105 | /* See how much data is available */ | ||
| 106 | reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG); | ||
| 107 | reg &= SUN4I_FIFO_STA_RF_CNT_MASK; | ||
| 108 | cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS; | ||
| 109 | |||
| 110 | if (len > cnt) | ||
| 111 | len = cnt; | ||
| 112 | |||
| 113 | while (len--) { | ||
| 114 | byte = readb(sspi->base_addr + SUN4I_RXDATA_REG); | ||
| 115 | if (sspi->rx_buf) | ||
| 116 | *sspi->rx_buf++ = byte; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) | ||
| 121 | { | ||
| 122 | u8 byte; | ||
| 123 | |||
| 124 | if (len > sspi->len) | ||
| 125 | len = sspi->len; | ||
| 126 | |||
| 127 | while (len--) { | ||
| 128 | byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; | ||
| 129 | writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG); | ||
| 130 | sspi->len--; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | static void sun4i_spi_set_cs(struct spi_device *spi, bool enable) | ||
| 135 | { | ||
| 136 | struct sun4i_spi *sspi = spi_master_get_devdata(spi->master); | ||
| 137 | u32 reg; | ||
| 138 | |||
| 139 | reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); | ||
| 140 | |||
| 141 | reg &= ~SUN4I_CTL_CS_MASK; | ||
| 142 | reg |= SUN4I_CTL_CS(spi->chip_select); | ||
| 143 | |||
| 144 | if (enable) | ||
| 145 | reg |= SUN4I_CTL_CS_LEVEL; | ||
| 146 | else | ||
| 147 | reg &= ~SUN4I_CTL_CS_LEVEL; | ||
| 148 | |||
| 149 | /* | ||
| 150 | * Even though this looks irrelevant since we are supposed to | ||
| 151 | * be controlling the chip select manually, this bit also | ||
| 152 | * controls the levels of the chip select for inactive | ||
| 153 | * devices. | ||
| 154 | * | ||
| 155 | * If we don't set it, the chip select level will go low by | ||
| 156 | * default when the device is idle, which is not really | ||
| 157 | * expected in the common case where the chip select is active | ||
| 158 | * low. | ||
| 159 | */ | ||
| 160 | if (spi->mode & SPI_CS_HIGH) | ||
| 161 | reg &= ~SUN4I_CTL_CS_ACTIVE_LOW; | ||
| 162 | else | ||
| 163 | reg |= SUN4I_CTL_CS_ACTIVE_LOW; | ||
| 164 | |||
| 165 | sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); | ||
| 166 | } | ||
| 167 | |||
| 168 | static int sun4i_spi_transfer_one(struct spi_master *master, | ||
| 169 | struct spi_device *spi, | ||
| 170 | struct spi_transfer *tfr) | ||
| 171 | { | ||
| 172 | struct sun4i_spi *sspi = spi_master_get_devdata(master); | ||
| 173 | unsigned int mclk_rate, div, timeout; | ||
| 174 | unsigned int tx_len = 0; | ||
| 175 | int ret = 0; | ||
| 176 | u32 reg; | ||
| 177 | |||
| 178 | /* We don't support transfer larger than the FIFO */ | ||
| 179 | if (tfr->len > SUN4I_FIFO_DEPTH) | ||
| 180 | return -EINVAL; | ||
| 181 | |||
| 182 | reinit_completion(&sspi->done); | ||
| 183 | sspi->tx_buf = tfr->tx_buf; | ||
| 184 | sspi->rx_buf = tfr->rx_buf; | ||
| 185 | sspi->len = tfr->len; | ||
| 186 | |||
| 187 | /* Clear pending interrupts */ | ||
| 188 | sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0); | ||
| 189 | |||
| 190 | |||
| 191 | reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); | ||
| 192 | |||
| 193 | /* Reset FIFOs */ | ||
| 194 | sun4i_spi_write(sspi, SUN4I_CTL_REG, | ||
| 195 | reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST); | ||
| 196 | |||
| 197 | /* | ||
| 198 | * Setup the transfer control register: Chip Select, | ||
| 199 | * polarities, etc. | ||
| 200 | */ | ||
| 201 | if (spi->mode & SPI_CPOL) | ||
| 202 | reg |= SUN4I_CTL_CPOL; | ||
| 203 | else | ||
| 204 | reg &= ~SUN4I_CTL_CPOL; | ||
| 205 | |||
| 206 | if (spi->mode & SPI_CPHA) | ||
| 207 | reg |= SUN4I_CTL_CPHA; | ||
| 208 | else | ||
| 209 | reg &= ~SUN4I_CTL_CPHA; | ||
| 210 | |||
| 211 | if (spi->mode & SPI_LSB_FIRST) | ||
| 212 | reg |= SUN4I_CTL_LMTF; | ||
| 213 | else | ||
| 214 | reg &= ~SUN4I_CTL_LMTF; | ||
| 215 | |||
| 216 | |||
| 217 | /* | ||
| 218 | * If it's a TX only transfer, we don't want to fill the RX | ||
| 219 | * FIFO with bogus data | ||
| 220 | */ | ||
| 221 | if (sspi->rx_buf) | ||
| 222 | reg &= ~SUN4I_CTL_DHB; | ||
| 223 | else | ||
| 224 | reg |= SUN4I_CTL_DHB; | ||
| 225 | |||
| 226 | /* We want to control the chip select manually */ | ||
| 227 | reg |= SUN4I_CTL_CS_MANUAL; | ||
| 228 | |||
| 229 | sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); | ||
| 230 | |||
| 231 | /* Ensure that we have a parent clock fast enough */ | ||
| 232 | mclk_rate = clk_get_rate(sspi->mclk); | ||
| 233 | if (mclk_rate < (2 * spi->max_speed_hz)) { | ||
| 234 | clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz); | ||
| 235 | mclk_rate = clk_get_rate(sspi->mclk); | ||
| 236 | } | ||
| 237 | |||
| 238 | /* | ||
| 239 | * Setup clock divider. | ||
| 240 | * | ||
| 241 | * We have two choices there. Either we can use the clock | ||
| 242 | * divide rate 1, which is calculated thanks to this formula: | ||
| 243 | * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1)) | ||
| 244 | * Or we can use CDR2, which is calculated with the formula: | ||
| 245 | * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) | ||
| 246 | * Wether we use the former or the latter is set through the | ||
| 247 | * DRS bit. | ||
| 248 | * | ||
| 249 | * First try CDR2, and if we can't reach the expected | ||
| 250 | * frequency, fall back to CDR1. | ||
| 251 | */ | ||
| 252 | div = mclk_rate / (2 * spi->max_speed_hz); | ||
| 253 | if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) { | ||
| 254 | if (div > 0) | ||
| 255 | div--; | ||
| 256 | |||
| 257 | reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS; | ||
| 258 | } else { | ||
| 259 | div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz); | ||
| 260 | reg = SUN4I_CLK_CTL_CDR1(div); | ||
| 261 | } | ||
| 262 | |||
| 263 | sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg); | ||
| 264 | |||
| 265 | /* Setup the transfer now... */ | ||
| 266 | if (sspi->tx_buf) | ||
| 267 | tx_len = tfr->len; | ||
| 268 | |||
| 269 | /* Setup the counters */ | ||
| 270 | sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len)); | ||
| 271 | sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len)); | ||
| 272 | |||
| 273 | /* Fill the TX FIFO */ | ||
| 274 | sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH); | ||
| 275 | |||
| 276 | /* Enable the interrupts */ | ||
| 277 | sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC); | ||
| 278 | |||
| 279 | /* Start the transfer */ | ||
| 280 | reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); | ||
| 281 | sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH); | ||
| 282 | |||
| 283 | timeout = wait_for_completion_timeout(&sspi->done, | ||
| 284 | msecs_to_jiffies(1000)); | ||
| 285 | if (!timeout) { | ||
| 286 | ret = -ETIMEDOUT; | ||
| 287 | goto out; | ||
| 288 | } | ||
| 289 | |||
| 290 | sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); | ||
| 291 | |||
| 292 | out: | ||
| 293 | sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0); | ||
| 294 | |||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | |||
| 298 | static irqreturn_t sun4i_spi_handler(int irq, void *dev_id) | ||
| 299 | { | ||
| 300 | struct sun4i_spi *sspi = dev_id; | ||
| 301 | u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG); | ||
| 302 | |||
| 303 | /* Transfer complete */ | ||
| 304 | if (status & SUN4I_INT_CTL_TC) { | ||
| 305 | sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC); | ||
| 306 | complete(&sspi->done); | ||
| 307 | return IRQ_HANDLED; | ||
| 308 | } | ||
| 309 | |||
| 310 | return IRQ_NONE; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int sun4i_spi_runtime_resume(struct device *dev) | ||
| 314 | { | ||
| 315 | struct spi_master *master = dev_get_drvdata(dev); | ||
| 316 | struct sun4i_spi *sspi = spi_master_get_devdata(master); | ||
| 317 | int ret; | ||
| 318 | |||
| 319 | ret = clk_prepare_enable(sspi->hclk); | ||
| 320 | if (ret) { | ||
| 321 | dev_err(dev, "Couldn't enable AHB clock\n"); | ||
| 322 | goto out; | ||
| 323 | } | ||
| 324 | |||
| 325 | ret = clk_prepare_enable(sspi->mclk); | ||
| 326 | if (ret) { | ||
| 327 | dev_err(dev, "Couldn't enable module clock\n"); | ||
| 328 | goto err; | ||
| 329 | } | ||
| 330 | |||
| 331 | sun4i_spi_write(sspi, SUN4I_CTL_REG, | ||
| 332 | SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP); | ||
| 333 | |||
| 334 | return 0; | ||
| 335 | |||
| 336 | err: | ||
| 337 | clk_disable_unprepare(sspi->hclk); | ||
| 338 | out: | ||
| 339 | return ret; | ||
| 340 | } | ||
| 341 | |||
| 342 | static int sun4i_spi_runtime_suspend(struct device *dev) | ||
| 343 | { | ||
| 344 | struct spi_master *master = dev_get_drvdata(dev); | ||
| 345 | struct sun4i_spi *sspi = spi_master_get_devdata(master); | ||
| 346 | |||
| 347 | clk_disable_unprepare(sspi->mclk); | ||
| 348 | clk_disable_unprepare(sspi->hclk); | ||
| 349 | |||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | static int sun4i_spi_probe(struct platform_device *pdev) | ||
| 354 | { | ||
| 355 | struct spi_master *master; | ||
| 356 | struct sun4i_spi *sspi; | ||
| 357 | struct resource *res; | ||
| 358 | int ret = 0, irq; | ||
| 359 | |||
| 360 | master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi)); | ||
| 361 | if (!master) { | ||
| 362 | dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); | ||
| 363 | return -ENOMEM; | ||
| 364 | } | ||
| 365 | |||
| 366 | platform_set_drvdata(pdev, master); | ||
| 367 | sspi = spi_master_get_devdata(master); | ||
| 368 | |||
| 369 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 370 | sspi->base_addr = devm_ioremap_resource(&pdev->dev, res); | ||
| 371 | if (IS_ERR(sspi->base_addr)) { | ||
| 372 | ret = PTR_ERR(sspi->base_addr); | ||
| 373 | goto err_free_master; | ||
| 374 | } | ||
| 375 | |||
| 376 | irq = platform_get_irq(pdev, 0); | ||
| 377 | if (irq < 0) { | ||
| 378 | dev_err(&pdev->dev, "No spi IRQ specified\n"); | ||
| 379 | ret = -ENXIO; | ||
| 380 | goto err_free_master; | ||
| 381 | } | ||
| 382 | |||
| 383 | ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler, | ||
| 384 | 0, "sun4i-spi", sspi); | ||
| 385 | if (ret) { | ||
| 386 | dev_err(&pdev->dev, "Cannot request IRQ\n"); | ||
| 387 | goto err_free_master; | ||
| 388 | } | ||
| 389 | |||
| 390 | sspi->master = master; | ||
| 391 | master->set_cs = sun4i_spi_set_cs; | ||
| 392 | master->transfer_one = sun4i_spi_transfer_one; | ||
| 393 | master->num_chipselect = 4; | ||
| 394 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; | ||
| 395 | master->bits_per_word_mask = SPI_BPW_MASK(8); | ||
| 396 | master->dev.of_node = pdev->dev.of_node; | ||
| 397 | master->auto_runtime_pm = true; | ||
| 398 | |||
| 399 | sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); | ||
| 400 | if (IS_ERR(sspi->hclk)) { | ||
| 401 | dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); | ||
| 402 | ret = PTR_ERR(sspi->hclk); | ||
| 403 | goto err_free_master; | ||
| 404 | } | ||
| 405 | |||
| 406 | sspi->mclk = devm_clk_get(&pdev->dev, "mod"); | ||
| 407 | if (IS_ERR(sspi->mclk)) { | ||
| 408 | dev_err(&pdev->dev, "Unable to acquire module clock\n"); | ||
| 409 | ret = PTR_ERR(sspi->mclk); | ||
| 410 | goto err_free_master; | ||
| 411 | } | ||
| 412 | |||
| 413 | init_completion(&sspi->done); | ||
| 414 | |||
| 415 | /* | ||
| 416 | * This wake-up/shutdown pattern is to be able to have the | ||
| 417 | * device woken up, even if runtime_pm is disabled | ||
| 418 | */ | ||
| 419 | ret = sun4i_spi_runtime_resume(&pdev->dev); | ||
| 420 | if (ret) { | ||
| 421 | dev_err(&pdev->dev, "Couldn't resume the device\n"); | ||
| 422 | goto err_free_master; | ||
| 423 | } | ||
| 424 | |||
| 425 | pm_runtime_set_active(&pdev->dev); | ||
| 426 | pm_runtime_enable(&pdev->dev); | ||
| 427 | pm_runtime_idle(&pdev->dev); | ||
| 428 | |||
| 429 | ret = devm_spi_register_master(&pdev->dev, master); | ||
| 430 | if (ret) { | ||
| 431 | dev_err(&pdev->dev, "cannot register SPI master\n"); | ||
| 432 | goto err_pm_disable; | ||
| 433 | } | ||
| 434 | |||
| 435 | return 0; | ||
| 436 | |||
| 437 | err_pm_disable: | ||
| 438 | pm_runtime_disable(&pdev->dev); | ||
| 439 | sun4i_spi_runtime_suspend(&pdev->dev); | ||
| 440 | err_free_master: | ||
| 441 | spi_master_put(master); | ||
| 442 | return ret; | ||
| 443 | } | ||
| 444 | |||
| 445 | static int sun4i_spi_remove(struct platform_device *pdev) | ||
| 446 | { | ||
| 447 | pm_runtime_disable(&pdev->dev); | ||
| 448 | |||
| 449 | return 0; | ||
| 450 | } | ||
| 451 | |||
| 452 | static const struct of_device_id sun4i_spi_match[] = { | ||
| 453 | { .compatible = "allwinner,sun4i-a10-spi", }, | ||
| 454 | {} | ||
| 455 | }; | ||
| 456 | MODULE_DEVICE_TABLE(of, sun4i_spi_match); | ||
| 457 | |||
| 458 | static const struct dev_pm_ops sun4i_spi_pm_ops = { | ||
| 459 | .runtime_resume = sun4i_spi_runtime_resume, | ||
| 460 | .runtime_suspend = sun4i_spi_runtime_suspend, | ||
| 461 | }; | ||
| 462 | |||
| 463 | static struct platform_driver sun4i_spi_driver = { | ||
| 464 | .probe = sun4i_spi_probe, | ||
| 465 | .remove = sun4i_spi_remove, | ||
| 466 | .driver = { | ||
| 467 | .name = "sun4i-spi", | ||
| 468 | .owner = THIS_MODULE, | ||
| 469 | .of_match_table = sun4i_spi_match, | ||
| 470 | .pm = &sun4i_spi_pm_ops, | ||
| 471 | }, | ||
| 472 | }; | ||
| 473 | module_platform_driver(sun4i_spi_driver); | ||
| 474 | |||
| 475 | MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>"); | ||
| 476 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||
| 477 | MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver"); | ||
| 478 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c new file mode 100644 index 000000000000..b3e3498a7e6f --- /dev/null +++ b/drivers/spi/spi-sun6i.c | |||
| @@ -0,0 +1,484 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 - 2014 Allwinner Tech | ||
| 3 | * Pan Nan <pannan@allwinnertech.com> | ||
| 4 | * | ||
| 5 | * Copyright (C) 2014 Maxime Ripard | ||
| 6 | * Maxime Ripard <maxime.ripard@free-electrons.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License as | ||
| 10 | * published by the Free Software Foundation; either version 2 of | ||
| 11 | * the License, or (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/clk.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/device.h> | ||
| 17 | #include <linux/interrupt.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/pm_runtime.h> | ||
| 22 | #include <linux/reset.h> | ||
| 23 | #include <linux/workqueue.h> | ||
| 24 | |||
| 25 | #include <linux/spi/spi.h> | ||
| 26 | |||
| 27 | #define SUN6I_FIFO_DEPTH 128 | ||
| 28 | |||
| 29 | #define SUN6I_GBL_CTL_REG 0x04 | ||
| 30 | #define SUN6I_GBL_CTL_BUS_ENABLE BIT(0) | ||
| 31 | #define SUN6I_GBL_CTL_MASTER BIT(1) | ||
| 32 | #define SUN6I_GBL_CTL_TP BIT(7) | ||
| 33 | #define SUN6I_GBL_CTL_RST BIT(31) | ||
| 34 | |||
| 35 | #define SUN6I_TFR_CTL_REG 0x08 | ||
| 36 | #define SUN6I_TFR_CTL_CPHA BIT(0) | ||
| 37 | #define SUN6I_TFR_CTL_CPOL BIT(1) | ||
| 38 | #define SUN6I_TFR_CTL_SPOL BIT(2) | ||
| 39 | #define SUN6I_TFR_CTL_CS_MASK 0x30 | ||
| 40 | #define SUN6I_TFR_CTL_CS(cs) (((cs) << 4) & SUN6I_TFR_CTL_CS_MASK) | ||
| 41 | #define SUN6I_TFR_CTL_CS_MANUAL BIT(6) | ||
| 42 | #define SUN6I_TFR_CTL_CS_LEVEL BIT(7) | ||
| 43 | #define SUN6I_TFR_CTL_DHB BIT(8) | ||
| 44 | #define SUN6I_TFR_CTL_FBS BIT(12) | ||
| 45 | #define SUN6I_TFR_CTL_XCH BIT(31) | ||
| 46 | |||
| 47 | #define SUN6I_INT_CTL_REG 0x10 | ||
| 48 | #define SUN6I_INT_CTL_RF_OVF BIT(8) | ||
| 49 | #define SUN6I_INT_CTL_TC BIT(12) | ||
| 50 | |||
| 51 | #define SUN6I_INT_STA_REG 0x14 | ||
| 52 | |||
| 53 | #define SUN6I_FIFO_CTL_REG 0x18 | ||
| 54 | #define SUN6I_FIFO_CTL_RF_RST BIT(15) | ||
| 55 | #define SUN6I_FIFO_CTL_TF_RST BIT(31) | ||
| 56 | |||
| 57 | #define SUN6I_FIFO_STA_REG 0x1c | ||
| 58 | #define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f | ||
| 59 | #define SUN6I_FIFO_STA_RF_CNT_BITS 0 | ||
| 60 | #define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f | ||
| 61 | #define SUN6I_FIFO_STA_TF_CNT_BITS 16 | ||
| 62 | |||
| 63 | #define SUN6I_CLK_CTL_REG 0x24 | ||
| 64 | #define SUN6I_CLK_CTL_CDR2_MASK 0xff | ||
| 65 | #define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0) | ||
| 66 | #define SUN6I_CLK_CTL_CDR1_MASK 0xf | ||
| 67 | #define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8) | ||
| 68 | #define SUN6I_CLK_CTL_DRS BIT(12) | ||
| 69 | |||
| 70 | #define SUN6I_BURST_CNT_REG 0x30 | ||
| 71 | #define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff) | ||
| 72 | |||
| 73 | #define SUN6I_XMIT_CNT_REG 0x34 | ||
| 74 | #define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff) | ||
| 75 | |||
| 76 | #define SUN6I_BURST_CTL_CNT_REG 0x38 | ||
| 77 | #define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff) | ||
| 78 | |||
| 79 | #define SUN6I_TXDATA_REG 0x200 | ||
| 80 | #define SUN6I_RXDATA_REG 0x300 | ||
| 81 | |||
| 82 | struct sun6i_spi { | ||
| 83 | struct spi_master *master; | ||
| 84 | void __iomem *base_addr; | ||
| 85 | struct clk *hclk; | ||
| 86 | struct clk *mclk; | ||
| 87 | struct reset_control *rstc; | ||
| 88 | |||
| 89 | struct completion done; | ||
| 90 | |||
| 91 | const u8 *tx_buf; | ||
| 92 | u8 *rx_buf; | ||
| 93 | int len; | ||
| 94 | }; | ||
| 95 | |||
| 96 | static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg) | ||
| 97 | { | ||
| 98 | return readl(sspi->base_addr + reg); | ||
| 99 | } | ||
| 100 | |||
| 101 | static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value) | ||
| 102 | { | ||
| 103 | writel(value, sspi->base_addr + reg); | ||
| 104 | } | ||
| 105 | |||
| 106 | static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len) | ||
| 107 | { | ||
| 108 | u32 reg, cnt; | ||
| 109 | u8 byte; | ||
| 110 | |||
| 111 | /* See how much data is available */ | ||
| 112 | reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG); | ||
| 113 | reg &= SUN6I_FIFO_STA_RF_CNT_MASK; | ||
| 114 | cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS; | ||
| 115 | |||
| 116 | if (len > cnt) | ||
| 117 | len = cnt; | ||
| 118 | |||
| 119 | while (len--) { | ||
| 120 | byte = readb(sspi->base_addr + SUN6I_RXDATA_REG); | ||
| 121 | if (sspi->rx_buf) | ||
| 122 | *sspi->rx_buf++ = byte; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len) | ||
| 127 | { | ||
| 128 | u8 byte; | ||
| 129 | |||
| 130 | if (len > sspi->len) | ||
| 131 | len = sspi->len; | ||
| 132 | |||
| 133 | while (len--) { | ||
| 134 | byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; | ||
| 135 | writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG); | ||
| 136 | sspi->len--; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | static void sun6i_spi_set_cs(struct spi_device *spi, bool enable) | ||
| 141 | { | ||
| 142 | struct sun6i_spi *sspi = spi_master_get_devdata(spi->master); | ||
| 143 | u32 reg; | ||
| 144 | |||
| 145 | reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); | ||
| 146 | reg &= ~SUN6I_TFR_CTL_CS_MASK; | ||
| 147 | reg |= SUN6I_TFR_CTL_CS(spi->chip_select); | ||
| 148 | |||
| 149 | if (enable) | ||
| 150 | reg |= SUN6I_TFR_CTL_CS_LEVEL; | ||
| 151 | else | ||
| 152 | reg &= ~SUN6I_TFR_CTL_CS_LEVEL; | ||
| 153 | |||
| 154 | sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | static int sun6i_spi_transfer_one(struct spi_master *master, | ||
| 159 | struct spi_device *spi, | ||
| 160 | struct spi_transfer *tfr) | ||
| 161 | { | ||
| 162 | struct sun6i_spi *sspi = spi_master_get_devdata(master); | ||
| 163 | unsigned int mclk_rate, div, timeout; | ||
| 164 | unsigned int tx_len = 0; | ||
| 165 | int ret = 0; | ||
| 166 | u32 reg; | ||
| 167 | |||
| 168 | /* We don't support transfer larger than the FIFO */ | ||
| 169 | if (tfr->len > SUN6I_FIFO_DEPTH) | ||
| 170 | return -EINVAL; | ||
| 171 | |||
| 172 | reinit_completion(&sspi->done); | ||
| 173 | sspi->tx_buf = tfr->tx_buf; | ||
| 174 | sspi->rx_buf = tfr->rx_buf; | ||
| 175 | sspi->len = tfr->len; | ||
| 176 | |||
| 177 | /* Clear pending interrupts */ | ||
| 178 | sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0); | ||
| 179 | |||
| 180 | /* Reset FIFO */ | ||
| 181 | sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, | ||
| 182 | SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST); | ||
| 183 | |||
| 184 | /* | ||
| 185 | * Setup the transfer control register: Chip Select, | ||
| 186 | * polarities, etc. | ||
| 187 | */ | ||
| 188 | reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); | ||
| 189 | |||
| 190 | if (spi->mode & SPI_CPOL) | ||
| 191 | reg |= SUN6I_TFR_CTL_CPOL; | ||
| 192 | else | ||
| 193 | reg &= ~SUN6I_TFR_CTL_CPOL; | ||
| 194 | |||
| 195 | if (spi->mode & SPI_CPHA) | ||
| 196 | reg |= SUN6I_TFR_CTL_CPHA; | ||
| 197 | else | ||
| 198 | reg &= ~SUN6I_TFR_CTL_CPHA; | ||
| 199 | |||
| 200 | if (spi->mode & SPI_LSB_FIRST) | ||
| 201 | reg |= SUN6I_TFR_CTL_FBS; | ||
| 202 | else | ||
| 203 | reg &= ~SUN6I_TFR_CTL_FBS; | ||
| 204 | |||
| 205 | /* | ||
| 206 | * If it's a TX only transfer, we don't want to fill the RX | ||
| 207 | * FIFO with bogus data | ||
| 208 | */ | ||
| 209 | if (sspi->rx_buf) | ||
| 210 | reg &= ~SUN6I_TFR_CTL_DHB; | ||
| 211 | else | ||
| 212 | reg |= SUN6I_TFR_CTL_DHB; | ||
| 213 | |||
| 214 | /* We want to control the chip select manually */ | ||
| 215 | reg |= SUN6I_TFR_CTL_CS_MANUAL; | ||
| 216 | |||
| 217 | sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); | ||
| 218 | |||
| 219 | /* Ensure that we have a parent clock fast enough */ | ||
| 220 | mclk_rate = clk_get_rate(sspi->mclk); | ||
| 221 | if (mclk_rate < (2 * spi->max_speed_hz)) { | ||
| 222 | clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz); | ||
| 223 | mclk_rate = clk_get_rate(sspi->mclk); | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * Setup clock divider. | ||
| 228 | * | ||
| 229 | * We have two choices there. Either we can use the clock | ||
| 230 | * divide rate 1, which is calculated thanks to this formula: | ||
| 231 | * SPI_CLK = MOD_CLK / (2 ^ cdr) | ||
| 232 | * Or we can use CDR2, which is calculated with the formula: | ||
| 233 | * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) | ||
| 234 | * Wether we use the former or the latter is set through the | ||
| 235 | * DRS bit. | ||
| 236 | * | ||
| 237 | * First try CDR2, and if we can't reach the expected | ||
| 238 | * frequency, fall back to CDR1. | ||
| 239 | */ | ||
| 240 | div = mclk_rate / (2 * spi->max_speed_hz); | ||
| 241 | if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) { | ||
| 242 | if (div > 0) | ||
| 243 | div--; | ||
| 244 | |||
| 245 | reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS; | ||
| 246 | } else { | ||
| 247 | div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz); | ||
| 248 | reg = SUN6I_CLK_CTL_CDR1(div); | ||
| 249 | } | ||
| 250 | |||
| 251 | sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg); | ||
| 252 | |||
| 253 | /* Setup the transfer now... */ | ||
| 254 | if (sspi->tx_buf) | ||
| 255 | tx_len = tfr->len; | ||
| 256 | |||
| 257 | /* Setup the counters */ | ||
| 258 | sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len)); | ||
| 259 | sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len)); | ||
| 260 | sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, | ||
| 261 | SUN6I_BURST_CTL_CNT_STC(tx_len)); | ||
| 262 | |||
| 263 | /* Fill the TX FIFO */ | ||
| 264 | sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH); | ||
| 265 | |||
| 266 | /* Enable the interrupts */ | ||
| 267 | sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC); | ||
| 268 | |||
| 269 | /* Start the transfer */ | ||
| 270 | reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); | ||
| 271 | sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH); | ||
| 272 | |||
| 273 | timeout = wait_for_completion_timeout(&sspi->done, | ||
| 274 | msecs_to_jiffies(1000)); | ||
| 275 | if (!timeout) { | ||
| 276 | ret = -ETIMEDOUT; | ||
| 277 | goto out; | ||
| 278 | } | ||
| 279 | |||
| 280 | sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH); | ||
| 281 | |||
| 282 | out: | ||
| 283 | sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); | ||
| 284 | |||
| 285 | return ret; | ||
| 286 | } | ||
| 287 | |||
| 288 | static irqreturn_t sun6i_spi_handler(int irq, void *dev_id) | ||
| 289 | { | ||
| 290 | struct sun6i_spi *sspi = dev_id; | ||
| 291 | u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG); | ||
| 292 | |||
| 293 | /* Transfer complete */ | ||
| 294 | if (status & SUN6I_INT_CTL_TC) { | ||
| 295 | sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC); | ||
| 296 | complete(&sspi->done); | ||
| 297 | return IRQ_HANDLED; | ||
| 298 | } | ||
| 299 | |||
| 300 | return IRQ_NONE; | ||
| 301 | } | ||
| 302 | |||
| 303 | static int sun6i_spi_runtime_resume(struct device *dev) | ||
| 304 | { | ||
| 305 | struct spi_master *master = dev_get_drvdata(dev); | ||
| 306 | struct sun6i_spi *sspi = spi_master_get_devdata(master); | ||
| 307 | int ret; | ||
| 308 | |||
| 309 | ret = clk_prepare_enable(sspi->hclk); | ||
| 310 | if (ret) { | ||
| 311 | dev_err(dev, "Couldn't enable AHB clock\n"); | ||
| 312 | goto out; | ||
| 313 | } | ||
| 314 | |||
| 315 | ret = clk_prepare_enable(sspi->mclk); | ||
| 316 | if (ret) { | ||
| 317 | dev_err(dev, "Couldn't enable module clock\n"); | ||
| 318 | goto err; | ||
| 319 | } | ||
| 320 | |||
| 321 | ret = reset_control_deassert(sspi->rstc); | ||
| 322 | if (ret) { | ||
| 323 | dev_err(dev, "Couldn't deassert the device from reset\n"); | ||
| 324 | goto err2; | ||
| 325 | } | ||
| 326 | |||
| 327 | sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, | ||
| 328 | SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP); | ||
| 329 | |||
| 330 | return 0; | ||
| 331 | |||
| 332 | err2: | ||
| 333 | clk_disable_unprepare(sspi->mclk); | ||
| 334 | err: | ||
| 335 | clk_disable_unprepare(sspi->hclk); | ||
| 336 | out: | ||
| 337 | return ret; | ||
| 338 | } | ||
| 339 | |||
| 340 | static int sun6i_spi_runtime_suspend(struct device *dev) | ||
| 341 | { | ||
| 342 | struct spi_master *master = dev_get_drvdata(dev); | ||
| 343 | struct sun6i_spi *sspi = spi_master_get_devdata(master); | ||
| 344 | |||
| 345 | reset_control_assert(sspi->rstc); | ||
| 346 | clk_disable_unprepare(sspi->mclk); | ||
| 347 | clk_disable_unprepare(sspi->hclk); | ||
| 348 | |||
| 349 | return 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | static int sun6i_spi_probe(struct platform_device *pdev) | ||
| 353 | { | ||
| 354 | struct spi_master *master; | ||
| 355 | struct sun6i_spi *sspi; | ||
| 356 | struct resource *res; | ||
| 357 | int ret = 0, irq; | ||
| 358 | |||
| 359 | master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi)); | ||
| 360 | if (!master) { | ||
| 361 | dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); | ||
| 362 | return -ENOMEM; | ||
| 363 | } | ||
| 364 | |||
| 365 | platform_set_drvdata(pdev, master); | ||
| 366 | sspi = spi_master_get_devdata(master); | ||
| 367 | |||
| 368 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 369 | sspi->base_addr = devm_ioremap_resource(&pdev->dev, res); | ||
| 370 | if (IS_ERR(sspi->base_addr)) { | ||
| 371 | ret = PTR_ERR(sspi->base_addr); | ||
| 372 | goto err_free_master; | ||
| 373 | } | ||
| 374 | |||
| 375 | irq = platform_get_irq(pdev, 0); | ||
| 376 | if (irq < 0) { | ||
| 377 | dev_err(&pdev->dev, "No spi IRQ specified\n"); | ||
| 378 | ret = -ENXIO; | ||
| 379 | goto err_free_master; | ||
| 380 | } | ||
| 381 | |||
| 382 | ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler, | ||
| 383 | 0, "sun6i-spi", sspi); | ||
| 384 | if (ret) { | ||
| 385 | dev_err(&pdev->dev, "Cannot request IRQ\n"); | ||
| 386 | goto err_free_master; | ||
| 387 | } | ||
| 388 | |||
| 389 | sspi->master = master; | ||
| 390 | master->set_cs = sun6i_spi_set_cs; | ||
| 391 | master->transfer_one = sun6i_spi_transfer_one; | ||
| 392 | master->num_chipselect = 4; | ||
| 393 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; | ||
| 394 | master->bits_per_word_mask = SPI_BPW_MASK(8); | ||
| 395 | master->dev.of_node = pdev->dev.of_node; | ||
| 396 | master->auto_runtime_pm = true; | ||
| 397 | |||
| 398 | sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); | ||
| 399 | if (IS_ERR(sspi->hclk)) { | ||
| 400 | dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); | ||
| 401 | ret = PTR_ERR(sspi->hclk); | ||
| 402 | goto err_free_master; | ||
| 403 | } | ||
| 404 | |||
| 405 | sspi->mclk = devm_clk_get(&pdev->dev, "mod"); | ||
| 406 | if (IS_ERR(sspi->mclk)) { | ||
| 407 | dev_err(&pdev->dev, "Unable to acquire module clock\n"); | ||
| 408 | ret = PTR_ERR(sspi->mclk); | ||
| 409 | goto err_free_master; | ||
| 410 | } | ||
| 411 | |||
| 412 | init_completion(&sspi->done); | ||
| 413 | |||
| 414 | sspi->rstc = devm_reset_control_get(&pdev->dev, NULL); | ||
| 415 | if (IS_ERR(sspi->rstc)) { | ||
| 416 | dev_err(&pdev->dev, "Couldn't get reset controller\n"); | ||
| 417 | ret = PTR_ERR(sspi->rstc); | ||
| 418 | goto err_free_master; | ||
| 419 | } | ||
| 420 | |||
| 421 | /* | ||
| 422 | * This wake-up/shutdown pattern is to be able to have the | ||
| 423 | * device woken up, even if runtime_pm is disabled | ||
| 424 | */ | ||
| 425 | ret = sun6i_spi_runtime_resume(&pdev->dev); | ||
| 426 | if (ret) { | ||
| 427 | dev_err(&pdev->dev, "Couldn't resume the device\n"); | ||
| 428 | goto err_free_master; | ||
| 429 | } | ||
| 430 | |||
| 431 | pm_runtime_set_active(&pdev->dev); | ||
| 432 | pm_runtime_enable(&pdev->dev); | ||
| 433 | pm_runtime_idle(&pdev->dev); | ||
| 434 | |||
| 435 | ret = devm_spi_register_master(&pdev->dev, master); | ||
| 436 | if (ret) { | ||
| 437 | dev_err(&pdev->dev, "cannot register SPI master\n"); | ||
| 438 | goto err_pm_disable; | ||
| 439 | } | ||
| 440 | |||
| 441 | return 0; | ||
| 442 | |||
| 443 | err_pm_disable: | ||
| 444 | pm_runtime_disable(&pdev->dev); | ||
| 445 | sun6i_spi_runtime_suspend(&pdev->dev); | ||
| 446 | err_free_master: | ||
| 447 | spi_master_put(master); | ||
| 448 | return ret; | ||
| 449 | } | ||
| 450 | |||
| 451 | static int sun6i_spi_remove(struct platform_device *pdev) | ||
| 452 | { | ||
| 453 | pm_runtime_disable(&pdev->dev); | ||
| 454 | |||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | static const struct of_device_id sun6i_spi_match[] = { | ||
| 459 | { .compatible = "allwinner,sun6i-a31-spi", }, | ||
| 460 | {} | ||
| 461 | }; | ||
| 462 | MODULE_DEVICE_TABLE(of, sun6i_spi_match); | ||
| 463 | |||
| 464 | static const struct dev_pm_ops sun6i_spi_pm_ops = { | ||
| 465 | .runtime_resume = sun6i_spi_runtime_resume, | ||
| 466 | .runtime_suspend = sun6i_spi_runtime_suspend, | ||
| 467 | }; | ||
| 468 | |||
| 469 | static struct platform_driver sun6i_spi_driver = { | ||
| 470 | .probe = sun6i_spi_probe, | ||
| 471 | .remove = sun6i_spi_remove, | ||
| 472 | .driver = { | ||
| 473 | .name = "sun6i-spi", | ||
| 474 | .owner = THIS_MODULE, | ||
| 475 | .of_match_table = sun6i_spi_match, | ||
| 476 | .pm = &sun6i_spi_pm_ops, | ||
| 477 | }, | ||
| 478 | }; | ||
| 479 | module_platform_driver(sun6i_spi_driver); | ||
| 480 | |||
| 481 | MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>"); | ||
| 482 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||
| 483 | MODULE_DESCRIPTION("Allwinner A31 SPI controller driver"); | ||
| 484 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 6be661e4c6e1..400649595505 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c | |||
| @@ -846,8 +846,8 @@ complete_xfer: | |||
| 846 | SPI_COMMAND1); | 846 | SPI_COMMAND1); |
| 847 | tegra_spi_transfer_delay(xfer->delay_usecs); | 847 | tegra_spi_transfer_delay(xfer->delay_usecs); |
| 848 | goto exit; | 848 | goto exit; |
| 849 | } else if (msg->transfers.prev == &xfer->transfer_list) { | 849 | } else if (list_is_last(&xfer->transfer_list, |
| 850 | /* This is the last transfer in message */ | 850 | &msg->transfers)) { |
| 851 | if (xfer->cs_change) | 851 | if (xfer->cs_change) |
| 852 | tspi->cs_control = spi; | 852 | tspi->cs_control = spi; |
| 853 | else { | 853 | else { |
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 49ddfc7f12b1..6c211d1910b0 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c | |||
| @@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev) | |||
| 461 | if (res_mmap == NULL) { | 461 | if (res_mmap == NULL) { |
| 462 | dev_err(&pdev->dev, | 462 | dev_err(&pdev->dev, |
| 463 | "memory mapped resource not required\n"); | 463 | "memory mapped resource not required\n"); |
| 464 | return -ENODEV; | ||
| 465 | } | 464 | } |
| 466 | } | 465 | } |
| 467 | 466 | ||
diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c deleted file mode 100644 index 7d20e121e4c1..000000000000 --- a/drivers/spi/spi-ti-ssp.c +++ /dev/null | |||
| @@ -1,378 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Sequencer Serial Port (SSP) based SPI master driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Texas Instruments Inc | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/err.h> | ||
| 23 | #include <linux/completion.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | #include <linux/spi/spi.h> | ||
| 28 | #include <linux/mfd/ti_ssp.h> | ||
| 29 | |||
| 30 | #define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH) | ||
| 31 | |||
| 32 | struct ti_ssp_spi { | ||
| 33 | struct spi_master *master; | ||
| 34 | struct device *dev; | ||
| 35 | spinlock_t lock; | ||
| 36 | struct list_head msg_queue; | ||
| 37 | struct completion complete; | ||
| 38 | bool shutdown; | ||
| 39 | struct workqueue_struct *workqueue; | ||
| 40 | struct work_struct work; | ||
| 41 | u8 mode, bpw; | ||
| 42 | int cs_active; | ||
| 43 | u32 pc_en, pc_dis, pc_wr, pc_rd; | ||
| 44 | void (*select)(int cs); | ||
| 45 | }; | ||
| 46 | |||
| 47 | static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw) | ||
| 48 | { | ||
| 49 | u32 ret; | ||
| 50 | |||
| 51 | ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret); | ||
| 52 | return ret; | ||
| 53 | } | ||
| 54 | |||
| 55 | static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data) | ||
| 56 | { | ||
| 57 | ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL); | ||
| 58 | } | ||
| 59 | |||
| 60 | static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg, | ||
| 61 | struct spi_transfer *t) | ||
| 62 | { | ||
| 63 | int count; | ||
| 64 | |||
| 65 | if (hw->bpw <= 8) { | ||
| 66 | u8 *rx = t->rx_buf; | ||
| 67 | const u8 *tx = t->tx_buf; | ||
| 68 | |||
| 69 | for (count = 0; count < t->len; count += 1) { | ||
| 70 | if (t->tx_buf) | ||
| 71 | ti_ssp_spi_tx(hw, *tx++); | ||
| 72 | if (t->rx_buf) | ||
| 73 | *rx++ = ti_ssp_spi_rx(hw); | ||
| 74 | } | ||
| 75 | } else if (hw->bpw <= 16) { | ||
| 76 | u16 *rx = t->rx_buf; | ||
| 77 | const u16 *tx = t->tx_buf; | ||
| 78 | |||
| 79 | for (count = 0; count < t->len; count += 2) { | ||
| 80 | if (t->tx_buf) | ||
| 81 | ti_ssp_spi_tx(hw, *tx++); | ||
| 82 | if (t->rx_buf) | ||
| 83 | *rx++ = ti_ssp_spi_rx(hw); | ||
| 84 | } | ||
| 85 | } else { | ||
| 86 | u32 *rx = t->rx_buf; | ||
| 87 | const u32 *tx = t->tx_buf; | ||
| 88 | |||
| 89 | for (count = 0; count < t->len; count += 4) { | ||
| 90 | if (t->tx_buf) | ||
| 91 | ti_ssp_spi_tx(hw, *tx++); | ||
| 92 | if (t->rx_buf) | ||
| 93 | *rx++ = ti_ssp_spi_rx(hw); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | msg->actual_length += count; /* bytes transferred */ | ||
| 98 | |||
| 99 | dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n", | ||
| 100 | t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len, | ||
| 101 | hw->bpw, count, (count < t->len) ? " (under)" : ""); | ||
| 102 | |||
| 103 | return (count < t->len) ? -EIO : 0; /* left over data */ | ||
| 104 | } | ||
| 105 | |||
| 106 | static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active) | ||
| 107 | { | ||
| 108 | cs_active = !!cs_active; | ||
| 109 | if (cs_active == hw->cs_active) | ||
| 110 | return; | ||
| 111 | ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL); | ||
| 112 | hw->cs_active = cs_active; | ||
| 113 | } | ||
| 114 | |||
| 115 | #define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \ | ||
| 116 | cs_en | clk | SSP_COUNT((bits) * 2 - 1)) | ||
| 117 | #define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \ | ||
| 118 | cs_en | clk | SSP_COUNT((bits) * 2 - 1)) | ||
| 119 | |||
| 120 | static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode) | ||
| 121 | { | ||
| 122 | int error, idx = 0; | ||
| 123 | u32 seqram[16]; | ||
| 124 | u32 cs_en, cs_dis, clk; | ||
| 125 | u32 topbits, botbits; | ||
| 126 | |||
| 127 | mode &= MODE_BITS; | ||
| 128 | if (mode == hw->mode && bpw == hw->bpw) | ||
| 129 | return 0; | ||
| 130 | |||
| 131 | cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW; | ||
| 132 | cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH; | ||
| 133 | clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW; | ||
| 134 | |||
| 135 | /* Construct instructions */ | ||
| 136 | |||
| 137 | /* Disable Chip Select */ | ||
| 138 | hw->pc_dis = idx; | ||
| 139 | seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk; | ||
| 140 | seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk; | ||
| 141 | |||
| 142 | /* Enable Chip Select */ | ||
| 143 | hw->pc_en = idx; | ||
| 144 | seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk; | ||
| 145 | seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; | ||
| 146 | |||
| 147 | /* Reads and writes need to be split for bpw > 16 */ | ||
| 148 | topbits = (bpw > 16) ? 16 : bpw; | ||
| 149 | botbits = bpw - topbits; | ||
| 150 | |||
| 151 | /* Write */ | ||
| 152 | hw->pc_wr = idx; | ||
| 153 | seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG; | ||
| 154 | if (botbits) | ||
| 155 | seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG; | ||
| 156 | seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; | ||
| 157 | |||
| 158 | /* Read */ | ||
| 159 | hw->pc_rd = idx; | ||
| 160 | if (botbits) | ||
| 161 | seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG; | ||
| 162 | seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG; | ||
| 163 | seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; | ||
| 164 | |||
| 165 | error = ti_ssp_load(hw->dev, 0, seqram, idx); | ||
| 166 | if (error < 0) | ||
| 167 | return error; | ||
| 168 | |||
| 169 | error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ? | ||
| 170 | 0 : SSP_EARLY_DIN)); | ||
| 171 | if (error < 0) | ||
| 172 | return error; | ||
| 173 | |||
| 174 | hw->bpw = bpw; | ||
| 175 | hw->mode = mode; | ||
| 176 | |||
| 177 | return error; | ||
| 178 | } | ||
| 179 | |||
| 180 | static void ti_ssp_spi_work(struct work_struct *work) | ||
| 181 | { | ||
| 182 | struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work); | ||
| 183 | |||
| 184 | spin_lock(&hw->lock); | ||
| 185 | |||
| 186 | while (!list_empty(&hw->msg_queue)) { | ||
| 187 | struct spi_message *m; | ||
| 188 | struct spi_device *spi; | ||
| 189 | struct spi_transfer *t = NULL; | ||
| 190 | int status = 0; | ||
| 191 | |||
| 192 | m = container_of(hw->msg_queue.next, struct spi_message, | ||
| 193 | queue); | ||
| 194 | |||
| 195 | list_del_init(&m->queue); | ||
| 196 | |||
| 197 | spin_unlock(&hw->lock); | ||
| 198 | |||
| 199 | spi = m->spi; | ||
| 200 | |||
| 201 | if (hw->select) | ||
| 202 | hw->select(spi->chip_select); | ||
| 203 | |||
| 204 | list_for_each_entry(t, &m->transfers, transfer_list) { | ||
| 205 | int bpw = spi->bits_per_word; | ||
| 206 | int xfer_status; | ||
| 207 | |||
| 208 | if (t->bits_per_word) | ||
| 209 | bpw = t->bits_per_word; | ||
| 210 | |||
| 211 | if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0) | ||
| 212 | break; | ||
| 213 | |||
| 214 | ti_ssp_spi_chip_select(hw, 1); | ||
| 215 | |||
| 216 | xfer_status = ti_ssp_spi_txrx(hw, m, t); | ||
| 217 | if (xfer_status < 0) | ||
| 218 | status = xfer_status; | ||
| 219 | |||
| 220 | if (t->delay_usecs) | ||
| 221 | udelay(t->delay_usecs); | ||
| 222 | |||
| 223 | if (t->cs_change) | ||
| 224 | ti_ssp_spi_chip_select(hw, 0); | ||
| 225 | } | ||
| 226 | |||
| 227 | ti_ssp_spi_chip_select(hw, 0); | ||
| 228 | m->status = status; | ||
| 229 | m->complete(m->context); | ||
| 230 | |||
| 231 | spin_lock(&hw->lock); | ||
| 232 | } | ||
| 233 | |||
| 234 | if (hw->shutdown) | ||
| 235 | complete(&hw->complete); | ||
| 236 | |||
| 237 | spin_unlock(&hw->lock); | ||
| 238 | } | ||
| 239 | |||
| 240 | static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m) | ||
| 241 | { | ||
| 242 | struct ti_ssp_spi *hw; | ||
| 243 | struct spi_transfer *t; | ||
| 244 | int error = 0; | ||
| 245 | |||
| 246 | m->actual_length = 0; | ||
| 247 | m->status = -EINPROGRESS; | ||
| 248 | |||
| 249 | hw = spi_master_get_devdata(spi->master); | ||
| 250 | |||
| 251 | if (list_empty(&m->transfers) || !m->complete) | ||
| 252 | return -EINVAL; | ||
| 253 | |||
| 254 | list_for_each_entry(t, &m->transfers, transfer_list) { | ||
| 255 | if (t->len && !(t->rx_buf || t->tx_buf)) { | ||
| 256 | dev_err(&spi->dev, "invalid xfer, no buffer\n"); | ||
| 257 | return -EINVAL; | ||
| 258 | } | ||
| 259 | |||
| 260 | if (t->len && t->rx_buf && t->tx_buf) { | ||
| 261 | dev_err(&spi->dev, "invalid xfer, full duplex\n"); | ||
| 262 | return -EINVAL; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | spin_lock(&hw->lock); | ||
| 267 | if (hw->shutdown) { | ||
| 268 | error = -ESHUTDOWN; | ||
| 269 | goto error_unlock; | ||
| 270 | } | ||
| 271 | list_add_tail(&m->queue, &hw->msg_queue); | ||
| 272 | queue_work(hw->workqueue, &hw->work); | ||
| 273 | error_unlock: | ||
| 274 | spin_unlock(&hw->lock); | ||
| 275 | return error; | ||
| 276 | } | ||
| 277 | |||
| 278 | static int ti_ssp_spi_probe(struct platform_device *pdev) | ||
| 279 | { | ||
| 280 | const struct ti_ssp_spi_data *pdata; | ||
| 281 | struct ti_ssp_spi *hw; | ||
| 282 | struct spi_master *master; | ||
| 283 | struct device *dev = &pdev->dev; | ||
| 284 | int error = 0; | ||
| 285 | |||
| 286 | pdata = dev_get_platdata(dev); | ||
| 287 | if (!pdata) { | ||
| 288 | dev_err(dev, "platform data not found\n"); | ||
| 289 | return -EINVAL; | ||
| 290 | } | ||
| 291 | |||
| 292 | master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi)); | ||
| 293 | if (!master) { | ||
| 294 | dev_err(dev, "cannot allocate SPI master\n"); | ||
| 295 | return -ENOMEM; | ||
| 296 | } | ||
| 297 | |||
| 298 | hw = spi_master_get_devdata(master); | ||
| 299 | platform_set_drvdata(pdev, hw); | ||
| 300 | |||
| 301 | hw->master = master; | ||
| 302 | hw->dev = dev; | ||
| 303 | hw->select = pdata->select; | ||
| 304 | |||
| 305 | spin_lock_init(&hw->lock); | ||
| 306 | init_completion(&hw->complete); | ||
| 307 | INIT_LIST_HEAD(&hw->msg_queue); | ||
| 308 | INIT_WORK(&hw->work, ti_ssp_spi_work); | ||
| 309 | |||
| 310 | hw->workqueue = create_singlethread_workqueue(dev_name(dev)); | ||
| 311 | if (!hw->workqueue) { | ||
| 312 | error = -ENOMEM; | ||
| 313 | dev_err(dev, "work queue creation failed\n"); | ||
| 314 | goto error_wq; | ||
| 315 | } | ||
| 316 | |||
| 317 | error = ti_ssp_set_iosel(hw->dev, pdata->iosel); | ||
| 318 | if (error < 0) { | ||
| 319 | dev_err(dev, "io setup failed\n"); | ||
| 320 | goto error_iosel; | ||
| 321 | } | ||
| 322 | |||
| 323 | master->bus_num = pdev->id; | ||
| 324 | master->num_chipselect = pdata->num_cs; | ||
| 325 | master->mode_bits = MODE_BITS; | ||
| 326 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); | ||
| 327 | master->flags = SPI_MASTER_HALF_DUPLEX; | ||
| 328 | master->transfer = ti_ssp_spi_transfer; | ||
| 329 | |||
| 330 | error = spi_register_master(master); | ||
| 331 | if (error) { | ||
| 332 | dev_err(dev, "master registration failed\n"); | ||
| 333 | goto error_reg; | ||
| 334 | } | ||
| 335 | |||
| 336 | return 0; | ||
| 337 | |||
| 338 | error_reg: | ||
| 339 | error_iosel: | ||
| 340 | destroy_workqueue(hw->workqueue); | ||
| 341 | error_wq: | ||
| 342 | spi_master_put(master); | ||
| 343 | return error; | ||
| 344 | } | ||
| 345 | |||
| 346 | static int ti_ssp_spi_remove(struct platform_device *pdev) | ||
| 347 | { | ||
| 348 | struct ti_ssp_spi *hw = platform_get_drvdata(pdev); | ||
| 349 | int error; | ||
| 350 | |||
| 351 | hw->shutdown = 1; | ||
| 352 | while (!list_empty(&hw->msg_queue)) { | ||
| 353 | error = wait_for_completion_interruptible(&hw->complete); | ||
| 354 | if (error < 0) { | ||
| 355 | hw->shutdown = 0; | ||
| 356 | return error; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | destroy_workqueue(hw->workqueue); | ||
| 360 | spi_unregister_master(hw->master); | ||
| 361 | |||
| 362 | return 0; | ||
| 363 | } | ||
| 364 | |||
| 365 | static struct platform_driver ti_ssp_spi_driver = { | ||
| 366 | .probe = ti_ssp_spi_probe, | ||
| 367 | .remove = ti_ssp_spi_remove, | ||
| 368 | .driver = { | ||
| 369 | .name = "ti-ssp-spi", | ||
| 370 | .owner = THIS_MODULE, | ||
| 371 | }, | ||
| 372 | }; | ||
| 373 | module_platform_driver(ti_ssp_spi_driver); | ||
| 374 | |||
| 375 | MODULE_DESCRIPTION("SSP SPI Master"); | ||
| 376 | MODULE_AUTHOR("Cyril Chemparathy"); | ||
| 377 | MODULE_LICENSE("GPL"); | ||
| 378 | MODULE_ALIAS("platform:ti-ssp-spi"); | ||
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 88eb57e858b3..f406b30af961 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c | |||
| @@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, | |||
| 332 | data->transfer_active = false; | 332 | data->transfer_active = false; |
| 333 | wake_up(&data->wait); | 333 | wake_up(&data->wait); |
| 334 | } else { | 334 | } else { |
| 335 | dev_err(&data->master->dev, | 335 | dev_vdbg(&data->master->dev, |
| 336 | "%s : Transfer is not completed", | 336 | "%s : Transfer is not completed", |
| 337 | __func__); | 337 | __func__); |
| 338 | } | 338 | } |
| @@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master) | |||
| 464 | pch_spi_writereg(master, PCH_SRST, 0x0); | 464 | pch_spi_writereg(master, PCH_SRST, 0x0); |
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | static int pch_spi_setup(struct spi_device *pspi) | ||
| 468 | { | ||
| 469 | /* Check baud rate setting */ | ||
| 470 | /* if baud rate of chip is greater than | ||
| 471 | max we can support,return error */ | ||
| 472 | if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE) | ||
| 473 | pspi->max_speed_hz = PCH_MAX_BAUDRATE; | ||
| 474 | |||
| 475 | dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__, | ||
| 476 | (pspi->mode) & (SPI_CPOL | SPI_CPHA)); | ||
| 477 | |||
| 478 | return 0; | ||
| 479 | } | ||
| 480 | |||
| 481 | static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) | 467 | static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) |
| 482 | { | 468 | { |
| 483 | 469 | ||
| @@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) | |||
| 486 | int retval; | 472 | int retval; |
| 487 | unsigned long flags; | 473 | unsigned long flags; |
| 488 | 474 | ||
| 489 | /* validate spi message and baud rate */ | ||
| 490 | if (unlikely(list_empty(&pmsg->transfers) == 1)) { | ||
| 491 | dev_err(&pspi->dev, "%s list empty\n", __func__); | ||
| 492 | retval = -EINVAL; | ||
| 493 | goto err_out; | ||
| 494 | } | ||
| 495 | |||
| 496 | if (unlikely(pspi->max_speed_hz == 0)) { | ||
| 497 | dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n", | ||
| 498 | __func__, pspi->max_speed_hz); | ||
| 499 | retval = -EINVAL; | ||
| 500 | goto err_out; | ||
| 501 | } | ||
| 502 | |||
| 503 | dev_dbg(&pspi->dev, | ||
| 504 | "%s Transfer List not empty. Transfer Speed is set.\n", __func__); | ||
| 505 | |||
| 506 | spin_lock_irqsave(&data->lock, flags); | 475 | spin_lock_irqsave(&data->lock, flags); |
| 507 | /* validate Tx/Rx buffers and Transfer length */ | 476 | /* validate Tx/Rx buffers and Transfer length */ |
| 508 | list_for_each_entry(transfer, &pmsg->transfers, transfer_list) { | 477 | list_for_each_entry(transfer, &pmsg->transfers, transfer_list) { |
| @@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) | |||
| 523 | dev_dbg(&pspi->dev, | 492 | dev_dbg(&pspi->dev, |
| 524 | "%s Tx/Rx buffer valid. Transfer length valid\n", | 493 | "%s Tx/Rx buffer valid. Transfer length valid\n", |
| 525 | __func__); | 494 | __func__); |
| 526 | |||
| 527 | /* if baud rate has been specified validate the same */ | ||
| 528 | if (transfer->speed_hz > PCH_MAX_BAUDRATE) | ||
| 529 | transfer->speed_hz = PCH_MAX_BAUDRATE; | ||
| 530 | } | 495 | } |
| 531 | spin_unlock_irqrestore(&data->lock, flags); | 496 | spin_unlock_irqrestore(&data->lock, flags); |
| 532 | 497 | ||
| @@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
| 1151 | dma->nent = num; | 1116 | dma->nent = num; |
| 1152 | dma->desc_tx = desc_tx; | 1117 | dma->desc_tx = desc_tx; |
| 1153 | 1118 | ||
| 1154 | dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing " | 1119 | dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__); |
| 1155 | "0x2 to SSNXCR\n", __func__); | ||
| 1156 | 1120 | ||
| 1157 | spin_lock_irqsave(&data->lock, flags); | 1121 | spin_lock_irqsave(&data->lock, flags); |
| 1158 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); | 1122 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); |
| @@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev) | |||
| 1418 | 1382 | ||
| 1419 | /* initialize members of SPI master */ | 1383 | /* initialize members of SPI master */ |
| 1420 | master->num_chipselect = PCH_MAX_CS; | 1384 | master->num_chipselect = PCH_MAX_CS; |
| 1421 | master->setup = pch_spi_setup; | ||
| 1422 | master->transfer = pch_spi_transfer; | 1385 | master->transfer = pch_spi_transfer; |
| 1423 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; | 1386 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; |
| 1424 | master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); | 1387 | master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); |
| 1388 | master->max_speed_hz = PCH_MAX_BAUDRATE; | ||
| 1425 | 1389 | ||
| 1426 | data->board_dat = board_dat; | 1390 | data->board_dat = board_dat; |
| 1427 | data->plat_dev = plat_dev; | 1391 | data->plat_dev = plat_dev; |
| @@ -1605,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = { | |||
| 1605 | .resume = pch_spi_pd_resume | 1569 | .resume = pch_spi_pd_resume |
| 1606 | }; | 1570 | }; |
| 1607 | 1571 | ||
| 1608 | static int pch_spi_probe(struct pci_dev *pdev, | 1572 | static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| 1609 | const struct pci_device_id *id) | ||
| 1610 | { | 1573 | { |
| 1611 | struct pch_spi_board_data *board_dat; | 1574 | struct pch_spi_board_data *board_dat; |
| 1612 | struct platform_device *pd_dev = NULL; | 1575 | struct platform_device *pd_dev = NULL; |
| @@ -1676,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev, | |||
| 1676 | return 0; | 1639 | return 0; |
| 1677 | 1640 | ||
| 1678 | err_platform_device: | 1641 | err_platform_device: |
| 1642 | while (--i >= 0) | ||
| 1643 | platform_device_unregister(pd_dev_save->pd_save[i]); | ||
| 1679 | pci_disable_device(pdev); | 1644 | pci_disable_device(pdev); |
| 1680 | pci_enable_device: | 1645 | pci_enable_device: |
| 1681 | pci_release_regions(pdev); | 1646 | pci_release_regions(pdev); |
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 6191ced514b2..820b499816f8 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c | |||
| @@ -80,7 +80,6 @@ struct txx9spi { | |||
| 80 | void __iomem *membase; | 80 | void __iomem *membase; |
| 81 | int baseclk; | 81 | int baseclk; |
| 82 | struct clk *clk; | 82 | struct clk *clk; |
| 83 | u32 max_speed_hz, min_speed_hz; | ||
| 84 | int last_chipselect; | 83 | int last_chipselect; |
| 85 | int last_chipselect_val; | 84 | int last_chipselect_val; |
| 86 | }; | 85 | }; |
| @@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi) | |||
| 117 | { | 116 | { |
| 118 | struct txx9spi *c = spi_master_get_devdata(spi->master); | 117 | struct txx9spi *c = spi_master_get_devdata(spi->master); |
| 119 | 118 | ||
| 120 | if (!spi->max_speed_hz | 119 | if (!spi->max_speed_hz) |
| 121 | || spi->max_speed_hz > c->max_speed_hz | ||
| 122 | || spi->max_speed_hz < c->min_speed_hz) | ||
| 123 | return -EINVAL; | 120 | return -EINVAL; |
| 124 | 121 | ||
| 125 | if (gpio_direction_output(spi->chip_select, | 122 | if (gpio_direction_output(spi->chip_select, |
| @@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) | |||
| 309 | 306 | ||
| 310 | /* check each transfer's parameters */ | 307 | /* check each transfer's parameters */ |
| 311 | list_for_each_entry(t, &m->transfers, transfer_list) { | 308 | list_for_each_entry(t, &m->transfers, transfer_list) { |
| 312 | u32 speed_hz = t->speed_hz ? : spi->max_speed_hz; | ||
| 313 | u8 bits_per_word = t->bits_per_word; | ||
| 314 | |||
| 315 | if (!t->tx_buf && !t->rx_buf && t->len) | 309 | if (!t->tx_buf && !t->rx_buf && t->len) |
| 316 | return -EINVAL; | 310 | return -EINVAL; |
| 317 | if (t->len & ((bits_per_word >> 3) - 1)) | ||
| 318 | return -EINVAL; | ||
| 319 | if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz) | ||
| 320 | return -EINVAL; | ||
| 321 | } | 311 | } |
| 322 | 312 | ||
| 323 | spin_lock_irqsave(&c->lock, flags); | 313 | spin_lock_irqsave(&c->lock, flags); |
| @@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev) | |||
| 360 | goto exit; | 350 | goto exit; |
| 361 | } | 351 | } |
| 362 | c->baseclk = clk_get_rate(c->clk); | 352 | c->baseclk = clk_get_rate(c->clk); |
| 363 | c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); | 353 | master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); |
| 364 | c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); | 354 | master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); |
| 365 | 355 | ||
| 366 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | 356 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); |
| 367 | if (!res) | 357 | c->membase = devm_ioremap_resource(&dev->dev, res); |
| 368 | goto exit_busy; | 358 | if (IS_ERR(c->membase)) |
| 369 | if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res), | ||
| 370 | "spi_txx9")) | ||
| 371 | goto exit_busy; | ||
| 372 | c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res)); | ||
| 373 | if (!c->membase) | ||
| 374 | goto exit_busy; | 359 | goto exit_busy; |
| 375 | 360 | ||
| 376 | /* enter config mode */ | 361 | /* enter config mode */ |
diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 350a76b7e8d4..bb478dccf1d8 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c | |||
| @@ -73,15 +73,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, | |||
| 73 | static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, | 73 | static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, |
| 74 | struct spi_device *spi, struct spi_transfer *t, unsigned int *settings) | 74 | struct spi_device *spi, struct spi_transfer *t, unsigned int *settings) |
| 75 | { | 75 | { |
| 76 | unsigned int speed; | ||
| 77 | |||
| 78 | if (t->len > 62) | 76 | if (t->len > 62) |
| 79 | return -EINVAL; | 77 | return -EINVAL; |
| 80 | 78 | ||
| 81 | speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz; | 79 | if (t->speed_hz != spi_xcomm->current_speed) { |
| 80 | unsigned int divider; | ||
| 82 | 81 | ||
| 83 | if (speed != spi_xcomm->current_speed) { | 82 | divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz); |
| 84 | unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed); | ||
| 85 | if (divider >= 64) | 83 | if (divider >= 64) |
| 86 | *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64; | 84 | *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64; |
| 87 | else if (divider >= 16) | 85 | else if (divider >= 16) |
| @@ -89,7 +87,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, | |||
| 89 | else | 87 | else |
| 90 | *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4; | 88 | *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4; |
| 91 | 89 | ||
| 92 | spi_xcomm->current_speed = speed; | 90 | spi_xcomm->current_speed = t->speed_hz; |
| 93 | } | 91 | } |
| 94 | 92 | ||
| 95 | if (spi->mode & SPI_CPOL) | 93 | if (spi->mode & SPI_CPOL) |
| @@ -147,8 +145,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master, | |||
| 147 | int status = 0; | 145 | int status = 0; |
| 148 | bool is_last; | 146 | bool is_last; |
| 149 | 147 | ||
| 150 | is_first = true; | ||
| 151 | |||
| 152 | spi_xcomm_chipselect(spi_xcomm, spi, true); | 148 | spi_xcomm_chipselect(spi_xcomm, spi, true); |
| 153 | 149 | ||
| 154 | list_for_each_entry(t, &msg->transfers, transfer_list) { | 150 | list_for_each_entry(t, &msg->transfers, transfer_list) { |
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ffc1a2ebc4ca..4eb9bf02996c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
| @@ -756,6 +756,7 @@ static int spi_transfer_one_message(struct spi_master *master, | |||
| 756 | struct spi_transfer *xfer; | 756 | struct spi_transfer *xfer; |
| 757 | bool keep_cs = false; | 757 | bool keep_cs = false; |
| 758 | int ret = 0; | 758 | int ret = 0; |
| 759 | int ms = 1; | ||
| 759 | 760 | ||
| 760 | spi_set_cs(msg->spi, true); | 761 | spi_set_cs(msg->spi, true); |
| 761 | 762 | ||
| @@ -773,7 +774,16 @@ static int spi_transfer_one_message(struct spi_master *master, | |||
| 773 | 774 | ||
| 774 | if (ret > 0) { | 775 | if (ret > 0) { |
| 775 | ret = 0; | 776 | ret = 0; |
| 776 | wait_for_completion(&master->xfer_completion); | 777 | ms = xfer->len * 8 * 1000 / xfer->speed_hz; |
| 778 | ms += 10; /* some tolerance */ | ||
| 779 | |||
| 780 | ms = wait_for_completion_timeout(&master->xfer_completion, | ||
| 781 | msecs_to_jiffies(ms)); | ||
| 782 | } | ||
| 783 | |||
| 784 | if (ms == 0) { | ||
| 785 | dev_err(&msg->spi->dev, "SPI transfer timed out\n"); | ||
| 786 | msg->status = -ETIMEDOUT; | ||
| 777 | } | 787 | } |
| 778 | 788 | ||
| 779 | trace_spi_transfer_stop(msg, xfer); | 789 | trace_spi_transfer_stop(msg, xfer); |
