Commit d2901069 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'spi-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi updates from Mark Brown:
 "A quiet release for SPI, mainly driver updates and not too many of
  them:

   - Support for dummy transfers (for delays on startup) in drivers
     using transfer_one().
   - Lots of enhancements to the Designware driver to support new Intel
     SoCs.
   - Support for newer Renesas chips.
   - DMA support for the i.MX driver.
   - One new driver for Broadcom BCM53xx chips"

* tag 'spi-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (64 commits)
  spi: spi-mxs: fix a tiny typo in a comment
  spi: dw-mid: follow new DMAengine workflow
  spi: dw-mid: convert to use DMAengine wrappers
  spi: dw-mid: change magic numbers to the constants
  spi: orion: support armada extended baud rates
  spi: fsl: Sort include headers alphabetically
  spi: bcm53xx: Add missing module information
  spi: bcm53xx: Fix module dependency
  spi/rockchip: fix bug that cause the failure to read data in DMA mode
  spi: fsl-dspi: Remove probe info message
  spi: pl022: Add support for chip select extension
  spi: Fix possible ZERO_SIZE_PTR pointer dereferencing error.
  spi: dw: fix style of code in few places
  spi: dw: introduce support of loopback mode
  spi: dw-mid: terminate ongoing transfers at exit
  spi: dw-mid: respect 8 bit mode
  spi: clps711x: Migrate to the new clk subsystem
  spi: pl022: Add missing error check for devm_kzalloc
  spi: spi-imx: add DMA support
  spi: davinci: add support for adding delay between word's transmissions
  ...
parents 81e29b7d a2285b8c
...@@ -7,6 +7,9 @@ Required properties: ...@@ -7,6 +7,9 @@ Required properties:
- interrupts : Should contain CSPI/eCSPI interrupt - interrupts : Should contain CSPI/eCSPI interrupt
- fsl,spi-num-chipselects : Contains the number of the chipselect - fsl,spi-num-chipselects : Contains the number of the chipselect
- cs-gpios : Specifies the gpio pins to be used for chipselects. - cs-gpios : Specifies the gpio pins to be used for chipselects.
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt
- dma-names: DMA request names should include "tx" and "rx" if present.
Example: Example:
...@@ -19,4 +22,6 @@ ecspi@70010000 { ...@@ -19,4 +22,6 @@ ecspi@70010000 {
fsl,spi-num-chipselects = <2>; fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio3 24 0>, /* GPIO3_24 */ cs-gpios = <&gpio3 24 0>, /* GPIO3_24 */
<&gpio3 25 0>; /* GPIO3_25 */ <&gpio3 25 0>; /* GPIO3_25 */
dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
dma-names = "rx", "tx";
}; };
...@@ -6,8 +6,17 @@ Required properties: ...@@ -6,8 +6,17 @@ Required properties:
"renesas,sh-mobile-msiof" for SH Mobile series. "renesas,sh-mobile-msiof" for SH Mobile series.
Examples with soctypes are: Examples with soctypes are:
"renesas,msiof-r8a7790" (R-Car H2) "renesas,msiof-r8a7790" (R-Car H2)
"renesas,msiof-r8a7791" (R-Car M2) "renesas,msiof-r8a7791" (R-Car M2-W)
- reg : Offset and length of the register set for the device "renesas,msiof-r8a7792" (R-Car V2H)
"renesas,msiof-r8a7793" (R-Car M2-N)
"renesas,msiof-r8a7794" (R-Car E2)
- reg : A list of offsets and lengths of the register sets for
the device.
If only one register set is present, it is to be used
by both the CPU and the DMA engine.
If two register sets are present, the first is to be
used by the CPU, and the second is to be used by the
DMA engine.
- interrupt-parent : The phandle for the interrupt controller that - interrupt-parent : The phandle for the interrupt controller that
services interrupts for this device services interrupts for this device
- interrupts : Interrupt specifier - interrupts : Interrupt specifier
...@@ -17,12 +26,16 @@ Required properties: ...@@ -17,12 +26,16 @@ Required properties:
Optional properties: Optional properties:
- clocks : Must contain a reference to the functional clock. - clocks : Must contain a reference to the functional clock.
- num-cs : Total number of chip-selects (default is 1) - num-cs : Total number of chip-selects (default is 1)
- dmas : Must contain a list of two references to DMA
specifiers, one for transmission, and one for
reception.
- dma-names : Must contain a list of two DMA names, "tx" and "rx".
Optional properties, deprecated for soctype-specific bindings: Optional properties, deprecated for soctype-specific bindings:
- renesas,tx-fifo-size : Overrides the default tx fifo size given in words - renesas,tx-fifo-size : Overrides the default tx fifo size given in words
(default is 64) (default is 64)
- renesas,rx-fifo-size : Overrides the default rx fifo size given in words - renesas,rx-fifo-size : Overrides the default rx fifo size given in words
(default is 64, or 256 on R-Car H2 and M2) (default is 64, or 256 on R-Car Gen2)
Pinctrl properties might be needed, too. See Pinctrl properties might be needed, too. See
Documentation/devicetree/bindings/pinctrl/renesas,*. Documentation/devicetree/bindings/pinctrl/renesas,*.
...@@ -31,9 +44,11 @@ Example: ...@@ -31,9 +44,11 @@ Example:
msiof0: spi@e6e20000 { msiof0: spi@e6e20000 {
compatible = "renesas,msiof-r8a7791"; compatible = "renesas,msiof-r8a7791";
reg = <0 0xe6e20000 0 0x0064>; reg = <0 0xe6e20000 0 0x0064>, <0 0xe7e20000 0 0x0064>;
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>; interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>; clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
dmas = <&dmac0 0x51>, <&dmac0 0x52>;
dma-names = "tx", "rx";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
status = "disabled"; status = "disabled";
......
Davinci SPI controller device bindings Davinci SPI controller device bindings
Links on DM:
Keystone 2 - http://www.ti.com/lit/ug/sprugp2a/sprugp2a.pdf
dm644x - http://www.ti.com/lit/ug/sprue32a/sprue32a.pdf
OMAP-L138/da830 - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf
Required properties: Required properties:
- #address-cells: number of cells required to define a chip select - #address-cells: number of cells required to define a chip select
address on the SPI bus. Should be set to 1. address on the SPI bus. Should be set to 1.
...@@ -24,6 +29,30 @@ Optional: ...@@ -24,6 +29,30 @@ Optional:
cs-gpios = <0>, <0>, <0>, <&gpio1 30 0>, <&gpio1 31 0>; cs-gpios = <0>, <0>, <0>, <&gpio1 30 0>, <&gpio1 31 0>;
where first three are internal CS and last two are GPIO CS. where first three are internal CS and last two are GPIO CS.
Optional properties for slave devices:
SPI slave nodes can contain the following properties.
Not all SPI Peripherals from Texas Instruments support this.
Please check SPI peripheral documentation for a device before using these.
- ti,spi-wdelay : delay between transmission of words
(SPIFMTn.WDELAY, SPIDAT1.WDEL) must be specified in number of SPI module
clock periods.
delay = WDELAY * SPI_module_clock_period + 2 * SPI_module_clock_period
Below is timing diagram which shows functional meaning of
"ti,spi-wdelay" parameter.
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
SPI_CLK | | | | | | | | | | | | | | | |
+----------+ +-+ +-+ +-+ +-+ +---------------------------+ +-+ +-+ +-
SPI_SOMI/SIMO+-----------------+ +-----------
+----------+ word1 +---------------------------+word2
+-----------------+ +-----------
WDELAY
<-------------------------->
Example of a NOR flash slave device (n25q032) connected to DaVinci Example of a NOR flash slave device (n25q032) connected to DaVinci
SPI controller device over the SPI bus. SPI controller device over the SPI bus.
...@@ -43,6 +72,7 @@ spi0:spi@20BF0000 { ...@@ -43,6 +72,7 @@ spi0:spi@20BF0000 {
compatible = "st,m25p32"; compatible = "st,m25p32";
spi-max-frequency = <25000000>; spi-max-frequency = <25000000>;
reg = <0>; reg = <0>;
ti,spi-wdelay = <8>;
partition@0 { partition@0 {
label = "u-boot-spl"; label = "u-boot-spl";
......
...@@ -10,7 +10,12 @@ Required properties: ...@@ -10,7 +10,12 @@ Required properties:
- pinctrl-names: must contain a "default" entry. - pinctrl-names: must contain a "default" entry.
- spi-num-chipselects : the number of the chipselect signals. - spi-num-chipselects : the number of the chipselect signals.
- bus-num : the slave chip chipselect signal number. - bus-num : the slave chip chipselect signal number.
- big-endian : if DSPI modudle is big endian, the bool will be set in node.
Optional property:
- big-endian: If present the dspi device's registers are implemented
in big endian mode, otherwise in native mode(same with CPU), for more
detail please see: Documentation/devicetree/bindings/regmap/regmap.txt.
Example: Example:
dspi0@4002c000 { dspi0@4002c000 {
......
Marvell Orion SPI device Marvell Orion SPI device
Required properties: Required properties:
- compatible : should be "marvell,orion-spi". - compatible : should be "marvell,orion-spi" or "marvell,armada-370-spi".
- reg : offset and length of the register set for the device - reg : offset and length of the register set for the device
- cell-index : Which of multiple SPI controllers is this. - cell-index : Which of multiple SPI controllers is this.
Optional properties: Optional properties:
......
...@@ -11,7 +11,10 @@ Required properties: ...@@ -11,7 +11,10 @@ Required properties:
- "renesas,rspi-sh7757" (SH) - "renesas,rspi-sh7757" (SH)
- "renesas,rspi-r7s72100" (RZ/A1H) - "renesas,rspi-r7s72100" (RZ/A1H)
- "renesas,qspi-r8a7790" (R-Car H2) - "renesas,qspi-r8a7790" (R-Car H2)
- "renesas,qspi-r8a7791" (R-Car M2) - "renesas,qspi-r8a7791" (R-Car M2-W)
- "renesas,qspi-r8a7792" (R-Car V2H)
- "renesas,qspi-r8a7793" (R-Car M2-N)
- "renesas,qspi-r8a7794" (R-Car E2)
- reg : Address start and address range size of the device - reg : Address start and address range size of the device
- interrupts : A list of interrupt-specifiers, one for each entry in - interrupts : A list of interrupt-specifiers, one for each entry in
interrupt-names. interrupt-names.
...@@ -30,6 +33,9 @@ Required properties: ...@@ -30,6 +33,9 @@ Required properties:
Optional properties: Optional properties:
- clocks : Must contain a reference to the functional clock. - clocks : Must contain a reference to the functional clock.
- dmas : Must contain a list of two references to DMA specifiers,
one for transmission, and one for reception.
- dma-names : Must contain a list of two DMA names, "tx" and "rx".
Pinctrl properties might be needed, too. See Pinctrl properties might be needed, too. See
Documentation/devicetree/bindings/pinctrl/renesas,*. Documentation/devicetree/bindings/pinctrl/renesas,*.
...@@ -58,4 +64,6 @@ Examples: ...@@ -58,4 +64,6 @@ Examples:
num-cs = <1>; num-cs = <1>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
dmas = <&dmac0 0x17>, <&dmac0 0x18>;
dma-names = "tx", "rx";
}; };
...@@ -601,13 +601,13 @@ THANKS TO ...@@ -601,13 +601,13 @@ THANKS TO
Contributors to Linux-SPI discussions include (in alphabetical order, Contributors to Linux-SPI discussions include (in alphabetical order,
by last name): by last name):
Mark Brown
David Brownell David Brownell
Russell King Russell King
Grant Likely
Dmitry Pervushin Dmitry Pervushin
Stephen Street Stephen Street
Mark Underwood Mark Underwood
Andrew Victor Andrew Victor
Vitaly Wool
Grant Likely
Mark Brown
Linus Walleij Linus Walleij
Vitaly Wool
...@@ -69,6 +69,7 @@ config SPI_ATH79 ...@@ -69,6 +69,7 @@ config SPI_ATH79
config SPI_ATMEL config SPI_ATMEL
tristate "Atmel SPI Controller" tristate "Atmel SPI Controller"
depends on HAS_DMA
depends on (ARCH_AT91 || AVR32 || COMPILE_TEST) depends on (ARCH_AT91 || AVR32 || COMPILE_TEST)
help help
This selects a driver for the Atmel SPI Controller, present on This selects a driver for the Atmel SPI Controller, present on
...@@ -112,6 +113,14 @@ config SPI_AU1550 ...@@ -112,6 +113,14 @@ config SPI_AU1550
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
PSC SPI controller found on Au1550, Au1200 and Au1300 series. PSC SPI controller found on Au1550, Au1200 and Au1300 series.
config SPI_BCM53XX
tristate "Broadcom BCM53xx SPI controller"
depends on ARCH_BCM_5301X
depends on BCMA_POSSIBLE
select BCMA
help
Enable support for the SPI controller on Broadcom BCM53xx ARM SoCs.
config SPI_BCM63XX config SPI_BCM63XX
tristate "Broadcom BCM63xx SPI controller" tristate "Broadcom BCM63xx SPI controller"
depends on BCM63XX depends on BCM63XX
...@@ -185,6 +194,7 @@ config SPI_EFM32 ...@@ -185,6 +194,7 @@ config SPI_EFM32
config SPI_EP93XX config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller" tristate "Cirrus Logic EP93xx SPI controller"
depends on HAS_DMA
depends on ARCH_EP93XX || COMPILE_TEST depends on ARCH_EP93XX || COMPILE_TEST
help help
This enables using the Cirrus EP93xx SPI controller in master This enables using the Cirrus EP93xx SPI controller in master
...@@ -314,6 +324,7 @@ config SPI_OMAP_UWIRE ...@@ -314,6 +324,7 @@ config SPI_OMAP_UWIRE
config SPI_OMAP24XX config SPI_OMAP24XX
tristate "McSPI driver for OMAP" tristate "McSPI driver for OMAP"
depends on HAS_DMA
depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH
depends on ARCH_OMAP2PLUS || COMPILE_TEST depends on ARCH_OMAP2PLUS || COMPILE_TEST
help help
...@@ -380,7 +391,7 @@ config SPI_PXA2XX ...@@ -380,7 +391,7 @@ config SPI_PXA2XX
additional documentation can be found a Documentation/spi/pxa2xx. additional documentation can be found a Documentation/spi/pxa2xx.
config SPI_PXA2XX_PCI config SPI_PXA2XX_PCI
def_tristate SPI_PXA2XX && PCI def_tristate SPI_PXA2XX && PCI && COMMON_CLK
config SPI_ROCKCHIP config SPI_ROCKCHIP
tristate "Rockchip SPI controller driver" tristate "Rockchip SPI controller driver"
...@@ -500,7 +511,7 @@ config SPI_MXS ...@@ -500,7 +511,7 @@ config SPI_MXS
config SPI_TEGRA114 config SPI_TEGRA114
tristate "NVIDIA Tegra114 SPI Controller" tristate "NVIDIA Tegra114 SPI Controller"
depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
depends on RESET_CONTROLLER depends on RESET_CONTROLLER && HAS_DMA
help help
SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller
is different than the older SoCs SPI controller and also register interface is different than the older SoCs SPI controller and also register interface
...@@ -518,7 +529,7 @@ config SPI_TEGRA20_SFLASH ...@@ -518,7 +529,7 @@ config SPI_TEGRA20_SFLASH
config SPI_TEGRA20_SLINK config SPI_TEGRA20_SLINK
tristate "Nvidia Tegra20/Tegra30 SLINK Controller" tristate "Nvidia Tegra20/Tegra30 SLINK Controller"
depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
depends on RESET_CONTROLLER depends on RESET_CONTROLLER && HAS_DMA
help help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
...@@ -591,7 +602,7 @@ config SPI_DW_PCI ...@@ -591,7 +602,7 @@ config SPI_DW_PCI
depends on SPI_DESIGNWARE && PCI depends on SPI_DESIGNWARE && PCI
config SPI_DW_MID_DMA config SPI_DW_MID_DMA
bool "DMA support for DW SPI controller on Intel Moorestown platform" bool "DMA support for DW SPI controller on Intel MID platform"
depends on SPI_DW_PCI && INTEL_MID_DMAC depends on SPI_DW_PCI && INTEL_MID_DMAC
config SPI_DW_MMIO config SPI_DW_MMIO
......
...@@ -15,6 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o ...@@ -15,6 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
......
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/bcma/bcma.h>
#include <linux/spi/spi.h>
#include "spi-bcm53xx.h"
#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */
/* The longest observed required wait was 19 ms */
#define BCM53XXSPI_SPE_TIMEOUT_MS 80
struct bcm53xxspi {
struct bcma_device *core;
struct spi_master *master;
size_t read_offset;
};
static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
{
return bcma_read32(b53spi->core, offset);
}
static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset,
u32 value)
{
bcma_write32(b53spi->core, offset, value);
}
static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
{
/* Do some magic calculation based on length and buad. Add 10% and 1. */
return (len * 9000 / BCM53XXSPI_MAX_SPI_BAUD * 110 / 100) + 1;
}
static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms)
{
unsigned long deadline;
u32 tmp;
/* SPE bit has to be 0 before we read MSPI STATUS */
deadline = jiffies + BCM53XXSPI_SPE_TIMEOUT_MS * HZ / 1000;
do {
tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
if (!(tmp & B53SPI_MSPI_SPCR2_SPE))
break;
udelay(5);
} while (!time_after_eq(jiffies, deadline));
if (tmp & B53SPI_MSPI_SPCR2_SPE)
goto spi_timeout;
/* Check status */
deadline = jiffies + timeout_ms * HZ / 1000;
do {
tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS);
if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) {
bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0);
return 0;
}
cpu_relax();
udelay(100);
} while (!time_after_eq(jiffies, deadline));
spi_timeout:
bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0);
pr_err("Timeout waiting for SPI to be ready!\n");
return -EBUSY;
}
static void bcm53xxspi_buf_write(struct bcm53xxspi *b53spi, u8 *w_buf,
size_t len, bool cont)
{
u32 tmp;
int i;
for (i = 0; i < len; i++) {
/* Transmit Register File MSB */
bcm53xxspi_write(b53spi, B53SPI_MSPI_TXRAM + 4 * (i * 2),
(unsigned int)w_buf[i]);
}
for (i = 0; i < len; i++) {
tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL |
B53SPI_CDRAM_PCS_DSCK;
if (!cont && i == len - 1)
tmp &= ~B53SPI_CDRAM_CONT;
tmp &= ~0x1;
/* Command Register File */
bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp);
}
/* Set queue pointers */
bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0);
bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1);
if (cont)
bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1);
/* Start SPI transfer */
tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
tmp |= B53SPI_MSPI_SPCR2_SPE;
if (cont)
tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD;
bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp);
/* Wait for SPI to finish */
bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len));
if (!cont)
bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0);
b53spi->read_offset = len;
}
static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf,
size_t len, bool cont)
{
u32 tmp;
int i;
for (i = 0; i < b53spi->read_offset + len; i++) {
tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL |
B53SPI_CDRAM_PCS_DSCK;
if (!cont && i == b53spi->read_offset + len - 1)
tmp &= ~B53SPI_CDRAM_CONT;
tmp &= ~0x1;
/* Command Register File */
bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp);
}
/* Set queue pointers */
bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0);
bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP,
b53spi->read_offset + len - 1);
if (cont)
bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1);
/* Start SPI transfer */
tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
tmp |= B53SPI_MSPI_SPCR2_SPE;
if (cont)
tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD;
bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp);
/* Wait for SPI to finish */
bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len));
if (!cont)
bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0);
for (i = 0; i < len; ++i) {
int offset = b53spi->read_offset + i;
/* Data stored in the transmit register file LSB */
r_buf[i] = (u8)bcm53xxspi_read(b53spi, B53SPI_MSPI_RXRAM + 4 * (1 + offset * 2));
}
b53spi->read_offset = 0;
}
static int bcm53xxspi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *t)
{
struct bcm53xxspi *b53spi = spi_master_get_devdata(master);
u8 *buf;
size_t left;
if (t->tx_buf) {
buf = (u8 *)t->tx_buf;
left = t->len;
while (left) {
size_t to_write = min_t(size_t, 16, left);
bool cont = left - to_write > 0;
bcm53xxspi_buf_write(b53spi, buf, to_write, cont);
left -= to_write;
buf += to_write;
}
}
if (t->rx_buf) {
buf = (u8 *)t->rx_buf;
left = t->len;
while (left) {
size_t to_read = min_t(size_t, 16 - b53spi->read_offset,
left);
bool cont = left - to_read > 0;
bcm53xxspi_buf_read(b53spi, buf, to_read, cont);
left -= to_read;
buf += to_read;
}
}
return 0;
}
/**************************************************
* BCMA
**************************************************/
static struct spi_board_info bcm53xx_info = {
.modalias = "bcm53xxspiflash",
};
static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS),
BCMA_CORETABLE_END
};
MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl);
static int bcm53xxspi_bcma_probe(struct bcma_device *core)
{
struct bcm53xxspi *b53spi;
struct spi_master *master;
int err;
if (core->bus->drv_cc.core->id.rev != 42) {
pr_err("SPI on SoC with unsupported ChipCommon rev\n");
return -ENOTSUPP;
}
master = spi_alloc_master(&core->dev, sizeof(*b53spi));
if (!master)
return -ENOMEM;
b53spi = spi_master_get_devdata(master);
b53spi->master = master;
b53spi->core = core;
master->transfer_one = bcm53xxspi_transfer_one;
bcma_set_drvdata(core, b53spi);
err = devm_spi_register_master(&core->dev, master);
if (err) {
spi_master_put(master);
bcma_set_drvdata(core, NULL);
goto out;
}
/* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */
spi_new_device(master, &bcm53xx_info);
out:
return err;
}
static void bcm53xxspi_bcma_remove(struct bcma_device *core)
{
struct bcm53xxspi *b53spi = bcma_get_drvdata(core);
spi_unregister_master(b53spi->master);
}
static struct bcma_driver bcm53xxspi_bcma_driver = {
.name = KBUILD_MODNAME,
.id_table = bcm53xxspi_bcma_tbl,
.probe = bcm53xxspi_bcma_probe,
.remove = bcm53xxspi_bcma_remove,
};
/**************************************************
* Init & exit
**************************************************/
static int __init bcm53xxspi_module_init(void)
{
int err = 0;
err = bcma_driver_register(&bcm53xxspi_bcma_driver);
if (err)
pr_err("Failed to register bcma driver: %d\n", err);
return err;
}
static void __exit bcm53xxspi_module_exit(void)
{
bcma_driver_unregister(&bcm53xxspi_bcma_driver);
}
module_init(bcm53xxspi_module_init);
module_exit(bcm53xxspi_module_exit);
MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver");
MODULE_AUTHOR("Rafał Miłecki <zajec5@gmail.com>");
MODULE_LICENSE("GPL");
#ifndef SPI_BCM53XX_H
#define SPI_BCM53XX_H
#define B53SPI_BSPI_REVISION_ID 0x000
#define B53SPI_BSPI_SCRATCH 0x004
#define B53SPI_BSPI_MAST_N_BOOT_CTRL 0x008
#define B53SPI_BSPI_BUSY_STATUS 0x00c
#define B53SPI_BSPI_INTR_STATUS 0x010
#define B53SPI_BSPI_B0_STATUS 0x014
#define B53SPI_BSPI_B0_CTRL 0x018
#define B53SPI_BSPI_B1_STATUS 0x01c
#define B53SPI_BSPI_B1_CTRL 0x020
#define B53SPI_BSPI_STRAP_OVERRIDE_CTRL 0x024
#define B53SPI_BSPI_FLEX_MODE_ENABLE 0x028
#define B53SPI_BSPI_BITS_PER_CYCLE 0x02c
#define B53SPI_BSPI_BITS_PER_PHASE 0x030
#define B53SPI_BSPI_CMD_AND_MODE_BYTE 0x034
#define B53SPI_BSPI_BSPI_FLASH_UPPER_ADDR_BYTE 0x038
#define B53SPI_BSPI_BSPI_XOR_VALUE 0x03c
#define B53SPI_BSPI_BSPI_XOR_ENABLE 0x040
#define B53SPI_BSPI_BSPI_PIO_MODE_ENABLE 0x044
#define B53SPI_BSPI_BSPI_PIO_IODIR 0x048
#define B53SPI_BSPI_BSPI_PIO_DATA 0x04c
/* RAF */
#define B53SPI_RAF_START_ADDR 0x100
#define B53SPI_RAF_NUM_WORDS 0x104
#define B53SPI_RAF_CTRL 0x108
#define B53SPI_RAF_FULLNESS 0x10c
#define B53SPI_RAF_WATERMARK 0x110
#define B53SPI_RAF_STATUS 0x114
#define B53SPI_RAF_READ_DATA 0x118
#define B53SPI_RAF_WORD_CNT 0x11c
#define B53SPI_RAF_CURR_ADDR 0x120
/* MSPI */
#define B53SPI_MSPI_SPCR0_LSB 0x200
#define B53SPI_MSPI_SPCR0_MSB 0x204
#define B53SPI_MSPI_SPCR1_LSB 0x208
#define B53SPI_MSPI_SPCR1_MSB 0x20c
#define B53SPI_MSPI_NEWQP 0x210
#define B53SPI_MSPI_ENDQP 0x214
#define B53SPI_MSPI_SPCR2 0x218
#define B53SPI_MSPI_SPCR2_SPE 0x00000040
#define B53SPI_MSPI_SPCR2_CONT_AFTER_CMD 0x00000080
#define B53SPI_MSPI_MSPI_STATUS 0x220
#define B53SPI_MSPI_MSPI_STATUS_SPIF 0x00000001
#define B53SPI_MSPI_CPTQP 0x224
#define B53SPI_MSPI_TXRAM 0x240 /* 32 registers, up to 0x2b8 */
#define B53SPI_MSPI_RXRAM 0x2c0 /* 32 registers, up to 0x33c */
#define B53SPI_MSPI_CDRAM 0x340 /* 16 registers, up to 0x37c */
#define B53SPI_CDRAM_PCS_PCS0 0x00000001
#define B53SPI_CDRAM_PCS_PCS1 0x00000002
#define B53SPI_CDRAM_PCS_PCS2 0x00000004
#define B53SPI_CDRAM_PCS_PCS3 0x00000008
#define B53SPI_CDRAM_PCS_DISABLE_ALL 0x0000000f
#define B53SPI_CDRAM_PCS_DSCK 0x00000010
#define B53SPI_CDRAM_BITSE 0x00000040
#define B53SPI_CDRAM_CONT 0x00000080
#define B53SPI_MSPI_WRITE_LOCK 0x380
#define B53SPI_MSPI_DISABLE_FLUSH_GEN 0x384
/* Interrupt */
#define B53SPI_INTR_RAF_LR_FULLNESS_REACHED 0x3a0
#define B53SPI_INTR_RAF_LR_TRUNCATED 0x3a4
#define B53SPI_INTR_RAF_LR_IMPATIENT 0x3a8
#define B53SPI_INTR_RAF_LR_SESSION_DONE 0x3ac
#define B53SPI_INTR_RAF_LR_OVERREAD 0x3b0
#define B53SPI_INTR_MSPI_DONE 0x3b4
#define B53SPI_INTR_MSPI_HALT_SET_TRANSACTION_DONE 0x3b8
#endif /* SPI_BCM53XX_H */
...@@ -677,7 +677,6 @@ static struct platform_driver cdns_spi_driver = { ...@@ -677,7 +677,6 @@ static struct platform_driver cdns_spi_driver = {
.remove = cdns_spi_remove, .remove = cdns_spi_remove,
.driver = { .driver = {
.name = CDNS_SPI_NAME, .name = CDNS_SPI_NAME,
.owner = THIS_MODULE,
.of_match_table = cdns_spi_of_match, .of_match_table = cdns_spi_of_match,
.pm = &cdns_spi_dev_pm_ops, .pm = &cdns_spi_dev_pm_ops,
}, },
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
struct spi_clps711x_data { struct spi_clps711x_data {
void __iomem *syncio; void __iomem *syncio;
struct regmap *syscon; struct regmap *syscon;
struct regmap *syscon1;
struct clk *spi_clk; struct clk *spi_clk;
u8 *tx_buf; u8 *tx_buf;
...@@ -47,27 +46,6 @@ static int spi_clps711x_setup(struct spi_device *spi) ...@@ -47,27 +46,6 @@ static int spi_clps711x_setup(struct spi_device *spi)
return 0; return 0;
} }
static void spi_clps711x_setup_xfer(struct spi_device *spi,
struct spi_transfer *xfer)
{
struct spi_master *master = spi->master;
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
/* Setup SPI frequency divider */
if (xfer->speed_hz >= master->max_speed_hz)
regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3));
else if (xfer->speed_hz >= (master->max_speed_hz / 2))
regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2));
else if (xfer->speed_hz >= (master->max_speed_hz / 8))
regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1));
else
regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0));
}
static int spi_clps711x_prepare_message(struct spi_master *master, static int spi_clps711x_prepare_message(struct spi_master *master,
struct spi_message *msg) struct spi_message *msg)
{ {
...@@ -87,7 +65,7 @@ static int spi_clps711x_transfer_one(struct spi_master *master, ...@@ -87,7 +65,7 @@ static int spi_clps711x_transfer_one(struct spi_master *master,
struct spi_clps711x_data *hw = spi_master_get_devdata(master); struct spi_clps711x_data *hw = spi_master_get_devdata(master);
u8 data; u8 data;
spi_clps711x_setup_xfer(spi, xfer); clk_set_rate(hw->spi_clk, xfer->speed_hz ? : spi->max_speed_hz);
hw->len = xfer->len; hw->len = xfer->len;
hw->bpw = xfer->bits_per_word; hw->bpw = xfer->bits_per_word;
...@@ -176,13 +154,11 @@ static int spi_clps711x_probe(struct platform_device *pdev) ...@@ -176,13 +154,11 @@ static int spi_clps711x_probe(struct platform_device *pdev)
} }
} }
hw->spi_clk = devm_clk_get(&pdev->dev, "spi"); hw->spi_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(hw->spi_clk)) { if (IS_ERR(hw->spi_clk)) {
dev_err(&pdev->dev, "Can't get clocks\n");
ret = PTR_ERR(hw->spi_clk); ret = PTR_ERR(hw->spi_clk);
goto err_out; goto err_out;
} }
master->max_speed_hz = clk_get_rate(hw->spi_clk);
hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3"); hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
if (IS_ERR(hw->syscon)) { if (IS_ERR(hw->syscon)) {
...@@ -190,12 +166,6 @@ static int spi_clps711x_probe(struct platform_device *pdev) ...@@ -190,12 +166,6 @@ static int spi_clps711x_probe(struct platform_device *pdev)
goto err_out; goto err_out;
} }
hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1");
if (IS_ERR(hw->syscon1)) {
ret = PTR_ERR(hw->syscon1);
goto err_out;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hw->syncio = devm_ioremap_resource(&pdev->dev, res); hw->syncio = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->syncio)) { if (IS_ERR(hw->syncio)) {
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
/* SPIDAT1 (upper 16 bit defines) */ /* SPIDAT1 (upper 16 bit defines) */
#define SPIDAT1_CSHOLD_MASK BIT(12) #define SPIDAT1_CSHOLD_MASK BIT(12)
#define SPIDAT1_WDEL BIT(10)
/* SPIGCR1 */ /* SPIGCR1 */
#define SPIGCR1_CLKMOD_MASK BIT(1) #define SPIGCR1_CLKMOD_MASK BIT(1)
...@@ -167,8 +168,10 @@ static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *dspi) ...@@ -167,8 +168,10 @@ static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *dspi)
static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi) static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi)
{ {
u32 data = 0; u32 data = 0;
if (dspi->tx) { if (dspi->tx) {
const u8 *tx = dspi->tx; const u8 *tx = dspi->tx;
data = *tx++; data = *tx++;
dspi->tx = tx; dspi->tx = tx;
} }
...@@ -178,8 +181,10 @@ static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi) ...@@ -178,8 +181,10 @@ static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi)
static u32 davinci_spi_tx_buf_u16(struct davinci_spi *dspi) static u32 davinci_spi_tx_buf_u16(struct davinci_spi *dspi)
{ {
u32 data = 0; u32 data = 0;
if (dspi->tx) { if (dspi->tx) {
const u16 *tx = dspi->tx; const u16 *tx = dspi->tx;
data = *tx++; data = *tx++;
dspi->tx = tx; dspi->tx = tx;
} }
...@@ -209,6 +214,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) ...@@ -209,6 +214,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
{ {
struct davinci_spi *dspi; struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
struct davinci_spi_config *spicfg = spi->controller_data;
u8 chip_sel = spi->chip_select; u8 chip_sel = spi->chip_select;
u16 spidat1 = CS_DEFAULT; u16 spidat1 = CS_DEFAULT;
bool gpio_chipsel = false; bool gpio_chipsel = false;
...@@ -223,6 +229,10 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) ...@@ -223,6 +229,10 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
gpio = spi->cs_gpio; gpio = spi->cs_gpio;
} }
/* program delay transfers if tx_delay is non zero */
if (spicfg->wdelay)
spidat1 |= SPIDAT1_WDEL;
/* /*
* Board specific chip select logic decides the polarity and cs * Board specific chip select logic decides the polarity and cs
* line for the controller * line for the controller
...@@ -237,9 +247,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) ...@@ -237,9 +247,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
spidat1 |= SPIDAT1_CSHOLD_MASK; spidat1 |= SPIDAT1_CSHOLD_MASK;
spidat1 &= ~(0x1 << chip_sel); spidat1 &= ~(0x1 << chip_sel);
} }
iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
} }
iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
} }
/** /**
...@@ -285,7 +295,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, ...@@ -285,7 +295,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
int prescale; int prescale;
dspi = spi_master_get_devdata(spi->master); dspi = spi_master_get_devdata(spi->master);
spicfg = (struct davinci_spi_config *)spi->controller_data; spicfg = spi->controller_data;
if (!spicfg) if (!spicfg)
spicfg = &davinci_spi_default_cfg; spicfg = &davinci_spi_default_cfg;
...@@ -332,6 +342,14 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, ...@@ -332,6 +342,14 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
if (!(spi->mode & SPI_CPHA)) if (!(spi->mode & SPI_CPHA))
spifmt |= SPIFMT_PHASE_MASK; spifmt |= SPIFMT_PHASE_MASK;
/*
* Assume wdelay is used only on SPI peripherals that has this field
* in SPIFMTn register and when it's configured from board file or DT.
*/
if (spicfg->wdelay)
spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
& SPIFMT_WDELAY_MASK);
/* /*
* Version 1 hardware supports two basic SPI modes: * Version 1 hardware supports two basic SPI modes:
* - Standard SPI mode uses 4 pins, with chipselect * - Standard SPI mode uses 4 pins, with chipselect
...@@ -349,9 +367,6 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, ...@@ -349,9 +367,6 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
u32 delay = 0; u32 delay = 0;
spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
& SPIFMT_WDELAY_MASK);
if (spicfg->odd_parity) if (spicfg->odd_parity)
spifmt |= SPIFMT_ODD_PARITY_MASK; spifmt |= SPIFMT_ODD_PARITY_MASK;
...@@ -383,6 +398,26 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, ...@@ -383,6 +398,26 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
return 0; return 0;
} }
static int davinci_spi_of_setup(struct spi_device *spi)
{
struct davinci_spi_config *spicfg = spi->controller_data;
struct device_node *np = spi->dev.of_node;
u32 prop;
if (spicfg == NULL && np) {
spicfg = kzalloc(sizeof(*spicfg), GFP_KERNEL);
if (!spicfg)
return -ENOMEM;
*spicfg = davinci_spi_default_cfg;
/* override with dt configured values */
if (!of_property_read_u32(np, "ti,spi-wdelay", &prop))
spicfg->wdelay = (u8)prop;
spi->controller_data = spicfg;
}
return 0;
}
/** /**
* davinci_spi_setup - This functions will set default transfer method * davinci_spi_setup - This functions will set default transfer method
* @spi: spi device on which data transfer to be done * @spi: spi device on which data transfer to be done
...@@ -433,7 +468,16 @@ static int davinci_spi_setup(struct spi_device *spi) ...@@ -433,7 +468,16 @@ static int davinci_spi_setup(struct spi_device *spi)
else else
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK); clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);
return retval; return davinci_spi_of_setup(spi);
}
static void davinci_spi_cleanup(struct spi_device *spi)
{
struct davinci_spi_config *spicfg = spi->controller_data;
spi->controller_data = NULL;
if (spi->dev.of_node)
kfree(spicfg);
} }
static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
...@@ -947,6 +991,7 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -947,6 +991,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
master->num_chipselect = pdata->num_chipselect; master->num_chipselect = pdata->num_chipselect;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
master->setup = davinci_spi_setup; master->setup = davinci_spi_setup;
master->cleanup = davinci_spi_cleanup;
dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.chipselect = davinci_spi_chipselect;
dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
...@@ -996,8 +1041,8 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -996,8 +1041,8 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_clk; goto free_clk;
dev_info(&pdev->dev, "DMA: supported\n"); dev_info(&pdev->dev, "DMA: supported\n");
dev_info(&pdev->dev, "DMA: RX channel: %pa, TX channel: %pa, " dev_info(&pdev->dev, "DMA: RX channel: %pa, TX channel: %pa, event queue: %d\n",
"event queue: %d\n", &dma_rx_chan, &dma_tx_chan, &dma_rx_chan, &dma_tx_chan,
pdata->dma_event_q); pdata->dma_event_q);
} }
......
/* /*
* Special handling for DW core on Intel MID platform * Special handling for DW core on Intel MID platform
* *
* Copyright (c) 2009, Intel Corporation. * Copyright (c) 2009, 2014 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -11,10 +11,6 @@ ...@@ -11,10 +11,6 @@
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details. * more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
...@@ -39,22 +35,25 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param) ...@@ -39,22 +35,25 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
{ {
struct dw_spi *dws = param; struct dw_spi *dws = param;
return dws->dmac && (&dws->dmac->dev == chan->device->dev); return dws->dma_dev == chan->device->dev;
} }
static int mid_spi_dma_init(struct dw_spi *dws) static int mid_spi_dma_init(struct dw_spi *dws)
{ {
struct mid_dma *dw_dma = dws->dma_priv; struct mid_dma *dw_dma = dws->dma_priv;
struct pci_dev *dma_dev;
struct intel_mid_dma_slave *rxs, *txs; struct intel_mid_dma_slave *rxs, *txs;
dma_cap_mask_t mask; dma_cap_mask_t mask;
/* /*
* Get pci device for DMA controller, currently it could only * Get pci device for DMA controller, currently it could only
* be the DMA controller of either Moorestown or Medfield * be the DMA controller of Medfield
*/ */
dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL); dma_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
if (!dws->dmac) if (!dma_dev)
dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL); return -ENODEV;
dws->dma_dev = &dma_dev->dev;
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
...@@ -83,13 +82,18 @@ static int mid_spi_dma_init(struct dw_spi *dws) ...@@ -83,13 +82,18 @@ static int mid_spi_dma_init(struct dw_spi *dws)
free_rxchan: free_rxchan:
dma_release_channel(dws->rxchan); dma_release_channel(dws->rxchan);
err_exit: err_exit:
return -1; return -EBUSY;
} }
static void mid_spi_dma_exit(struct dw_spi *dws) static void mid_spi_dma_exit(struct dw_spi *dws)
{ {
if (!dws->dma_inited)
return;
dmaengine_terminate_all(dws->txchan);
dma_release_channel(dws->txchan); dma_release_channel(dws->txchan);
dmaengine_terminate_all(dws->rxchan);
dma_release_channel(dws->rxchan); dma_release_channel(dws->rxchan);
} }
...@@ -109,8 +113,7 @@ static void dw_spi_dma_done(void *arg) ...@@ -109,8 +113,7 @@ static void dw_spi_dma_done(void *arg)
static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
{ {
struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL; struct dma_async_tx_descriptor *txdesc, *rxdesc;
struct dma_chan *txchan, *rxchan;
struct dma_slave_config txconf, rxconf; struct dma_slave_config txconf, rxconf;
u16 dma_ctrl = 0; u16 dma_ctrl = 0;
...@@ -120,37 +123,34 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) ...@@ -120,37 +123,34 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
dw_writew(dws, DW_SPI_DMARDLR, 0xf); dw_writew(dws, DW_SPI_DMARDLR, 0xf);
dw_writew(dws, DW_SPI_DMATDLR, 0x10); dw_writew(dws, DW_SPI_DMATDLR, 0x10);
if (dws->tx_dma) if (dws->tx_dma)
dma_ctrl |= 0x2; dma_ctrl |= SPI_DMA_TDMAE;
if (dws->rx_dma) if (dws->rx_dma)
dma_ctrl |= 0x1; dma_ctrl |= SPI_DMA_RDMAE;
dw_writew(dws, DW_SPI_DMACR, dma_ctrl); dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
spi_enable_chip(dws, 1); spi_enable_chip(dws, 1);
} }
dws->dma_chan_done = 0; dws->dma_chan_done = 0;
txchan = dws->txchan;
rxchan = dws->rxchan;
/* 2. Prepare the TX dma transfer */ /* 2. Prepare the TX dma transfer */
txconf.direction = DMA_MEM_TO_DEV; txconf.direction = DMA_MEM_TO_DEV;
txconf.dst_addr = dws->dma_addr; txconf.dst_addr = dws->dma_addr;
txconf.dst_maxburst = LNW_DMA_MSIZE_16; txconf.dst_maxburst = LNW_DMA_MSIZE_16;
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; txconf.dst_addr_width = dws->dma_width;
txconf.device_fc = false; txconf.device_fc = false;
txchan->device->device_control(txchan, DMA_SLAVE_CONFIG, dmaengine_slave_config(dws->txchan, &txconf);
(unsigned long) &txconf);
memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl)); memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
dws->tx_sgl.dma_address = dws->tx_dma; dws->tx_sgl.dma_address = dws->tx_dma;
dws->tx_sgl.length = dws->len; dws->tx_sgl.length = dws->len;
txdesc = dmaengine_prep_slave_sg(txchan, txdesc = dmaengine_prep_slave_sg(dws->txchan,
&dws->tx_sgl, &dws->tx_sgl,
1, 1,
DMA_MEM_TO_DEV, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
txdesc->callback = dw_spi_dma_done; txdesc->callback = dw_spi_dma_done;
txdesc->callback_param = dws; txdesc->callback_param = dws;
...@@ -159,27 +159,30 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) ...@@ -159,27 +159,30 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
rxconf.src_addr = dws->dma_addr; rxconf.src_addr = dws->dma_addr;
rxconf.src_maxburst = LNW_DMA_MSIZE_16; rxconf.src_maxburst = LNW_DMA_MSIZE_16;
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; rxconf.src_addr_width = dws->dma_width;
rxconf.device_fc = false; rxconf.device_fc = false;
rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG, dmaengine_slave_config(dws->rxchan, &rxconf);
(unsigned long) &rxconf);
memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl)); memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
dws->rx_sgl.dma_address = dws->rx_dma; dws->rx_sgl.dma_address = dws->rx_dma;
dws->rx_sgl.length = dws->len; dws->rx_sgl.length = dws->len;
rxdesc = dmaengine_prep_slave_sg(rxchan, rxdesc = dmaengine_prep_slave_sg(dws->rxchan,
&dws->rx_sgl, &dws->rx_sgl,
1, 1,
DMA_DEV_TO_MEM, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
rxdesc->callback = dw_spi_dma_done; rxdesc->callback = dw_spi_dma_done;
rxdesc->callback_param = dws; rxdesc->callback_param = dws;
/* rx must be started before tx due to spi instinct */ /* rx must be started before tx due to spi instinct */
rxdesc->tx_submit(rxdesc); dmaengine_submit(rxdesc);
txdesc->tx_submit(txdesc); dma_async_issue_pending(dws->rxchan);
dmaengine_submit(txdesc);
dma_async_issue_pending(dws->txchan);
return 0; return 0;
} }
...@@ -190,7 +193,7 @@ static struct dw_spi_dma_ops mid_dma_ops = { ...@@ -190,7 +193,7 @@ static struct dw_spi_dma_ops mid_dma_ops = {
}; };
#endif #endif
/* Some specific info for SPI0 controller on Moorestown */ /* Some specific info for SPI0 controller on Intel MID */
/* HW info for MRST CLk Control Unit, one 32b reg */ /* HW info for MRST CLk Control Unit, one 32b reg */
#define MRST_SPI_CLK_BASE 100000000 /* 100m */ #define MRST_SPI_CLK_BASE 100000000 /* 100m */
......
/* /*
* PCI interface driver for DW SPI Core * PCI interface driver for DW SPI Core
* *
* Copyright (c) 2009, Intel Corporation. * Copyright (c) 2009, 2014 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -11,10 +11,6 @@ ...@@ -11,10 +11,6 @@
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details. * more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -32,17 +28,22 @@ struct dw_spi_pci { ...@@ -32,17 +28,22 @@ struct dw_spi_pci {
struct dw_spi dws; struct dw_spi dws;
}; };
static int spi_pci_probe(struct pci_dev *pdev, struct spi_pci_desc {
const struct pci_device_id *ent) int (*setup)(struct dw_spi *);
};
static struct spi_pci_desc spi_pci_mid_desc = {
.setup = dw_spi_mid_init,
};
static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
struct dw_spi_pci *dwpci; struct dw_spi_pci *dwpci;
struct dw_spi *dws; struct dw_spi *dws;
struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data;
int pci_bar = 0; int pci_bar = 0;
int ret; int ret;
dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
pdev->vendor, pdev->device);
ret = pcim_enable_device(pdev); ret = pcim_enable_device(pdev);
if (ret) if (ret)
return ret; return ret;
...@@ -58,7 +59,7 @@ static int spi_pci_probe(struct pci_dev *pdev, ...@@ -58,7 +59,7 @@ static int spi_pci_probe(struct pci_dev *pdev,
/* Get basic io resource and map it */ /* Get basic io resource and map it */
dws->paddr = pci_resource_start(pdev, pci_bar); dws->paddr = pci_resource_start(pdev, pci_bar);
ret = pcim_iomap_regions(pdev, 1, dev_name(&pdev->dev)); ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
if (ret) if (ret)
return ret; return ret;
...@@ -69,11 +70,11 @@ static int spi_pci_probe(struct pci_dev *pdev, ...@@ -69,11 +70,11 @@ static int spi_pci_probe(struct pci_dev *pdev,
dws->irq = pdev->irq; dws->irq = pdev->irq;
/* /*
* Specific handling for Intel MID paltforms, like dma setup, * Specific handling for paltforms, like dma setup,
* clock rate, FIFO depth. * clock rate, FIFO depth.
*/ */
if (pdev->device == 0x0800) { if (desc && desc->setup) {
ret = dw_spi_mid_init(dws); ret = desc->setup(dws);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -85,6 +86,9 @@ static int spi_pci_probe(struct pci_dev *pdev, ...@@ -85,6 +86,9 @@ static int spi_pci_probe(struct pci_dev *pdev,
/* PCI hook and SPI hook use the same drv data */ /* PCI hook and SPI hook use the same drv data */
pci_set_drvdata(pdev, dwpci); pci_set_drvdata(pdev, dwpci);
dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
pdev->vendor, pdev->device);
return 0; return 0;
} }
...@@ -95,41 +99,29 @@ static void spi_pci_remove(struct pci_dev *pdev) ...@@ -95,41 +99,29 @@ static void spi_pci_remove(struct pci_dev *pdev)
dw_spi_remove_host(&dwpci->dws); dw_spi_remove_host(&dwpci->dws);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int spi_suspend(struct pci_dev *pdev, pm_message_t state) static int spi_suspend(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev);
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
int ret;
ret = dw_spi_suspend_host(&dwpci->dws); return dw_spi_suspend_host(&dwpci->dws);
if (ret)
return ret;
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return ret;
} }
static int spi_resume(struct pci_dev *pdev) static int spi_resume(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev);
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
int ret;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
ret = pci_enable_device(pdev);
if (ret)
return ret;
return dw_spi_resume_host(&dwpci->dws); return dw_spi_resume_host(&dwpci->dws);
} }
#else
#define spi_suspend NULL
#define spi_resume NULL
#endif #endif
static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume);
static const struct pci_device_id pci_ids[] = { static const struct pci_device_id pci_ids[] = {
/* Intel MID platform SPI controller 0 */ /* Intel MID platform SPI controller 0 */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc},
{}, {},
}; };
...@@ -138,8 +130,9 @@ static struct pci_driver dw_spi_driver = { ...@@ -138,8 +130,9 @@ static struct pci_driver dw_spi_driver = {
.id_table = pci_ids, .id_table = pci_ids,
.probe = spi_pci_probe, .probe = spi_pci_probe,
.remove = spi_pci_remove, .remove = spi_pci_remove,
.suspend = spi_suspend, .driver = {
.resume = spi_resume, .pm = &dw_spi_pm_ops,
},
}; };
module_pci_driver(dw_spi_driver); module_pci_driver(dw_spi_driver);
......
...@@ -11,10 +11,6 @@ ...@@ -11,10 +11,6 @@
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details. * more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
...@@ -59,22 +55,20 @@ struct chip_data { ...@@ -59,22 +55,20 @@ struct chip_data {
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
#define SPI_REGS_BUFSIZE 1024 #define SPI_REGS_BUFSIZE 1024
static ssize_t spi_show_regs(struct file *file, char __user *user_buf, static ssize_t dw_spi_show_regs(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct dw_spi *dws; struct dw_spi *dws = file->private_data;
char *buf; char *buf;
u32 len = 0; u32 len = 0;
ssize_t ret; ssize_t ret;
dws = file->private_data;
buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL); buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL);
if (!buf) if (!buf)
return 0; return 0;
len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
"MRST SPI0 registers:\n"); "%s registers:\n", dev_name(&dws->master->dev));
len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
"=================================\n"); "=================================\n");
len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
...@@ -110,42 +104,41 @@ static ssize_t spi_show_regs(struct file *file, char __user *user_buf, ...@@ -110,42 +104,41 @@ static ssize_t spi_show_regs(struct file *file, char __user *user_buf,
len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
"=================================\n"); "=================================\n");
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf); kfree(buf);
return ret; return ret;
} }
static const struct file_operations mrst_spi_regs_ops = { static const struct file_operations dw_spi_regs_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = simple_open, .open = simple_open,
.read = spi_show_regs, .read = dw_spi_show_regs,
.llseek = default_llseek, .llseek = default_llseek,
}; };
static int mrst_spi_debugfs_init(struct dw_spi *dws) static int dw_spi_debugfs_init(struct dw_spi *dws)
{ {
dws->debugfs = debugfs_create_dir("mrst_spi", NULL); dws->debugfs = debugfs_create_dir("dw_spi", NULL);
if (!dws->debugfs) if (!dws->debugfs)
return -ENOMEM; return -ENOMEM;
debugfs_create_file("registers", S_IFREG | S_IRUGO, debugfs_create_file("registers", S_IFREG | S_IRUGO,
dws->debugfs, (void *)dws, &mrst_spi_regs_ops); dws->debugfs, (void *)dws, &dw_spi_regs_ops);
return 0; return 0;
} }
static void mrst_spi_debugfs_remove(struct dw_spi *dws) static void dw_spi_debugfs_remove(struct dw_spi *dws)
{ {
if (dws->debugfs) debugfs_remove_recursive(dws->debugfs);
debugfs_remove_recursive(dws->debugfs);
} }
#else #else
static inline int mrst_spi_debugfs_init(struct dw_spi *dws) static inline int dw_spi_debugfs_init(struct dw_spi *dws)
{ {
return 0; return 0;
} }
static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
{ {
} }
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
...@@ -177,7 +170,7 @@ static inline u32 rx_max(struct dw_spi *dws) ...@@ -177,7 +170,7 @@ static inline u32 rx_max(struct dw_spi *dws)
{ {
u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes; u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes;
return min(rx_left, (u32)dw_readw(dws, DW_SPI_RXFLR)); return min_t(u32, rx_left, dw_readw(dws, DW_SPI_RXFLR));
} }
static void dw_writer(struct dw_spi *dws) static void dw_writer(struct dw_spi *dws)
...@@ -228,8 +221,9 @@ static void *next_transfer(struct dw_spi *dws) ...@@ -228,8 +221,9 @@ static void *next_transfer(struct dw_spi *dws)
struct spi_transfer, struct spi_transfer,
transfer_list); transfer_list);
return RUNNING_STATE; return RUNNING_STATE;
} else }
return DONE_STATE;
return DONE_STATE;
} }
/* /*
...@@ -396,7 +390,7 @@ static void pump_transfers(unsigned long data) ...@@ -396,7 +390,7 @@ static void pump_transfers(unsigned long data)
goto early_exit; goto early_exit;
} }
/* Delay if requested at end of transfer*/ /* Delay if requested at end of transfer */
if (message->state == RUNNING_STATE) { if (message->state == RUNNING_STATE) {
previous = list_entry(transfer->transfer_list.prev, previous = list_entry(transfer->transfer_list.prev,
struct spi_transfer, struct spi_transfer,
...@@ -471,10 +465,12 @@ static void pump_transfers(unsigned long data) ...@@ -471,10 +465,12 @@ static void pump_transfers(unsigned long data)
*/ */
if (!dws->dma_mapped && !chip->poll_mode) { if (!dws->dma_mapped && !chip->poll_mode) {
int templen = dws->len / dws->n_bytes; int templen = dws->len / dws->n_bytes;
txint_level = dws->fifo_len / 2; txint_level = dws->fifo_len / 2;
txint_level = (templen > txint_level) ? txint_level : templen; txint_level = (templen > txint_level) ? txint_level : templen;
imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI; imask |= SPI_INT_TXEI | SPI_INT_TXOI |
SPI_INT_RXUI | SPI_INT_RXOI;
dws->transfer_handler = interrupt_transfer; dws->transfer_handler = interrupt_transfer;
} }
...@@ -515,7 +511,6 @@ static void pump_transfers(unsigned long data) ...@@ -515,7 +511,6 @@ static void pump_transfers(unsigned long data)
early_exit: early_exit:
giveback(dws); giveback(dws);
return;
} }
static int dw_spi_transfer_one_message(struct spi_master *master, static int dw_spi_transfer_one_message(struct spi_master *master,
...@@ -524,7 +519,7 @@ static int dw_spi_transfer_one_message(struct spi_master *master, ...@@ -524,7 +519,7 @@ static int dw_spi_transfer_one_message(struct spi_master *master,
struct dw_spi *dws = spi_master_get_devdata(master); struct dw_spi *dws = spi_master_get_devdata(master);
dws->cur_msg = msg; dws->cur_msg = msg;
/* Initial message state*/ /* Initial message state */
dws->cur_msg->state = START_STATE; dws->cur_msg->state = START_STATE;
dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
struct spi_transfer, struct spi_transfer,
...@@ -595,6 +590,9 @@ static int dw_spi_setup(struct spi_device *spi) ...@@ -595,6 +590,9 @@ static int dw_spi_setup(struct spi_device *spi)
| (spi->mode << SPI_MODE_OFFSET) | (spi->mode << SPI_MODE_OFFSET)
| (chip->tmode << SPI_TMOD_OFFSET); | (chip->tmode << SPI_TMOD_OFFSET);
if (spi->mode & SPI_LOOP)
chip->cr0 |= 1 << SPI_SRL_OFFSET;
if (gpio_is_valid(spi->cs_gpio)) { if (gpio_is_valid(spi->cs_gpio)) {
ret = gpio_direction_output(spi->cs_gpio, ret = gpio_direction_output(spi->cs_gpio,
!(spi->mode & SPI_CS_HIGH)); !(spi->mode & SPI_CS_HIGH));
...@@ -626,6 +624,7 @@ static void spi_hw_init(struct dw_spi *dws) ...@@ -626,6 +624,7 @@ static void spi_hw_init(struct dw_spi *dws)
*/ */
if (!dws->fifo_len) { if (!dws->fifo_len) {
u32 fifo; u32 fifo;
for (fifo = 2; fifo <= 257; fifo++) { for (fifo = 2; fifo <= 257; fifo++) {
dw_writew(dws, DW_SPI_TXFLTR, fifo); dw_writew(dws, DW_SPI_TXFLTR, fifo);
if (fifo != dw_readw(dws, DW_SPI_TXFLTR)) if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
...@@ -653,8 +652,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -653,8 +652,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
dws->prev_chip = NULL; dws->prev_chip = NULL;
dws->dma_inited = 0; dws->dma_inited = 0;
dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60); dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);
snprintf(dws->name, sizeof(dws->name), "dw_spi%d", snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num);
dws->bus_num);
ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED, ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED,
dws->name, dws); dws->name, dws);
...@@ -663,7 +661,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -663,7 +661,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
goto err_free_master; goto err_free_master;
} }
master->mode_bits = SPI_CPOL | SPI_CPHA; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->bus_num = dws->bus_num; master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs; master->num_chipselect = dws->num_cs;
...@@ -692,7 +690,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -692,7 +690,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
goto err_dma_exit; goto err_dma_exit;
} }
mrst_spi_debugfs_init(dws); dw_spi_debugfs_init(dws);
return 0; return 0;
err_dma_exit: err_dma_exit:
...@@ -709,7 +707,7 @@ void dw_spi_remove_host(struct dw_spi *dws) ...@@ -709,7 +707,7 @@ void dw_spi_remove_host(struct dw_spi *dws)
{ {
if (!dws) if (!dws)
return; return;
mrst_spi_debugfs_remove(dws); dw_spi_debugfs_remove(dws);
if (dws->dma_ops && dws->dma_ops->dma_exit) if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws); dws->dma_ops->dma_exit(dws);
......
...@@ -74,6 +74,10 @@ ...@@ -74,6 +74,10 @@
#define SPI_INT_RXFI (1 << 4) #define SPI_INT_RXFI (1 << 4)
#define SPI_INT_MSTI (1 << 5) #define SPI_INT_MSTI (1 << 5)
/* Bit fields in DMACR */
#define SPI_DMA_RDMAE (1 << 0)
#define SPI_DMA_TDMAE (1 << 1)
/* TX RX interrupt level threshold, max can be 256 */ /* TX RX interrupt level threshold, max can be 256 */
#define SPI_INT_THRESHOLD 32 #define SPI_INT_THRESHOLD 32
...@@ -140,7 +144,6 @@ struct dw_spi { ...@@ -140,7 +144,6 @@ struct dw_spi {
dma_addr_t dma_addr; /* phy address of the Data register */ dma_addr_t dma_addr; /* phy address of the Data register */
struct dw_spi_dma_ops *dma_ops; struct dw_spi_dma_ops *dma_ops;
void *dma_priv; /* platform relate info */ void *dma_priv; /* platform relate info */
struct pci_dev *dmac;
/* Bus interface info */ /* Bus interface info */
void *priv; void *priv;
...@@ -217,11 +220,11 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) ...@@ -217,11 +220,11 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
* Each SPI slave device to work with dw_api controller should * Each SPI slave device to work with dw_api controller should
* has such a structure claiming its working mode (PIO/DMA etc), * has such a structure claiming its working mode (PIO/DMA etc),
* which can be save in the "controller_data" member of the * which can be save in the "controller_data" member of the
* struct spi_device * struct spi_device.
*/ */
struct dw_spi_chip { struct dw_spi_chip {
u8 poll_mode; /* 0 for contoller polling mode */ u8 poll_mode; /* 1 for controller polling mode */
u8 type; /* SPI/SSP/Micrwire */ u8 type; /* SPI/SSP/MicroWire */
u8 enable_dma; u8 enable_dma;
void (*cs_control)(u32 command); void (*cs_control)(u32 command);
}; };
......
...@@ -266,6 +266,7 @@ static int ep93xx_spi_setup(struct spi_device *spi) ...@@ -266,6 +266,7 @@ static int ep93xx_spi_setup(struct spi_device *spi)
if (chip->ops && chip->ops->setup) { if (chip->ops && chip->ops->setup) {
int ret = chip->ops->setup(spi); int ret = chip->ops->setup(spi);
if (ret) { if (ret) {
kfree(chip); kfree(chip);
return ret; return ret;
......
...@@ -15,17 +15,17 @@ ...@@ -15,17 +15,17 @@
* Free Software Foundation; either version 2 of the License, or (at your * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * option) any later version.
*/ */
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/fsl_devices.h>
#include <linux/dma-mapping.h>
#include <linux/of_address.h>
#include <asm/cpm.h> #include <asm/cpm.h>
#include <asm/qe.h> #include <asm/qe.h>
#include <linux/dma-mapping.h>
#include <linux/fsl_devices.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#include "spi-fsl-lib.h"
#include "spi-fsl-cpm.h" #include "spi-fsl-cpm.h"
#include "spi-fsl-lib.h"
#include "spi-fsl-spi.h" #include "spi-fsl-spi.h"
/* CPM1 and CPM2 are mutually exclusive. */ /* CPM1 and CPM2 are mutually exclusive. */
......
...@@ -13,22 +13,22 @@ ...@@ -13,22 +13,22 @@
* *
*/ */
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/of.h>
#include <linux/errno.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_bitbang.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
#define DRIVER_NAME "fsl-dspi" #define DRIVER_NAME "fsl-dspi"
...@@ -493,9 +493,6 @@ static int dspi_probe(struct platform_device *pdev) ...@@ -493,9 +493,6 @@ static int dspi_probe(struct platform_device *pdev)
} }
dspi_regmap_config.lock_arg = dspi; dspi_regmap_config.lock_arg = dspi;
dspi_regmap_config.val_format_endian =
of_property_read_bool(np, "big-endian")
? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base, dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
&dspi_regmap_config); &dspi_regmap_config);
if (IS_ERR(dspi->regmap)) { if (IS_ERR(dspi->regmap)) {
...@@ -535,7 +532,6 @@ static int dspi_probe(struct platform_device *pdev) ...@@ -535,7 +532,6 @@ static int dspi_probe(struct platform_device *pdev)
goto out_clk_put; goto out_clk_put;
} }
pr_info(KERN_INFO "Freescale DSPI master initialized\n");
return ret; return ret;
out_clk_put: out_clk_put:
......
...@@ -8,19 +8,19 @@ ...@@ -8,19 +8,19 @@
* Free Software Foundation; either version 2 of the License, or (at your * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * option) any later version.
*/ */
#include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/irq.h> #include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h> #include <linux/fsl_devices.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/interrupt.h> #include <linux/platform_device.h>
#include <linux/err.h> #include <linux/spi/spi.h>
#include <sysdev/fsl_soc.h> #include <sysdev/fsl_soc.h>
#include "spi-fsl-lib.h" #include "spi-fsl-lib.h"
......
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
* Free Software Foundation; either version 2 of the License, or (at your * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * option) any later version.
*/ */
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/fsl_devices.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/fsl_devices.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
......
...@@ -19,25 +19,25 @@ ...@@ -19,25 +19,25 @@
* Free Software Foundation; either version 2 of the License, or (at your * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * option) any later version.
*/ */
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/irq.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/fsl_devices.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/types.h>
#include "spi-fsl-lib.h" #include "spi-fsl-lib.h"
#include "spi-fsl-cpm.h" #include "spi-fsl-cpm.h"
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,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/dmaengine.h>
#include <linux/dma-mapping.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>
...@@ -37,6 +39,7 @@ ...@@ -37,6 +39,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/platform_data/dma-imx.h>
#include <linux/platform_data/spi-imx.h> #include <linux/platform_data/spi-imx.h>
#define DRIVER_NAME "spi_imx" #define DRIVER_NAME "spi_imx"
...@@ -51,6 +54,9 @@ ...@@ -51,6 +54,9 @@
#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */ #define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */
#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */ #define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */
/* The maximum bytes that a sdma BD can transfer.*/
#define MAX_SDMA_BD_BYTES (1 << 15)
#define IMX_DMA_TIMEOUT (msecs_to_jiffies(3000))
struct spi_imx_config { struct spi_imx_config {
unsigned int speed_hz; unsigned int speed_hz;
unsigned int bpw; unsigned int bpw;
...@@ -95,6 +101,16 @@ struct spi_imx_data { ...@@ -95,6 +101,16 @@ struct spi_imx_data {
const void *tx_buf; const void *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */ unsigned int txfifo; /* number of words pushed in tx FIFO */
/* DMA */
unsigned int dma_is_inited;
unsigned int dma_finished;
bool usedma;
u32 rx_wml;
u32 tx_wml;
u32 rxt_wml;
struct completion dma_rx_completion;
struct completion dma_tx_completion;
const struct spi_imx_devtype_data *devtype_data; const struct spi_imx_devtype_data *devtype_data;
int chipselect[0]; int chipselect[0];
}; };
...@@ -181,9 +197,21 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, ...@@ -181,9 +197,21 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
return 7; return 7;
} }
static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
if (spi_imx->dma_is_inited && (transfer->len > spi_imx->rx_wml)
&& (transfer->len > spi_imx->tx_wml))
return true;
return false;
}
#define MX51_ECSPI_CTRL 0x08 #define MX51_ECSPI_CTRL 0x08
#define MX51_ECSPI_CTRL_ENABLE (1 << 0) #define MX51_ECSPI_CTRL_ENABLE (1 << 0)
#define MX51_ECSPI_CTRL_XCH (1 << 2) #define MX51_ECSPI_CTRL_XCH (1 << 2)
#define MX51_ECSPI_CTRL_SMC (1 << 3)
#define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4) #define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4)
#define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8 #define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8
#define MX51_ECSPI_CTRL_PREDIV_OFFSET 12 #define MX51_ECSPI_CTRL_PREDIV_OFFSET 12
...@@ -201,6 +229,18 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, ...@@ -201,6 +229,18 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
#define MX51_ECSPI_INT_TEEN (1 << 0) #define MX51_ECSPI_INT_TEEN (1 << 0)
#define MX51_ECSPI_INT_RREN (1 << 3) #define MX51_ECSPI_INT_RREN (1 << 3)
#define MX51_ECSPI_DMA 0x14
#define MX51_ECSPI_DMA_TX_WML_OFFSET 0
#define MX51_ECSPI_DMA_TX_WML_MASK 0x3F
#define MX51_ECSPI_DMA_RX_WML_OFFSET 16
#define MX51_ECSPI_DMA_RX_WML_MASK (0x3F << 16)
#define MX51_ECSPI_DMA_RXT_WML_OFFSET 24
#define MX51_ECSPI_DMA_RXT_WML_MASK (0x3F << 24)
#define MX51_ECSPI_DMA_TEDEN_OFFSET 7
#define MX51_ECSPI_DMA_RXDEN_OFFSET 23
#define MX51_ECSPI_DMA_RXTDEN_OFFSET 31
#define MX51_ECSPI_STAT 0x18 #define MX51_ECSPI_STAT 0x18
#define MX51_ECSPI_STAT_RR (1 << 3) #define MX51_ECSPI_STAT_RR (1 << 3)
...@@ -257,17 +297,22 @@ static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int ...@@ -257,17 +297,22 @@ static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int
static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx) static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
{ {
u32 reg; u32 reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
reg = readl(spi_imx->base + MX51_ECSPI_CTRL); if (!spi_imx->usedma)
reg |= MX51_ECSPI_CTRL_XCH; reg |= MX51_ECSPI_CTRL_XCH;
else if (!spi_imx->dma_finished)
reg |= MX51_ECSPI_CTRL_SMC;
else
reg &= ~MX51_ECSPI_CTRL_SMC;
writel(reg, spi_imx->base + MX51_ECSPI_CTRL); writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
} }
static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config) struct spi_imx_config *config)
{ {
u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0; u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0, dma = 0;
u32 tx_wml_cfg, rx_wml_cfg, rxt_wml_cfg;
u32 clk = config->speed_hz, delay; u32 clk = config->speed_hz, delay;
/* /*
...@@ -319,6 +364,30 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, ...@@ -319,6 +364,30 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
else /* SCLK is _very_ slow */ else /* SCLK is _very_ slow */
usleep_range(delay, delay + 10); usleep_range(delay, delay + 10);
/*
* Configure the DMA register: setup the watermark
* and enable DMA request.
*/
if (spi_imx->dma_is_inited) {
dma = readl(spi_imx->base + MX51_ECSPI_DMA);
spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2;
spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2;
spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2;
rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
rxt_wml_cfg = spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET;
dma = (dma & ~MX51_ECSPI_DMA_TX_WML_MASK
& ~MX51_ECSPI_DMA_RX_WML_MASK
& ~MX51_ECSPI_DMA_RXT_WML_MASK)
| rx_wml_cfg | tx_wml_cfg | rxt_wml_cfg
|(1 << MX51_ECSPI_DMA_TEDEN_OFFSET)
|(1 << MX51_ECSPI_DMA_RXDEN_OFFSET)
|(1 << MX51_ECSPI_DMA_RXTDEN_OFFSET);
writel(dma, spi_imx->base + MX51_ECSPI_DMA);
}
return 0; return 0;
} }
...@@ -730,7 +799,186 @@ static int spi_imx_setupxfer(struct spi_device *spi, ...@@ -730,7 +799,186 @@ static int spi_imx_setupxfer(struct spi_device *spi,
return 0; return 0;
} }
static int spi_imx_transfer(struct spi_device *spi, static void spi_imx_sdma_exit(struct spi_imx_data *spi_imx)
{
struct spi_master *master = spi_imx->bitbang.master;
if (master->dma_rx) {
dma_release_channel(master->dma_rx);
master->dma_rx = NULL;
}
if (master->dma_tx) {
dma_release_channel(master->dma_tx);
master->dma_tx = NULL;
}
spi_imx->dma_is_inited = 0;
}
static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
struct spi_master *master,
const struct resource *res)
{
struct dma_slave_config slave_config = {};
int ret;
/* Prepare for TX DMA: */
master->dma_tx = dma_request_slave_channel(dev, "tx");
if (!master->dma_tx) {
dev_err(dev, "cannot get the TX DMA channel!\n");
ret = -EINVAL;
goto err;
}
slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_addr = res->start + MXC_CSPITXDATA;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
slave_config.dst_maxburst = spi_imx_get_fifosize(spi_imx) / 2;
ret = dmaengine_slave_config(master->dma_tx, &slave_config);
if (ret) {
dev_err(dev, "error in TX dma configuration.\n");
goto err;
}
/* Prepare for RX : */
master->dma_rx = dma_request_slave_channel(dev, "rx");
if (!master->dma_rx) {
dev_dbg(dev, "cannot get the DMA channel.\n");
ret = -EINVAL;
goto err;
}
slave_config.direction = DMA_DEV_TO_MEM;
slave_config.src_addr = res->start + MXC_CSPIRXDATA;
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
slave_config.src_maxburst = spi_imx_get_fifosize(spi_imx) / 2;
ret = dmaengine_slave_config(master->dma_rx, &slave_config);
if (ret) {
dev_err(dev, "error in RX dma configuration.\n");
goto err;
}
init_completion(&spi_imx->dma_rx_completion);
init_completion(&spi_imx->dma_tx_completion);
master->can_dma = spi_imx_can_dma;
master->max_dma_len = MAX_SDMA_BD_BYTES;
spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX |
SPI_MASTER_MUST_TX;
spi_imx->dma_is_inited = 1;
return 0;
err:
spi_imx_sdma_exit(spi_imx);
return ret;
}
static void spi_imx_dma_rx_callback(void *cookie)
{
struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie;
complete(&spi_imx->dma_rx_completion);
}
static void spi_imx_dma_tx_callback(void *cookie)
{
struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie;
complete(&spi_imx->dma_tx_completion);
}
static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
struct spi_transfer *transfer)
{
struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
int ret;
u32 dma;
int left;
struct spi_master *master = spi_imx->bitbang.master;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
if (tx) {
desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
tx->sgl, tx->nents, DMA_TO_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx)
goto no_dma;
desc_tx->callback = spi_imx_dma_tx_callback;
desc_tx->callback_param = (void *)spi_imx;
dmaengine_submit(desc_tx);
}
if (rx) {
desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
rx->sgl, rx->nents, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx)
goto no_dma;
desc_rx->callback = spi_imx_dma_rx_callback;
desc_rx->callback_param = (void *)spi_imx;
dmaengine_submit(desc_rx);
}
reinit_completion(&spi_imx->dma_rx_completion);
reinit_completion(&spi_imx->dma_tx_completion);
/* Trigger the cspi module. */
spi_imx->dma_finished = 0;
dma = readl(spi_imx->base + MX51_ECSPI_DMA);
dma = dma & (~MX51_ECSPI_DMA_RXT_WML_MASK);
/* Change RX_DMA_LENGTH trigger dma fetch tail data */
left = transfer->len % spi_imx->rxt_wml;
if (left)
writel(dma | (left << MX51_ECSPI_DMA_RXT_WML_OFFSET),
spi_imx->base + MX51_ECSPI_DMA);
spi_imx->devtype_data->trigger(spi_imx);
dma_async_issue_pending(master->dma_tx);
dma_async_issue_pending(master->dma_rx);
/* Wait SDMA to finish the data transfer.*/
ret = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
IMX_DMA_TIMEOUT);
if (!ret) {
pr_warn("%s %s: I/O Error in DMA TX\n",
dev_driver_string(&master->dev),
dev_name(&master->dev));
dmaengine_terminate_all(master->dma_tx);
} else {
ret = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
IMX_DMA_TIMEOUT);
if (!ret) {
pr_warn("%s %s: I/O Error in DMA RX\n",
dev_driver_string(&master->dev),
dev_name(&master->dev));
spi_imx->devtype_data->reset(spi_imx);
dmaengine_terminate_all(master->dma_rx);
}
writel(dma |
spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
spi_imx->base + MX51_ECSPI_DMA);
}
spi_imx->dma_finished = 1;
spi_imx->devtype_data->trigger(spi_imx);
if (!ret)
ret = -ETIMEDOUT;
else if (ret > 0)
ret = transfer->len;
return ret;
no_dma:
pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
dev_driver_string(&master->dev),
dev_name(&master->dev));
return -EAGAIN;
}
static int spi_imx_pio_transfer(struct spi_device *spi,
struct spi_transfer *transfer) struct spi_transfer *transfer)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
...@@ -751,6 +999,24 @@ static int spi_imx_transfer(struct spi_device *spi, ...@@ -751,6 +999,24 @@ static int spi_imx_transfer(struct spi_device *spi,
return transfer->len; return transfer->len;
} }
static int spi_imx_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
int ret;
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
if (spi_imx->bitbang.master->can_dma &&
spi_imx_can_dma(spi_imx->bitbang.master, spi, transfer)) {
spi_imx->usedma = true;
ret = spi_imx_dma_transfer(spi_imx, transfer);
if (ret != -EAGAIN)
return ret;
}
spi_imx->usedma = false;
return spi_imx_pio_transfer(spi, transfer);
}
static int spi_imx_setup(struct spi_device *spi) static int spi_imx_setup(struct spi_device *spi)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
...@@ -911,6 +1177,13 @@ static int spi_imx_probe(struct platform_device *pdev) ...@@ -911,6 +1177,13 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_put_per; goto out_put_per;
spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per); spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per);
/*
* Only validated on i.mx6 now, can remove the constrain if validated on
* other chips.
*/
if (spi_imx->devtype_data == &imx51_ecspi_devtype_data
&& spi_imx_sdma_init(&pdev->dev, spi_imx, master, res))
dev_err(&pdev->dev, "dma setup error,use pio instead\n");
spi_imx->devtype_data->reset(spi_imx); spi_imx->devtype_data->reset(spi_imx);
...@@ -949,6 +1222,7 @@ static int spi_imx_remove(struct platform_device *pdev) ...@@ -949,6 +1222,7 @@ static int spi_imx_remove(struct platform_device *pdev)
writel(0, spi_imx->base + MXC_CSPICTRL); writel(0, spi_imx->base + MXC_CSPICTRL);
clk_unprepare(spi_imx->clk_ipg); clk_unprepare(spi_imx->clk_ipg);
clk_unprepare(spi_imx->clk_per); clk_unprepare(spi_imx->clk_per);
spi_imx_sdma_exit(spi_imx);
spi_master_put(master); spi_master_put(master);
return 0; return 0;
......
...@@ -85,7 +85,7 @@ static int mxs_spi_setup_transfer(struct spi_device *dev, ...@@ -85,7 +85,7 @@ static int mxs_spi_setup_transfer(struct spi_device *dev,
mxs_ssp_set_clk_rate(ssp, hz); mxs_ssp_set_clk_rate(ssp, hz);
/* /*
* Save requested rate, hz, rather than the actual rate, * Save requested rate, hz, rather than the actual rate,
* ssp->clk_rate. Otherwise we would set the rate every trasfer * ssp->clk_rate. Otherwise we would set the rate every transfer
* when the actual rate is not quite the same as requested rate. * when the actual rate is not quite the same as requested rate.
*/ */
spi->sck = hz; spi->sck = hz;
...@@ -154,12 +154,14 @@ static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set) ...@@ -154,12 +154,14 @@ static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set)
static void mxs_ssp_dma_irq_callback(void *param) static void mxs_ssp_dma_irq_callback(void *param)
{ {
struct mxs_spi *spi = param; struct mxs_spi *spi = param;
complete(&spi->c); complete(&spi->c);
} }
static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id) static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id)
{ {
struct mxs_ssp *ssp = dev_id; struct mxs_ssp *ssp = dev_id;
dev_err(ssp->dev, "%s[%i] CTRL1=%08x STATUS=%08x\n", dev_err(ssp->dev, "%s[%i] CTRL1=%08x STATUS=%08x\n",
__func__, __LINE__, __func__, __LINE__,
readl(ssp->base + HW_SSP_CTRL1(ssp)), readl(ssp->base + HW_SSP_CTRL1(ssp)),
...@@ -189,7 +191,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, ...@@ -189,7 +191,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
if (!len) if (!len)
return -EINVAL; return -EINVAL;
dma_xfer = kzalloc(sizeof(*dma_xfer) * sgs, GFP_KERNEL); dma_xfer = kcalloc(sgs, sizeof(*dma_xfer), GFP_KERNEL);
if (!dma_xfer) if (!dma_xfer)
return -ENOMEM; return -ENOMEM;
......
...@@ -70,10 +70,6 @@ ...@@ -70,10 +70,6 @@
#define SPI_STATUS_WE (1UL << 1) #define SPI_STATUS_WE (1UL << 1)
#define SPI_STATUS_RD (1UL << 0) #define SPI_STATUS_RD (1UL << 0)
#define WRITE 0
#define READ 1
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
* cache operations; better heuristics consider wordsize and bitrate. * cache operations; better heuristics consider wordsize and bitrate.
*/ */
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -40,13 +41,27 @@ ...@@ -40,13 +41,27 @@
#define ORION_SPI_MODE_CPHA (1 << 12) #define ORION_SPI_MODE_CPHA (1 << 12)
#define ORION_SPI_IF_8_16_BIT_MODE (1 << 5) #define ORION_SPI_IF_8_16_BIT_MODE (1 << 5)
#define ORION_SPI_CLK_PRESCALE_MASK 0x1F #define ORION_SPI_CLK_PRESCALE_MASK 0x1F
#define ARMADA_SPI_CLK_PRESCALE_MASK 0xDF
#define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \ #define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \
ORION_SPI_MODE_CPHA) ORION_SPI_MODE_CPHA)
enum orion_spi_type {
ORION_SPI,
ARMADA_SPI,
};
struct orion_spi_dev {
enum orion_spi_type typ;
unsigned int min_divisor;
unsigned int max_divisor;
u32 prescale_mask;
};
struct orion_spi { struct orion_spi {
struct spi_master *master; struct spi_master *master;
void __iomem *base; void __iomem *base;
struct clk *clk; struct clk *clk;
const struct orion_spi_dev *devdata;
}; };
static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
...@@ -83,30 +98,66 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) ...@@ -83,30 +98,66 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
u32 prescale; u32 prescale;
u32 reg; u32 reg;
struct orion_spi *orion_spi; struct orion_spi *orion_spi;
const struct orion_spi_dev *devdata;
orion_spi = spi_master_get_devdata(spi->master); orion_spi = spi_master_get_devdata(spi->master);
devdata = orion_spi->devdata;
tclk_hz = clk_get_rate(orion_spi->clk); tclk_hz = clk_get_rate(orion_spi->clk);
/* if (devdata->typ == ARMADA_SPI) {
* the supported rates are: 4,6,8...30 unsigned int clk, spr, sppr, sppr2, err;
* round up as we look for equal or less speed unsigned int best_spr, best_sppr, best_err;
*/
rate = DIV_ROUND_UP(tclk_hz, speed);
rate = roundup(rate, 2);
/* check if requested speed is too small */ best_err = speed;
if (rate > 30) best_spr = 0;
return -EINVAL; best_sppr = 0;
if (rate < 4) /* Iterate over the valid range looking for best fit */
rate = 4; for (sppr = 0; sppr < 8; sppr++) {
sppr2 = 0x1 << sppr;
spr = tclk_hz / sppr2;
spr = DIV_ROUND_UP(spr, speed);
if ((spr == 0) || (spr > 15))
continue;
clk = tclk_hz / (spr * sppr2);
err = speed - clk;
if (err < best_err) {
best_spr = spr;
best_sppr = sppr;
best_err = err;
}
}
/* Convert the rate to SPI clock divisor value. */ if ((best_sppr == 0) && (best_spr == 0))
prescale = 0x10 + rate/2; return -EINVAL;
prescale = ((best_sppr & 0x6) << 5) |
((best_sppr & 0x1) << 4) | best_spr;
} else {
/*
* the supported rates are: 4,6,8...30
* round up as we look for equal or less speed
*/
rate = DIV_ROUND_UP(tclk_hz, speed);
rate = roundup(rate, 2);
/* check if requested speed is too small */
if (rate > 30)
return -EINVAL;
if (rate < 4)
rate = 4;
/* Convert the rate to SPI clock divisor value. */
prescale = 0x10 + rate/2;
}
reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
reg = ((reg & ~ORION_SPI_CLK_PRESCALE_MASK) | prescale); reg = ((reg & ~devdata->prescale_mask) | prescale);
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
return 0; return 0;
...@@ -179,8 +230,8 @@ static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi) ...@@ -179,8 +230,8 @@ static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi)
for (i = 0; i < ORION_SPI_WAIT_RDY_MAX_LOOP; i++) { for (i = 0; i < ORION_SPI_WAIT_RDY_MAX_LOOP; i++) {
if (readl(spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG))) if (readl(spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG)))
return 1; return 1;
else
udelay(1); udelay(1);
} }
return -1; return -1;
...@@ -342,8 +393,31 @@ static int orion_spi_reset(struct orion_spi *orion_spi) ...@@ -342,8 +393,31 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
return 0; return 0;
} }
static const struct orion_spi_dev orion_spi_dev_data = {
.typ = ORION_SPI,
.min_divisor = 4,
.max_divisor = 30,
.prescale_mask = ORION_SPI_CLK_PRESCALE_MASK,
};
static const struct orion_spi_dev armada_spi_dev_data = {
.typ = ARMADA_SPI,
.min_divisor = 1,
.max_divisor = 1920,
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
};
static const struct of_device_id orion_spi_of_match_table[] = {
{ .compatible = "marvell,orion-spi", .data = &orion_spi_dev_data, },
{ .compatible = "marvell,armada-370-spi", .data = &armada_spi_dev_data, },
{}
};
MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
static int orion_spi_probe(struct platform_device *pdev) static int orion_spi_probe(struct platform_device *pdev)
{ {
const struct of_device_id *of_id;
const struct orion_spi_dev *devdata;
struct spi_master *master; struct spi_master *master;
struct orion_spi *spi; struct orion_spi *spi;
struct resource *r; struct resource *r;
...@@ -360,6 +434,7 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -360,6 +434,7 @@ static int orion_spi_probe(struct platform_device *pdev)
master->bus_num = pdev->id; master->bus_num = pdev->id;
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
u32 cell_index; u32 cell_index;
if (!of_property_read_u32(pdev->dev.of_node, "cell-index", if (!of_property_read_u32(pdev->dev.of_node, "cell-index",
&cell_index)) &cell_index))
master->bus_num = cell_index; master->bus_num = cell_index;
...@@ -378,6 +453,10 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -378,6 +453,10 @@ static int orion_spi_probe(struct platform_device *pdev)
spi = spi_master_get_devdata(master); spi = spi_master_get_devdata(master);
spi->master = master; spi->master = master;
of_id = of_match_device(orion_spi_of_match_table, &pdev->dev);
devdata = of_id->data;
spi->devdata = devdata;
spi->clk = devm_clk_get(&pdev->dev, NULL); spi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(spi->clk)) { if (IS_ERR(spi->clk)) {
status = PTR_ERR(spi->clk); status = PTR_ERR(spi->clk);
...@@ -389,8 +468,8 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -389,8 +468,8 @@ static int orion_spi_probe(struct platform_device *pdev)
goto out; goto out;
tclk_hz = clk_get_rate(spi->clk); tclk_hz = clk_get_rate(spi->clk);
master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4); master->max_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->min_divisor);
master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30); master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi->base = devm_ioremap_resource(&pdev->dev, r); spi->base = devm_ioremap_resource(&pdev->dev, r);
...@@ -469,12 +548,6 @@ static const struct dev_pm_ops orion_spi_pm_ops = { ...@@ -469,12 +548,6 @@ static const struct dev_pm_ops orion_spi_pm_ops = {
NULL) NULL)
}; };
static const struct of_device_id orion_spi_of_match_table[] = {
{ .compatible = "marvell,orion-spi", },
{}
};
MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
static struct platform_driver orion_spi_driver = { static struct platform_driver orion_spi_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
......
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
#define SSP_MIS(r) (r + 0x01C) #define SSP_MIS(r) (r + 0x01C)
#define SSP_ICR(r) (r + 0x020) #define SSP_ICR(r) (r + 0x020)
#define SSP_DMACR(r) (r + 0x024) #define SSP_DMACR(r) (r + 0x024)
#define SSP_CSR(r) (r + 0x030) /* vendor extension */
#define SSP_ITCR(r) (r + 0x080) #define SSP_ITCR(r) (r + 0x080)
#define SSP_ITIP(r) (r + 0x084) #define SSP_ITIP(r) (r + 0x084)
#define SSP_ITOP(r) (r + 0x088) #define SSP_ITOP(r) (r + 0x088)
...@@ -197,6 +198,12 @@ ...@@ -197,6 +198,12 @@
/* Transmit DMA Enable bit */ /* Transmit DMA Enable bit */
#define SSP_DMACR_MASK_TXDMAE (0x1UL << 1) #define SSP_DMACR_MASK_TXDMAE (0x1UL << 1)
/*
* SSP Chip Select Control Register - SSP_CSR
* (vendor extension)
*/
#define SSP_CSR_CSVALUE_MASK (0x1FUL << 0)
/* /*
* SSP Integration Test control Register - SSP_ITCR * SSP Integration Test control Register - SSP_ITCR
*/ */
...@@ -313,6 +320,7 @@ enum ssp_writing { ...@@ -313,6 +320,7 @@ enum ssp_writing {
* @extended_cr: 32 bit wide control register 0 with extra * @extended_cr: 32 bit wide control register 0 with extra
* features and extra features in CR1 as found in the ST variants * features and extra features in CR1 as found in the ST variants
* @pl023: supports a subset of the ST extensions called "PL023" * @pl023: supports a subset of the ST extensions called "PL023"
* @internal_cs_ctrl: supports chip select control register
*/ */
struct vendor_data { struct vendor_data {
int fifodepth; int fifodepth;
...@@ -321,6 +329,7 @@ struct vendor_data { ...@@ -321,6 +329,7 @@ struct vendor_data {
bool extended_cr; bool extended_cr;
bool pl023; bool pl023;
bool loopback; bool loopback;
bool internal_cs_ctrl;
}; };
/** /**
...@@ -440,9 +449,32 @@ static void null_cs_control(u32 command) ...@@ -440,9 +449,32 @@ static void null_cs_control(u32 command)
pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); pr_debug("pl022: dummy chip select control, CS=0x%x\n", command);
} }
/**
* internal_cs_control - Control chip select signals via SSP_CSR.
* @pl022: SSP driver private data structure
* @command: select/delect the chip
*
* Used on controller with internal chip select control via SSP_CSR register
* (vendor extension). Each of the 5 LSB in the register controls one chip
* select signal.
*/
static void internal_cs_control(struct pl022 *pl022, u32 command)
{
u32 tmp;
tmp = readw(SSP_CSR(pl022->virtbase));
if (command == SSP_CHIP_SELECT)
tmp &= ~BIT(pl022->cur_cs);
else
tmp |= BIT(pl022->cur_cs);
writew(tmp, SSP_CSR(pl022->virtbase));
}
static void pl022_cs_control(struct pl022 *pl022, u32 command) static void pl022_cs_control(struct pl022 *pl022, u32 command)
{ {
if (gpio_is_valid(pl022->cur_cs)) if (pl022->vendor->internal_cs_ctrl)
internal_cs_control(pl022, command);
else if (gpio_is_valid(pl022->cur_cs))
gpio_set_value(pl022->cur_cs, command); gpio_set_value(pl022->cur_cs, command);
else else
pl022->cur_chip->cs_control(command); pl022->cur_chip->cs_control(command);
...@@ -2100,6 +2132,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2100,6 +2132,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
pl022->vendor = id->data; pl022->vendor = id->data;
pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int), pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
GFP_KERNEL); GFP_KERNEL);
if (!pl022->chipselects) {
status = -ENOMEM;
goto err_no_mem;
}
/* /*
* Bus Number Which has been Assigned to this SSP controller * Bus Number Which has been Assigned to this SSP controller
...@@ -2118,6 +2154,9 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2118,6 +2154,9 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
if (platform_info->num_chipselect && platform_info->chipselects) { if (platform_info->num_chipselect && platform_info->chipselects) {
for (i = 0; i < num_cs; i++) for (i = 0; i < num_cs; i++)
pl022->chipselects[i] = platform_info->chipselects[i]; pl022->chipselects[i] = platform_info->chipselects[i];
} else if (pl022->vendor->internal_cs_ctrl) {
for (i = 0; i < num_cs; i++)
pl022->chipselects[i] = i;
} else if (IS_ENABLED(CONFIG_OF)) { } else if (IS_ENABLED(CONFIG_OF)) {
for (i = 0; i < num_cs; i++) { for (i = 0; i < num_cs; i++) {
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
...@@ -2241,6 +2280,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2241,6 +2280,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
amba_release_regions(adev); amba_release_regions(adev);
err_no_ioregion: err_no_ioregion:
err_no_gpio: err_no_gpio:
err_no_mem:
spi_master_put(master); spi_master_put(master);
return status; return status;
} }
...@@ -2347,6 +2387,7 @@ static struct vendor_data vendor_arm = { ...@@ -2347,6 +2387,7 @@ static struct vendor_data vendor_arm = {
.extended_cr = false, .extended_cr = false,
.pl023 = false, .pl023 = false,
.loopback = true, .loopback = true,
.internal_cs_ctrl = false,
}; };
static struct vendor_data vendor_st = { static struct vendor_data vendor_st = {
...@@ -2356,6 +2397,7 @@ static struct vendor_data vendor_st = { ...@@ -2356,6 +2397,7 @@ static struct vendor_data vendor_st = {
.extended_cr = true, .extended_cr = true,
.pl023 = false, .pl023 = false,
.loopback = true, .loopback = true,
.internal_cs_ctrl = false,
}; };
static struct vendor_data vendor_st_pl023 = { static struct vendor_data vendor_st_pl023 = {
...@@ -2365,6 +2407,17 @@ static struct vendor_data vendor_st_pl023 = { ...@@ -2365,6 +2407,17 @@ static struct vendor_data vendor_st_pl023 = {
.extended_cr = true, .extended_cr = true,
.pl023 = true, .pl023 = true,
.loopback = false, .loopback = false,
.internal_cs_ctrl = false,
};
static struct vendor_data vendor_lsi = {
.fifodepth = 8,
.max_bpw = 16,
.unidir = false,
.extended_cr = false,
.pl023 = false,
.loopback = true,
.internal_cs_ctrl = true,
}; };
static struct amba_id pl022_ids[] = { static struct amba_id pl022_ids[] = {
...@@ -2398,6 +2451,15 @@ static struct amba_id pl022_ids[] = { ...@@ -2398,6 +2451,15 @@ static struct amba_id pl022_ids[] = {
.mask = 0xffffffff, .mask = 0xffffffff,
.data = &vendor_st_pl023, .data = &vendor_st_pl023,
}, },
{
/*
* PL022 variant that has a chip select control register whih
* allows control of 5 output signals nCS[0:4].
*/
.id = 0x000b6022,
.mask = 0x000fffff,
.data = &vendor_lsi,
},
{ 0, 0 }, { 0, 0 },
}; };
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
enum { enum {
PORT_CE4100, PORT_CE4100,
...@@ -21,6 +23,7 @@ struct pxa_spi_info { ...@@ -21,6 +23,7 @@ struct pxa_spi_info {
int tx_chan_id; int tx_chan_id;
int rx_slave_id; int rx_slave_id;
int rx_chan_id; int rx_chan_id;
unsigned long max_clk_rate;
}; };
static struct pxa_spi_info spi_info_configs[] = { static struct pxa_spi_info spi_info_configs[] = {
...@@ -32,6 +35,7 @@ static struct pxa_spi_info spi_info_configs[] = { ...@@ -32,6 +35,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.tx_chan_id = -1, .tx_chan_id = -1,
.rx_slave_id = -1, .rx_slave_id = -1,
.rx_chan_id = -1, .rx_chan_id = -1,
.max_clk_rate = 3686400,
}, },
[PORT_BYT] = { [PORT_BYT] = {
.type = LPSS_SSP, .type = LPSS_SSP,
...@@ -41,6 +45,7 @@ static struct pxa_spi_info spi_info_configs[] = { ...@@ -41,6 +45,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.tx_chan_id = 0, .tx_chan_id = 0,
.rx_slave_id = 1, .rx_slave_id = 1,
.rx_chan_id = 1, .rx_chan_id = 1,
.max_clk_rate = 50000000,
}, },
}; };
...@@ -53,6 +58,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -53,6 +58,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
struct pxa2xx_spi_master spi_pdata; struct pxa2xx_spi_master spi_pdata;
struct ssp_device *ssp; struct ssp_device *ssp;
struct pxa_spi_info *c; struct pxa_spi_info *c;
char buf[40];
ret = pcim_enable_device(dev); ret = pcim_enable_device(dev);
if (ret) if (ret)
...@@ -84,6 +90,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -84,6 +90,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn; ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
ssp->type = c->type; ssp->type = c->type;
snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id);
ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL,
CLK_IS_ROOT, c->max_clk_rate);
if (IS_ERR(ssp->clk))
return PTR_ERR(ssp->clk);
memset(&pi, 0, sizeof(pi)); memset(&pi, 0, sizeof(pi));
pi.parent = &dev->dev; pi.parent = &dev->dev;
pi.name = "pxa2xx-spi"; pi.name = "pxa2xx-spi";
...@@ -92,8 +104,10 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -92,8 +104,10 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
pi.size_data = sizeof(spi_pdata); pi.size_data = sizeof(spi_pdata);
pdev = platform_device_register_full(&pi); pdev = platform_device_register_full(&pi);
if (IS_ERR(pdev)) if (IS_ERR(pdev)) {
clk_unregister(ssp->clk);
return PTR_ERR(pdev); return PTR_ERR(pdev);
}
pci_set_drvdata(dev, pdev); pci_set_drvdata(dev, pdev);
...@@ -103,8 +117,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -103,8 +117,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
static void pxa2xx_spi_pci_remove(struct pci_dev *dev) static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
{ {
struct platform_device *pdev = pci_get_drvdata(dev); struct platform_device *pdev = pci_get_drvdata(dev);
struct pxa2xx_spi_master *spi_pdata;
spi_pdata = dev_get_platdata(&pdev->dev);
platform_device_unregister(pdev); platform_device_unregister(pdev);
clk_unregister(spi_pdata->ssp.clk);
} }
static const struct pci_device_id pxa2xx_spi_pci_devices[] = { static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
......
...@@ -415,7 +415,7 @@ static void rockchip_spi_dma_txcb(void *data) ...@@ -415,7 +415,7 @@ static void rockchip_spi_dma_txcb(void *data)
spin_unlock_irqrestore(&rs->lock, flags); spin_unlock_irqrestore(&rs->lock, flags);
} }
static int rockchip_spi_dma_transfer(struct rockchip_spi *rs) static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
{ {
unsigned long flags; unsigned long flags;
struct dma_slave_config rxconf, txconf; struct dma_slave_config rxconf, txconf;
...@@ -474,8 +474,6 @@ static int rockchip_spi_dma_transfer(struct rockchip_spi *rs) ...@@ -474,8 +474,6 @@ static int rockchip_spi_dma_transfer(struct rockchip_spi *rs)
dmaengine_submit(txdesc); dmaengine_submit(txdesc);
dma_async_issue_pending(rs->dma_tx.ch); dma_async_issue_pending(rs->dma_tx.ch);
} }
return 1;
} }
static void rockchip_spi_config(struct rockchip_spi *rs) static void rockchip_spi_config(struct rockchip_spi *rs)
...@@ -557,16 +555,17 @@ static int rockchip_spi_transfer_one( ...@@ -557,16 +555,17 @@ static int rockchip_spi_transfer_one(
else if (rs->rx) else if (rs->rx)
rs->tmode = CR0_XFM_RO; rs->tmode = CR0_XFM_RO;
if (master->can_dma && master->can_dma(master, spi, xfer)) /* we need prepare dma before spi was enabled */
if (master->can_dma && master->can_dma(master, spi, xfer)) {
rs->use_dma = 1; rs->use_dma = 1;
else rockchip_spi_prepare_dma(rs);
} else {
rs->use_dma = 0; rs->use_dma = 0;
}
rockchip_spi_config(rs); rockchip_spi_config(rs);
if (rs->use_dma) if (!rs->use_dma)
ret = rockchip_spi_dma_transfer(rs);
else
ret = rockchip_spi_pio_transfer(rs); ret = rockchip_spi_pio_transfer(rs);
return ret; return ret;
......
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
/* RSPI on SH only */ /* RSPI on SH only */
#define SPCR_TXMD 0x02 /* TX Only Mode (vs. Full Duplex) */ #define SPCR_TXMD 0x02 /* TX Only Mode (vs. Full Duplex) */
#define SPCR_SPMS 0x01 /* 3-wire Mode (vs. 4-wire) */ #define SPCR_SPMS 0x01 /* 3-wire Mode (vs. 4-wire) */
/* QSPI on R-Car M2 only */ /* QSPI on R-Car Gen2 only */
#define SPCR_WSWAP 0x02 /* Word Swap of read-data for DMAC */ #define SPCR_WSWAP 0x02 /* Word Swap of read-data for DMAC */
#define SPCR_BSWAP 0x01 /* Byte Swap of read-data for DMAC */ #define SPCR_BSWAP 0x01 /* Byte Swap of read-data for DMAC */
...@@ -909,20 +909,24 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev, ...@@ -909,20 +909,24 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev,
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
chan = dma_request_channel(mask, shdma_chan_filter, chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
(void *)(unsigned long)id); (void *)(unsigned long)id, dev,
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) { if (!chan) {
dev_warn(dev, "dma_request_channel failed\n"); dev_warn(dev, "dma_request_slave_channel_compat failed\n");
return NULL; return NULL;
} }
memset(&cfg, 0, sizeof(cfg)); memset(&cfg, 0, sizeof(cfg));
cfg.slave_id = id; cfg.slave_id = id;
cfg.direction = dir; cfg.direction = dir;
if (dir == DMA_MEM_TO_DEV) if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = port_addr; cfg.dst_addr = port_addr;
else cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
} else {
cfg.src_addr = port_addr; cfg.src_addr = port_addr;
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
}
ret = dmaengine_slave_config(chan, &cfg); ret = dmaengine_slave_config(chan, &cfg);
if (ret) { if (ret) {
...@@ -938,22 +942,30 @@ static int rspi_request_dma(struct device *dev, struct spi_master *master, ...@@ -938,22 +942,30 @@ static int rspi_request_dma(struct device *dev, struct spi_master *master,
const struct resource *res) const struct resource *res)
{ {
const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev); const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev);
unsigned int dma_tx_id, dma_rx_id;
if (dev->of_node) {
/* In the OF case we will get the slave IDs from the DT */
dma_tx_id = 0;
dma_rx_id = 0;
} else if (rspi_pd && rspi_pd->dma_tx_id && rspi_pd->dma_rx_id) {
dma_tx_id = rspi_pd->dma_tx_id;
dma_rx_id = rspi_pd->dma_rx_id;
} else {
/* The driver assumes no error. */
return 0;
}
if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id) master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, dma_tx_id,
return 0; /* The driver assumes no error. */
master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM,
rspi_pd->dma_rx_id,
res->start + RSPI_SPDR); res->start + RSPI_SPDR);
if (!master->dma_rx) if (!master->dma_tx)
return -ENODEV; return -ENODEV;
master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, dma_rx_id,
rspi_pd->dma_tx_id,
res->start + RSPI_SPDR); res->start + RSPI_SPDR);
if (!master->dma_tx) { if (!master->dma_rx) {
dma_release_channel(master->dma_rx); dma_release_channel(master->dma_tx);
master->dma_rx = NULL; master->dma_tx = NULL;
return -ENODEV; return -ENODEV;
} }
...@@ -1046,12 +1058,11 @@ static int rspi_request_irq(struct device *dev, unsigned int irq, ...@@ -1046,12 +1058,11 @@ static int rspi_request_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, const char *suffix, irq_handler_t handler, const char *suffix,
void *dev_id) void *dev_id)
{ {
const char *base = dev_name(dev); const char *name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s",
size_t len = strlen(base) + strlen(suffix) + 2; dev_name(dev), suffix);
char *name = devm_kzalloc(dev, len, GFP_KERNEL);
if (!name) if (!name)
return -ENOMEM; return -ENOMEM;
snprintf(name, len, "%s:%s", base, suffix);
return devm_request_irq(dev, irq, handler, 0, name, dev_id); return devm_request_irq(dev, irq, handler, 0, name, dev_id);
} }
...@@ -1084,7 +1095,7 @@ static int rspi_probe(struct platform_device *pdev) ...@@ -1084,7 +1095,7 @@ static int rspi_probe(struct platform_device *pdev)
master->num_chipselect = rspi_pd->num_chipselect; master->num_chipselect = rspi_pd->num_chipselect;
else else
master->num_chipselect = 2; /* default */ master->num_chipselect = 2; /* default */
}; }
/* ops parameter check */ /* ops parameter check */
if (!ops->set_config_register) { if (!ops->set_config_register) {
......
...@@ -642,18 +642,14 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, ...@@ -642,18 +642,14 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx, desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
p->rx_dma_addr, len, DMA_FROM_DEVICE, p->rx_dma_addr, len, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx) { if (!desc_rx)
ret = -EAGAIN; return -EAGAIN;
goto no_dma_rx;
}
desc_rx->callback = sh_msiof_dma_complete; desc_rx->callback = sh_msiof_dma_complete;
desc_rx->callback_param = p; desc_rx->callback_param = p;
cookie = dmaengine_submit(desc_rx); cookie = dmaengine_submit(desc_rx);
if (dma_submit_error(cookie)) { if (dma_submit_error(cookie))
ret = cookie; return cookie;
goto no_dma_rx;
}
} }
if (tx) { if (tx) {
...@@ -738,7 +734,6 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, ...@@ -738,7 +734,6 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
if (rx) if (rx)
dmaengine_terminate_all(p->master->dma_rx); dmaengine_terminate_all(p->master->dma_rx);
sh_msiof_write(p, IER, 0); sh_msiof_write(p, IER, 0);
no_dma_rx:
return ret; return ret;
} }
...@@ -933,6 +928,9 @@ static const struct of_device_id sh_msiof_match[] = { ...@@ -933,6 +928,9 @@ static const struct of_device_id sh_msiof_match[] = {
{ .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
{ .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7792", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7793", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7794", .data = &r8a779x_data },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, sh_msiof_match); MODULE_DEVICE_TABLE(of, sh_msiof_match);
...@@ -977,20 +975,24 @@ static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev, ...@@ -977,20 +975,24 @@ static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev,
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
chan = dma_request_channel(mask, shdma_chan_filter, chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
(void *)(unsigned long)id); (void *)(unsigned long)id, dev,
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) { if (!chan) {
dev_warn(dev, "dma_request_channel failed\n"); dev_warn(dev, "dma_request_slave_channel_compat failed\n");
return NULL; return NULL;
} }
memset(&cfg, 0, sizeof(cfg)); memset(&cfg, 0, sizeof(cfg));
cfg.slave_id = id; cfg.slave_id = id;
cfg.direction = dir; cfg.direction = dir;
if (dir == DMA_MEM_TO_DEV) if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = port_addr; cfg.dst_addr = port_addr;
else cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
} else {
cfg.src_addr = port_addr; cfg.src_addr = port_addr;
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
}
ret = dmaengine_slave_config(chan, &cfg); ret = dmaengine_slave_config(chan, &cfg);
if (ret) { if (ret) {
...@@ -1007,12 +1009,22 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p) ...@@ -1007,12 +1009,22 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
struct platform_device *pdev = p->pdev; struct platform_device *pdev = p->pdev;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct sh_msiof_spi_info *info = dev_get_platdata(dev); const struct sh_msiof_spi_info *info = dev_get_platdata(dev);
unsigned int dma_tx_id, dma_rx_id;
const struct resource *res; const struct resource *res;
struct spi_master *master; struct spi_master *master;
struct device *tx_dev, *rx_dev; struct device *tx_dev, *rx_dev;
if (!info || !info->dma_tx_id || !info->dma_rx_id) if (dev->of_node) {
return 0; /* The driver assumes no error */ /* In the OF case we will get the slave IDs from the DT */
dma_tx_id = 0;
dma_rx_id = 0;
} else if (info && info->dma_tx_id && info->dma_rx_id) {
dma_tx_id = info->dma_tx_id;
dma_rx_id = info->dma_rx_id;
} else {
/* The driver assumes no error */
return 0;
}
/* The DMA engine uses the second register set, if present */ /* The DMA engine uses the second register set, if present */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
...@@ -1021,13 +1033,13 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p) ...@@ -1021,13 +1033,13 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
master = p->master; master = p->master;
master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV, master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV,
info->dma_tx_id, dma_tx_id,
res->start + TFDR); res->start + TFDR);
if (!master->dma_tx) if (!master->dma_tx)
return -ENODEV; return -ENODEV;
master->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM, master->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM,
info->dma_rx_id, dma_rx_id,
res->start + RFDR); res->start + RFDR);
if (!master->dma_rx) if (!master->dma_rx)
goto free_tx_chan; goto free_tx_chan;
...@@ -1210,6 +1222,9 @@ static struct platform_device_id spi_driver_ids[] = { ...@@ -1210,6 +1222,9 @@ static struct platform_device_id spi_driver_ids[] = {
{ "spi_sh_msiof", (kernel_ulong_t)&sh_data }, { "spi_sh_msiof", (kernel_ulong_t)&sh_data },
{ "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data }, { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data }, { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7792_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7793_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7794_msiof", (kernel_ulong_t)&r8a779x_data },
{}, {},
}; };
MODULE_DEVICE_TABLE(platform, spi_driver_ids); MODULE_DEVICE_TABLE(platform, spi_driver_ids);
......
...@@ -62,15 +62,15 @@ ...@@ -62,15 +62,15 @@
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_12 (1 << 26) #define SIRFSOC_SPI_TRAN_DAT_FORMAT_12 (1 << 26)
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_16 (2 << 26) #define SIRFSOC_SPI_TRAN_DAT_FORMAT_16 (2 << 26)
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_32 (3 << 26) #define SIRFSOC_SPI_TRAN_DAT_FORMAT_32 (3 << 26)
#define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28) #define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28)
#define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30) #define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30)
#define SIRFSOC_SPI_MUL_DAT_MODE BIT(31) #define SIRFSOC_SPI_MUL_DAT_MODE BIT(31)
/* Interrupt Enable */ /* Interrupt Enable */
#define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0) #define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0)
#define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1) #define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1)
#define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2) #define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2)
#define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3) #define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3)
#define SIRFSOC_SPI_RX_IO_DMA_INT_EN BIT(4) #define SIRFSOC_SPI_RX_IO_DMA_INT_EN BIT(4)
#define SIRFSOC_SPI_TX_IO_DMA_INT_EN BIT(5) #define SIRFSOC_SPI_TX_IO_DMA_INT_EN BIT(5)
#define SIRFSOC_SPI_RXFIFO_FULL_INT_EN BIT(6) #define SIRFSOC_SPI_RXFIFO_FULL_INT_EN BIT(6)
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
#define SIRFSOC_SPI_TXFIFO_THD_INT_EN BIT(9) #define SIRFSOC_SPI_TXFIFO_THD_INT_EN BIT(9)
#define SIRFSOC_SPI_FRM_END_INT_EN BIT(10) #define SIRFSOC_SPI_FRM_END_INT_EN BIT(10)
#define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF #define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF
/* Interrupt status */ /* Interrupt status */
#define SIRFSOC_SPI_RX_DONE BIT(0) #define SIRFSOC_SPI_RX_DONE BIT(0)
...@@ -170,8 +170,7 @@ struct sirfsoc_spi { ...@@ -170,8 +170,7 @@ struct sirfsoc_spi {
* command model * command model
*/ */
bool tx_by_cmd; bool tx_by_cmd;
bool hw_cs;
int chipselect[0];
}; };
static void spi_sirfsoc_rx_word_u8(struct sirfsoc_spi *sspi) static void spi_sirfsoc_rx_word_u8(struct sirfsoc_spi *sspi)
...@@ -304,7 +303,7 @@ static void spi_sirfsoc_dma_fini_callback(void *data) ...@@ -304,7 +303,7 @@ static void spi_sirfsoc_dma_fini_callback(void *data)
complete(dma_complete); complete(dma_complete);
} }
static int spi_sirfsoc_cmd_transfer(struct spi_device *spi, static void spi_sirfsoc_cmd_transfer(struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
{ {
struct sirfsoc_spi *sspi; struct sirfsoc_spi *sspi;
...@@ -328,10 +327,9 @@ static int spi_sirfsoc_cmd_transfer(struct spi_device *spi, ...@@ -328,10 +327,9 @@ static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
sspi->base + SIRFSOC_SPI_TX_RX_EN); sspi->base + SIRFSOC_SPI_TX_RX_EN);
if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
dev_err(&spi->dev, "cmd transfer timeout\n"); dev_err(&spi->dev, "cmd transfer timeout\n");
return 0; return;
} }
sspi->left_rx_word -= t->len;
return t->len;
} }
static void spi_sirfsoc_dma_transfer(struct spi_device *spi, static void spi_sirfsoc_dma_transfer(struct spi_device *spi,
...@@ -487,7 +485,7 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value) ...@@ -487,7 +485,7 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
{ {
struct sirfsoc_spi *sspi = spi_master_get_devdata(spi->master); struct sirfsoc_spi *sspi = spi_master_get_devdata(spi->master);
if (sspi->chipselect[spi->chip_select] == 0) { if (sspi->hw_cs) {
u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL); u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL);
switch (value) { switch (value) {
case BITBANG_CS_ACTIVE: case BITBANG_CS_ACTIVE:
...@@ -505,14 +503,13 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value) ...@@ -505,14 +503,13 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
} }
writel(regval, sspi->base + SIRFSOC_SPI_CTRL); writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
} else { } else {
int gpio = sspi->chipselect[spi->chip_select];
switch (value) { switch (value) {
case BITBANG_CS_ACTIVE: case BITBANG_CS_ACTIVE:
gpio_direction_output(gpio, gpio_direction_output(spi->cs_gpio,
spi->mode & SPI_CS_HIGH ? 1 : 0); spi->mode & SPI_CS_HIGH ? 1 : 0);
break; break;
case BITBANG_CS_INACTIVE: case BITBANG_CS_INACTIVE:
gpio_direction_output(gpio, gpio_direction_output(spi->cs_gpio,
spi->mode & SPI_CS_HIGH ? 0 : 1); spi->mode & SPI_CS_HIGH ? 0 : 1);
break; break;
} }
...@@ -606,8 +603,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -606,8 +603,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
sspi->tx_by_cmd = false; sspi->tx_by_cmd = false;
} }
/* /*
* set spi controller in RISC chipselect mode, we are controlling CS by * it should never set to hardware cs mode because in hardware cs mode,
* software BITBANG_CS_ACTIVE and BITBANG_CS_INACTIVE. * cs signal can't controlled by driver.
*/ */
regval |= SIRFSOC_SPI_CS_IO_MODE; regval |= SIRFSOC_SPI_CS_IO_MODE;
writel(regval, sspi->base + SIRFSOC_SPI_CTRL); writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
...@@ -630,9 +627,17 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -630,9 +627,17 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static int spi_sirfsoc_setup(struct spi_device *spi) static int spi_sirfsoc_setup(struct spi_device *spi)
{ {
struct sirfsoc_spi *sspi;
if (!spi->max_speed_hz) if (!spi->max_speed_hz)
return -EINVAL; return -EINVAL;
sspi = spi_master_get_devdata(spi->master);
if (spi->cs_gpio == -ENOENT)
sspi->hw_cs = true;
else
sspi->hw_cs = false;
return spi_sirfsoc_setup_transfer(spi, NULL); return spi_sirfsoc_setup_transfer(spi, NULL);
} }
...@@ -641,19 +646,10 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ...@@ -641,19 +646,10 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct sirfsoc_spi *sspi; struct sirfsoc_spi *sspi;
struct spi_master *master; struct spi_master *master;
struct resource *mem_res; struct resource *mem_res;
int num_cs, cs_gpio, irq; int irq;
int i; int i, ret;
int ret;
ret = of_property_read_u32(pdev->dev.of_node,
"sirf,spi-num-chipselects", &num_cs);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to get chip select number\n");
goto err_cs;
}
master = spi_alloc_master(&pdev->dev, master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
sizeof(*sspi) + sizeof(int) * num_cs);
if (!master) { if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI master\n"); dev_err(&pdev->dev, "Unable to allocate SPI master\n");
return -ENOMEM; return -ENOMEM;
...@@ -661,32 +657,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ...@@ -661,32 +657,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master); sspi = spi_master_get_devdata(master);
master->num_chipselect = num_cs;
for (i = 0; i < master->num_chipselect; i++) {
cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i);
if (cs_gpio < 0) {
dev_err(&pdev->dev, "can't get cs gpio from DT\n");
ret = -ENODEV;
goto free_master;
}
sspi->chipselect[i] = cs_gpio;
if (cs_gpio == 0)
continue; /* use cs from spi controller */
ret = gpio_request(cs_gpio, DRIVER_NAME);
if (ret) {
while (i > 0) {
i--;
if (sspi->chipselect[i] > 0)
gpio_free(sspi->chipselect[i]);
}
dev_err(&pdev->dev, "fail to request cs gpios\n");
goto free_master;
}
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sspi->base = devm_ioremap_resource(&pdev->dev, mem_res); sspi->base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sspi->base)) { if (IS_ERR(sspi->base)) {
...@@ -756,7 +726,21 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ...@@ -756,7 +726,21 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
ret = spi_bitbang_start(&sspi->bitbang); ret = spi_bitbang_start(&sspi->bitbang);
if (ret) if (ret)
goto free_dummypage; goto free_dummypage;
for (i = 0; master->cs_gpios && i < master->num_chipselect; i++) {
if (master->cs_gpios[i] == -ENOENT)
continue;
if (!gpio_is_valid(master->cs_gpios[i])) {
dev_err(&pdev->dev, "no valid gpio\n");
ret = -EINVAL;
goto free_dummypage;
}
ret = devm_gpio_request(&pdev->dev,
master->cs_gpios[i], DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev, "failed to request gpio\n");
goto free_dummypage;
}
}
dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num); dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num);
return 0; return 0;
...@@ -771,7 +755,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ...@@ -771,7 +755,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
dma_release_channel(sspi->rx_chan); dma_release_channel(sspi->rx_chan);
free_master: free_master:
spi_master_put(master); spi_master_put(master);
err_cs:
return ret; return ret;
} }
...@@ -779,16 +763,11 @@ static int spi_sirfsoc_remove(struct platform_device *pdev) ...@@ -779,16 +763,11 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
{ {
struct spi_master *master; struct spi_master *master;
struct sirfsoc_spi *sspi; struct sirfsoc_spi *sspi;
int i;
master = platform_get_drvdata(pdev); master = platform_get_drvdata(pdev);
sspi = spi_master_get_devdata(master); sspi = spi_master_get_devdata(master);
spi_bitbang_stop(&sspi->bitbang); spi_bitbang_stop(&sspi->bitbang);
for (i = 0; i < master->num_chipselect; i++) {
if (sspi->chipselect[i] > 0)
gpio_free(sspi->chipselect[i]);
}
kfree(sspi->dummypage); kfree(sspi->dummypage);
clk_disable_unprepare(sspi->clk); clk_disable_unprepare(sspi->clk);
clk_put(sspi->clk); clk_put(sspi->clk);
......
...@@ -302,6 +302,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( ...@@ -302,6 +302,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
max_n_32bit = DIV_ROUND_UP(nbytes, 4); max_n_32bit = DIV_ROUND_UP(nbytes, 4);
for (count = 0; count < max_n_32bit; count++) { for (count = 0; count < max_n_32bit; count++) {
u32 x = 0; u32 x = 0;
for (i = 0; (i < 4) && nbytes; i++, nbytes--) for (i = 0; (i < 4) && nbytes; i++, nbytes--)
x |= (u32)(*tx_buf++) << (i * 8); x |= (u32)(*tx_buf++) << (i * 8);
tegra_spi_writel(tspi, x, SPI_TX_FIFO); tegra_spi_writel(tspi, x, SPI_TX_FIFO);
...@@ -312,6 +313,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( ...@@ -312,6 +313,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
nbytes = written_words * tspi->bytes_per_word; nbytes = written_words * tspi->bytes_per_word;
for (count = 0; count < max_n_32bit; count++) { for (count = 0; count < max_n_32bit; count++) {
u32 x = 0; u32 x = 0;
for (i = 0; nbytes && (i < tspi->bytes_per_word); for (i = 0; nbytes && (i < tspi->bytes_per_word);
i++, nbytes--) i++, nbytes--)
x |= (u32)(*tx_buf++) << (i * 8); x |= (u32)(*tx_buf++) << (i * 8);
...@@ -338,6 +340,7 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( ...@@ -338,6 +340,7 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf(
len = tspi->curr_dma_words * tspi->bytes_per_word; len = tspi->curr_dma_words * tspi->bytes_per_word;
for (count = 0; count < rx_full_count; count++) { for (count = 0; count < rx_full_count; count++) {
u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO); u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO);
for (i = 0; len && (i < 4); i++, len--) for (i = 0; len && (i < 4); i++, len--)
*rx_buf++ = (x >> i*8) & 0xFF; *rx_buf++ = (x >> i*8) & 0xFF;
} }
...@@ -345,8 +348,10 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( ...@@ -345,8 +348,10 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf(
read_words += tspi->curr_dma_words; read_words += tspi->curr_dma_words;
} else { } else {
u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; u32 rx_mask = ((u32)1 << t->bits_per_word) - 1;
for (count = 0; count < rx_full_count; count++) { for (count = 0; count < rx_full_count; count++) {
u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask; u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask;
for (i = 0; (i < tspi->bytes_per_word); i++) for (i = 0; (i < tspi->bytes_per_word); i++)
*rx_buf++ = (x >> (i*8)) & 0xFF; *rx_buf++ = (x >> (i*8)) & 0xFF;
} }
...@@ -365,6 +370,7 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( ...@@ -365,6 +370,7 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf(
if (tspi->is_packed) { if (tspi->is_packed) {
unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; unsigned len = tspi->curr_dma_words * tspi->bytes_per_word;
memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len); memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len);
} else { } else {
unsigned int i; unsigned int i;
...@@ -374,6 +380,7 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( ...@@ -374,6 +380,7 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf(
for (count = 0; count < tspi->curr_dma_words; count++) { for (count = 0; count < tspi->curr_dma_words; count++) {
u32 x = 0; u32 x = 0;
for (i = 0; consume && (i < tspi->bytes_per_word); for (i = 0; consume && (i < tspi->bytes_per_word);
i++, consume--) i++, consume--)
x |= (u32)(*tx_buf++) << (i * 8); x |= (u32)(*tx_buf++) << (i * 8);
...@@ -396,6 +403,7 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf( ...@@ -396,6 +403,7 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf(
if (tspi->is_packed) { if (tspi->is_packed) {
unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; unsigned len = tspi->curr_dma_words * tspi->bytes_per_word;
memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len); memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len);
} else { } else {
unsigned int i; unsigned int i;
...@@ -405,6 +413,7 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf( ...@@ -405,6 +413,7 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf(
for (count = 0; count < tspi->curr_dma_words; count++) { for (count = 0; count < tspi->curr_dma_words; count++) {
u32 x = tspi->rx_dma_buf[count] & rx_mask; u32 x = tspi->rx_dma_buf[count] & rx_mask;
for (i = 0; (i < tspi->bytes_per_word); i++) for (i = 0; (i < tspi->bytes_per_word); i++)
*rx_buf++ = (x >> (i*8)) & 0xFF; *rx_buf++ = (x >> (i*8)) & 0xFF;
} }
......
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
#define SPI_TX_TRIG_MASK (0x3 << 16) #define SPI_TX_TRIG_MASK (0x3 << 16)
#define SPI_TX_TRIG_1W (0x0 << 16) #define SPI_TX_TRIG_1W (0x0 << 16)
#define SPI_TX_TRIG_4W (0x1 << 16) #define SPI_TX_TRIG_4W (0x1 << 16)
#define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF); #define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF)
#define SPI_TX_FIFO 0x10 #define SPI_TX_FIFO 0x10
#define SPI_RX_FIFO 0x20 #define SPI_RX_FIFO 0x20
...@@ -221,6 +221,7 @@ static int tegra_sflash_read_rx_fifo_to_client_rxbuf( ...@@ -221,6 +221,7 @@ static int tegra_sflash_read_rx_fifo_to_client_rxbuf(
while (!(status & SPI_RXF_EMPTY)) { while (!(status & SPI_RXF_EMPTY)) {
int i; int i;
u32 x = tegra_sflash_readl(tsd, SPI_RX_FIFO); u32 x = tegra_sflash_readl(tsd, SPI_RX_FIFO);
for (i = 0; (i < tsd->bytes_per_word); i++) for (i = 0; (i < tsd->bytes_per_word); i++)
*rx_buf++ = (x >> (i*8)) & 0xFF; *rx_buf++ = (x >> (i*8)) & 0xFF;
read_words++; read_words++;
......
...@@ -97,6 +97,7 @@ static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c, ...@@ -97,6 +97,7 @@ static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
int on, unsigned int cs_delay) int on, unsigned int cs_delay)
{ {
int val = (spi->mode & SPI_CS_HIGH) ? on : !on; int val = (spi->mode & SPI_CS_HIGH) ? on : !on;
if (on) { if (on) {
/* deselect the chip with cs_change hint in last transfer */ /* deselect the chip with cs_change hint in last transfer */
if (c->last_chipselect >= 0) if (c->last_chipselect >= 0)
...@@ -188,6 +189,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m) ...@@ -188,6 +189,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
if (prev_speed_hz != speed_hz if (prev_speed_hz != speed_hz
|| prev_bits_per_word != bits_per_word) { || prev_bits_per_word != bits_per_word) {
int n = DIV_ROUND_UP(c->baseclk, speed_hz) - 1; int n = DIV_ROUND_UP(c->baseclk, speed_hz) - 1;
n = clamp(n, SPI_MIN_DIVIDER, SPI_MAX_DIVIDER); n = clamp(n, SPI_MIN_DIVIDER, SPI_MAX_DIVIDER);
/* enter config mode */ /* enter config mode */
txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR,
......
...@@ -471,7 +471,6 @@ static struct platform_driver xilinx_spi_driver = { ...@@ -471,7 +471,6 @@ static struct platform_driver xilinx_spi_driver = {
.remove = xilinx_spi_remove, .remove = xilinx_spi_remove,
.driver = { .driver = {
.name = XILINX_SPI_NAME, .name = XILINX_SPI_NAME,
.owner = THIS_MODULE,
.of_match_table = xilinx_spi_of_match, .of_match_table = xilinx_spi_of_match,
}, },
}; };
......
...@@ -46,6 +46,7 @@ static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi, ...@@ -46,6 +46,7 @@ static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi,
static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi) static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
{ {
unsigned i; unsigned i;
for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) && for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) &&
i < BUSY_WAIT_US; ++i) i < BUSY_WAIT_US; ++i)
udelay(1); udelay(1);
......
...@@ -552,6 +552,9 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) ...@@ -552,6 +552,9 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
struct boardinfo *bi; struct boardinfo *bi;
int i; int i;
if (!n)
return -EINVAL;
bi = kzalloc(n * sizeof(*bi), GFP_KERNEL); bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi) if (!bi)
return -ENOMEM; return -ENOMEM;
...@@ -789,27 +792,35 @@ static int spi_transfer_one_message(struct spi_master *master, ...@@ -789,27 +792,35 @@ static int spi_transfer_one_message(struct spi_master *master,
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
trace_spi_transfer_start(msg, xfer); trace_spi_transfer_start(msg, xfer);
reinit_completion(&master->xfer_completion); if (xfer->tx_buf || xfer->rx_buf) {
reinit_completion(&master->xfer_completion);
ret = master->transfer_one(master, msg->spi, xfer); ret = master->transfer_one(master, msg->spi, xfer);
if (ret < 0) { if (ret < 0) {
dev_err(&msg->spi->dev, dev_err(&msg->spi->dev,
"SPI transfer failed: %d\n", ret); "SPI transfer failed: %d\n", ret);
goto out; goto out;
} }
if (ret > 0) { if (ret > 0) {
ret = 0; ret = 0;
ms = xfer->len * 8 * 1000 / xfer->speed_hz; ms = xfer->len * 8 * 1000 / xfer->speed_hz;
ms += ms + 100; /* some tolerance */ ms += ms + 100; /* some tolerance */
ms = wait_for_completion_timeout(&master->xfer_completion, ms = wait_for_completion_timeout(&master->xfer_completion,
msecs_to_jiffies(ms)); msecs_to_jiffies(ms));
} }
if (ms == 0) { if (ms == 0) {
dev_err(&msg->spi->dev, "SPI transfer timed out\n"); dev_err(&msg->spi->dev,
msg->status = -ETIMEDOUT; "SPI transfer timed out\n");
msg->status = -ETIMEDOUT;
}
} else {
if (xfer->len)
dev_err(&msg->spi->dev,
"Bufferless transfer has length %u\n",
xfer->len);
} }
trace_spi_transfer_stop(msg, xfer); trace_spi_transfer_stop(msg, xfer);
......
...@@ -44,10 +44,15 @@ struct amba_driver { ...@@ -44,10 +44,15 @@ struct amba_driver {
const struct amba_id *id_table; const struct amba_id *id_table;
}; };
/*
* Constants for the designer field of the Peripheral ID register. When bit 7
* is set to '1', bits [6:0] should be the JEP106 manufacturer identity code.
*/
enum amba_vendor { enum amba_vendor {
AMBA_VENDOR_ARM = 0x41, AMBA_VENDOR_ARM = 0x41,
AMBA_VENDOR_ST = 0x80, AMBA_VENDOR_ST = 0x80,
AMBA_VENDOR_QCOM = 0x51, AMBA_VENDOR_QCOM = 0x51,
AMBA_VENDOR_LSI = 0xb6,
}; };
extern struct bus_type amba_bustype; extern struct bus_type amba_bustype;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment