Commit 7ae0ae4a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull spi updates from Mark Brown:
 "Quite a lot of cleanup and maintainence work going on this release in
  various drivers, and also a fix for a nasty locking issue in the core:

   - A fix for locking issues when external drivers explicitly locked
     the bus with spi_bus_lock() - we were using the same lock to both
     control access to the physical bus in multi-threaded I/O operations
     and exclude multiple callers.

     Confusion between these two caused us to have scenarios where we
     were dropping locks.  These are fixed by splitting into two
     separate locks like should have been done originally, making
     everything much clearer and correct.

   - Support for DMA in spi_flash_read().

   - Support for instantiating spidev on ACPI systems, including some
     test devices used in Windows validation.

   - Use of the core DMA mapping functionality in the McSPI driver.

   - Start of support for ThunderX SPI controllers, involving a very big
     set of changes to the Cavium driver.

   - Support for Braswell, Exynos 5433, Kaby Lake, Merrifield, RK3036,
     RK3228, RK3368 controllers"

* tag 'spi-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (64 commits)
  spi: Split bus and I/O locking
  spi: octeon: Split driver into Octeon specific and common parts
  spi: octeon: Move include file from arch/mips to drivers/spi
  spi: octeon: Put register offsets into a struct
  spi: octeon: Store system clock freqency in struct octeon_spi
  spi: octeon: Convert driver to use readq()/writeq() functions
  spi: pic32-sqi: fixup wait_for_completion_timeout return handling
  spi: pic32: fixup wait_for_completion_timeout return handling
  spi: rockchip: limit transfers to (64K - 1) bytes
  spi: xilinx: Return IRQ_NONE if no interrupts were detected
  spi: xilinx: Handle errors from platform_get_irq()
  spi: s3c64xx: restore removed comments
  spi: s3c64xx: add Exynos5433 compatible for ioclk handling
  spi: s3c64xx: use error code from clk_prepare_enable()
  spi: s3c64xx: rename goto labels to meaningful names
  spi: s3c64xx: document the clocks and the clock-name property
  spi: s3c64xx: add exynos5433 spi compatible
  spi: s3c64xx: fix reference leak to master in s3c64xx_spi_remove()
  spi: spi-sh: Remove deprecated create_singlethread_workqueue
  spi: spi-topcliff-pch: Remove deprecated create_singlethread_workqueue
  ...
parents 607e11ab dec34e8b
...@@ -11,7 +11,6 @@ Required properties: ...@@ -11,7 +11,6 @@ Required properties:
- "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51 - "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- interrupts : Should contain CSPI/eCSPI interrupt - interrupts : Should contain CSPI/eCSPI interrupt
- 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.
- clocks : Clock specifiers for both ipg and per clocks. - clocks : Clock specifiers for both ipg and per clocks.
- clock-names : Clock names should include both "ipg" and "per" - clock-names : Clock names should include both "ipg" and "per"
...@@ -21,6 +20,9 @@ See the clock consumer binding, ...@@ -21,6 +20,9 @@ See the clock consumer binding,
Documentation/devicetree/bindings/dma/dma.txt Documentation/devicetree/bindings/dma/dma.txt
- dma-names: DMA request names should include "tx" and "rx" if present. - dma-names: DMA request names should include "tx" and "rx" if present.
Obsolete properties:
- fsl,spi-num-chipselects : Contains the number of the chipselect
Example: Example:
ecspi@70010000 { ecspi@70010000 {
...@@ -29,7 +31,6 @@ ecspi@70010000 { ...@@ -29,7 +31,6 @@ ecspi@70010000 {
compatible = "fsl,imx51-ecspi"; compatible = "fsl,imx51-ecspi";
reg = <0x70010000 0x4000>; reg = <0x70010000 0x4000>;
interrupts = <36>; interrupts = <36>;
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>; dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
......
...@@ -8,11 +8,10 @@ in slave mode. ...@@ -8,11 +8,10 @@ in slave mode.
The SPI master node requires the following properties: The SPI master node requires the following 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. address on the SPI bus.
- #size-cells - should be zero. - #size-cells - should be zero.
- compatible - name of SPI bus controller following generic names - compatible - name of SPI bus controller following generic names
recommended practice. recommended practice.
- cs-gpios - (optional) gpios chip select.
No other properties are required in the SPI bus node. It is assumed No other properties are required in the SPI bus node. It is assumed
that a driver for an SPI bus device will understand that it is an SPI bus. that a driver for an SPI bus device will understand that it is an SPI bus.
However, the binding does not attempt to define the specific method for However, the binding does not attempt to define the specific method for
...@@ -22,11 +21,12 @@ assumption that board specific platform code will be used to manage ...@@ -22,11 +21,12 @@ assumption that board specific platform code will be used to manage
chip selects. Individual drivers can define additional properties to chip selects. Individual drivers can define additional properties to
support describing the chip select layout. support describing the chip select layout.
Optional property: Optional properties:
- num-cs : total number of chipselects - cs-gpios - gpios chip select.
- num-cs - total number of chipselects.
If cs-gpios is used the number of chip select will automatically increased If cs-gpios is used the number of chip selects will be increased automatically
with max(cs-gpios > hw cs) with max(cs-gpios > hw cs).
So if for example the controller has 2 CS lines, and the cs-gpios So if for example the controller has 2 CS lines, and the cs-gpios
property looks like this: property looks like this:
...@@ -45,29 +45,30 @@ SPI slave nodes must be children of the SPI master node and can ...@@ -45,29 +45,30 @@ SPI slave nodes must be children of the SPI master node and can
contain the following properties. contain the following properties.
- reg - (required) chip select address of device. - reg - (required) chip select address of device.
- compatible - (required) name of SPI device following generic names - compatible - (required) name of SPI device following generic names
recommended practice recommended practice.
- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz - spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz.
- spi-cpol - (optional) Empty property indicating device requires - spi-cpol - (optional) Empty property indicating device requires
inverse clock polarity (CPOL) mode inverse clock polarity (CPOL) mode.
- spi-cpha - (optional) Empty property indicating device requires - spi-cpha - (optional) Empty property indicating device requires
shifted clock phase (CPHA) mode shifted clock phase (CPHA) mode.
- spi-cs-high - (optional) Empty property indicating device requires - spi-cs-high - (optional) Empty property indicating device requires
chip select active high chip select active high.
- spi-3wire - (optional) Empty property indicating device requires - spi-3wire - (optional) Empty property indicating device requires
3-wire mode. 3-wire mode.
- spi-lsb-first - (optional) Empty property indicating device requires - spi-lsb-first - (optional) Empty property indicating device requires
LSB first mode. LSB first mode.
- spi-tx-bus-width - (optional) The bus width(number of data wires) that - spi-tx-bus-width - (optional) The bus width (number of data wires) that is
used for MOSI. Defaults to 1 if not present. used for MOSI. Defaults to 1 if not present.
- spi-rx-bus-width - (optional) The bus width(number of data wires) that - spi-rx-bus-width - (optional) The bus width (number of data wires) that is
used for MISO. Defaults to 1 if not present. used for MISO. Defaults to 1 if not present.
- spi-rx-delay-us - (optional) Microsecond delay after a read transfer. - spi-rx-delay-us - (optional) Microsecond delay after a read transfer.
- spi-tx-delay-us - (optional) Microsecond delay after a write transfer. - spi-tx-delay-us - (optional) Microsecond delay after a write transfer.
Some SPI controllers and devices support Dual and Quad SPI transfer mode. Some SPI controllers and devices support Dual and Quad SPI transfer mode.
It allows data in the SPI system to be transferred in 2 wires(DUAL) or 4 wires(QUAD). It allows data in the SPI system to be transferred using 2 wires (DUAL) or 4
wires (QUAD).
Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is
only 1(SINGLE), 2(DUAL) and 4(QUAD). only 1 (SINGLE), 2 (DUAL) and 4 (QUAD).
Dual/Quad mode is not allowed when 3-wire mode is used. Dual/Quad mode is not allowed when 3-wire mode is used.
If a gpio chipselect is used for the SPI slave the gpio number will be passed If a gpio chipselect is used for the SPI slave the gpio number will be passed
......
Serial Peripheral Interface on Cirrus Logic CL-PS71xx, EP72xx, EP73xx
Required properties
- #address-cells: must be <1>
- #size-cells: must be <0>
- compatible: should include "cirrus,ep7209-spi"
- reg: Address and length of one register range
- interrupts: one interrupt line
- clocks: One entry, refers to the SPI bus clock
- cs-gpios: Specifies the gpio pins to be used for chipselects.
See: Documentation/devicetree/bindings/spi/spi-bus.txt
An additional register is present in the system controller,
which is assumed to be in the same device tree, with and marked
as compatible with "cirrus,ep7209-syscon3".
Example:
spi@80000500 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "cirrus,ep7209-spi";
reg = <0x80000500 0x4>;
interrupts = <15>;
clocks = <&clks CLPS711X_CLK_SPI>;
status = "disabled";
};
syscon3: syscon@80002200 {
compatible = "cirrus,ep7209-syscon3", "syscon";
reg = <0x80002200 0x40>;
};
...@@ -21,7 +21,7 @@ Required properties: ...@@ -21,7 +21,7 @@ Required properties:
IP to the interrupt controller within the SoC. Possible values IP to the interrupt controller within the SoC. Possible values
are 0 and 1. Manual says one of the two possible interrupt are 0 and 1. Manual says one of the two possible interrupt
lines can be tied to the interrupt controller. Set this lines can be tied to the interrupt controller. Set this
based on a specifc SoC configuration. based on a specific SoC configuration.
- interrupts: interrupt number mapped to CPU. - interrupts: interrupt number mapped to CPU.
- clocks: spi clk phandle - clocks: spi clk phandle
......
...@@ -8,7 +8,15 @@ Required properties: ...@@ -8,7 +8,15 @@ Required properties:
- "marvell,armada-380-spi", for the Armada 38x SoCs - "marvell,armada-380-spi", for the Armada 38x SoCs
- "marvell,armada-390-spi", for the Armada 39x SoCs - "marvell,armada-390-spi", for the Armada 39x SoCs
- "marvell,armada-xp-spi", for the Armada XP SoCs - "marvell,armada-xp-spi", for the Armada XP SoCs
- reg : offset and length of the register set for the device - reg : offset and length of the register set for the device.
This property can optionally have additional entries to configure
the SPI direct access mode that some of the Marvell SoCs support
additionally to the normal indirect access (PIO) mode. The values
for the MBus "target" and "attribute" are defined in the Marvell
SoC "Functional Specifications" Manual in the chapter "Marvell
Core Processor Address Decoding".
The eight register sets following the control registers refer to
chip-select lines 0 through 7 respectively.
- cell-index : Which of multiple SPI controllers is this. - cell-index : Which of multiple SPI controllers is this.
Optional properties: Optional properties:
- interrupts : Is currently not used. - interrupts : Is currently not used.
...@@ -23,3 +31,42 @@ Example: ...@@ -23,3 +31,42 @@ Example:
interrupts = <23>; interrupts = <23>;
status = "disabled"; status = "disabled";
}; };
Example with SPI direct mode support (optionally):
spi0: spi@10600 {
compatible = "marvell,orion-spi";
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
reg = <MBUS_ID(0xf0, 0x01) 0x10600 0x28>, /* control */
<MBUS_ID(0x01, 0x1e) 0 0xffffffff>, /* CS0 */
<MBUS_ID(0x01, 0x5e) 0 0xffffffff>, /* CS1 */
<MBUS_ID(0x01, 0x9e) 0 0xffffffff>, /* CS2 */
<MBUS_ID(0x01, 0xde) 0 0xffffffff>, /* CS3 */
<MBUS_ID(0x01, 0x1f) 0 0xffffffff>, /* CS4 */
<MBUS_ID(0x01, 0x5f) 0 0xffffffff>, /* CS5 */
<MBUS_ID(0x01, 0x9f) 0 0xffffffff>, /* CS6 */
<MBUS_ID(0x01, 0xdf) 0 0xffffffff>; /* CS7 */
interrupts = <23>;
status = "disabled";
};
To enable the direct mode, the board specific 'ranges' property in the
'soc' node needs to add the entries for the desired SPI controllers
and its chip-selects that are used in the direct mode instead of PIO
mode. Here an example for this (SPI controller 0, device 1 and SPI
controller 1, device 2 are used in direct mode. All other SPI device
are used in the default indirect (PIO) mode):
soc {
/*
* Enable the SPI direct access by configuring an entry
* here in the board-specific ranges property
*/
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000>, /* internal regs */
<MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>, /* BootROM */
<MBUS_ID(0x01, 0x5e) 0 0 0xf1100000 0x10000>, /* SPI0-DEV1 */
<MBUS_ID(0x01, 0x9a) 0 0 0xf1110000 0x10000>; /* SPI1-DEV2 */
For further information on the MBus bindings, please see the MBus
DT documentation:
Documentation/devicetree/bindings/bus/mvebu-mbus.txt
...@@ -6,10 +6,13 @@ and display controllers using the SPI communication interface. ...@@ -6,10 +6,13 @@ and display controllers using the SPI communication interface.
Required Properties: Required Properties:
- compatible: should be one of the following. - compatible: should be one of the following.
"rockchip,rk3066-spi" for rk3066. "rockchip,rk3036-spi" for rk3036 SoCS.
"rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188. "rockchip,rk3066-spi" for rk3066 SoCs.
"rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288. "rockchip,rk3188-spi" for rk3188 SoCs.
"rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399. "rockchip,rk3228-spi" for rk3228 SoCS.
"rockchip,rk3288-spi" for rk3288 SoCs.
"rockchip,rk3368-spi" for rk3368 SoCs.
"rockchip,rk3399-spi" for rk3399 SoCs.
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
- interrupts: The interrupt number to the cpu. The interrupt specifier format - interrupts: The interrupt number to the cpu. The interrupt specifier format
......
...@@ -9,7 +9,8 @@ Required SoC Specific Properties: ...@@ -9,7 +9,8 @@ Required SoC Specific Properties:
- samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms - samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms
- samsung,s3c6410-spi: for s3c6410 platforms - samsung,s3c6410-spi: for s3c6410 platforms
- samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms - samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms
- samsung,exynos7-spi: for exynos7 platforms - samsung,exynos5433-spi: for exynos5433 compatible controllers
- samsung,exynos7-spi: for exynos7 platforms <DEPRECATED>
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
...@@ -23,6 +24,15 @@ Required SoC Specific Properties: ...@@ -23,6 +24,15 @@ Required SoC Specific Properties:
- dma-names: Names for the dma channels. There must be at least one channel - dma-names: Names for the dma channels. There must be at least one channel
named "tx" for transmit and named "rx" for receive. named "tx" for transmit and named "rx" for receive.
- clocks: specifies the clock IDs provided to the SPI controller; they are
required for interacting with the controller itself, for synchronizing the bus
and as I/O clock (the latter is required by exynos5433 and exynos7).
- clock-names: string names of the clocks in the 'clocks' property; for all the
the devices the names must be "spi", "spi_busclkN" (where N is determined by
"samsung,spi-src-clk"), while Exynos5433 should specify a third clock
"spi_ioclk" for the I/O clock.
Required Board Specific Properties: Required Board Specific Properties:
- #address-cells: should be 1. - #address-cells: should be 1.
...@@ -40,6 +50,9 @@ Optional Board Specific Properties: ...@@ -40,6 +50,9 @@ Optional Board Specific Properties:
- cs-gpios: should specify GPIOs used for chipselects (see spi-bus.txt) - cs-gpios: should specify GPIOs used for chipselects (see spi-bus.txt)
- no-cs-readback: the CS line is disconnected, therefore the device should not
operate based on CS signalling.
SPI Controller specific data in SPI slave nodes: SPI Controller specific data in SPI slave nodes:
- The spi slave nodes should provide the following information which is required - The spi slave nodes should provide the following information which is required
......
...@@ -20,7 +20,7 @@ Optional properties: ...@@ -20,7 +20,7 @@ Optional properties:
chipselect register and offset of that register. chipselect register and offset of that register.
NOTE: TI QSPI controller requires different pinmux and IODelay NOTE: TI QSPI controller requires different pinmux and IODelay
paramaters for Mode-0 and Mode-3 operations, which needs to be set up by parameters for Mode-0 and Mode-3 operations, which needs to be set up by
the bootloader (U-Boot). Default configuration only supports Mode-0 the bootloader (U-Boot). Default configuration only supports Mode-0
operation. Hence, "spi-cpol" and "spi-cpha" DT properties cannot be operation. Hence, "spi-cpol" and "spi-cpha" DT properties cannot be
specified in the slave nodes of TI QSPI controller without appropriate specified in the slave nodes of TI QSPI controller without appropriate
......
...@@ -10921,6 +10921,7 @@ L: linux-spi@vger.kernel.org ...@@ -10921,6 +10921,7 @@ L: linux-spi@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
Q: http://patchwork.kernel.org/project/spi-devel-general/list/ Q: http://patchwork.kernel.org/project/spi-devel-general/list/
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/spi/
F: Documentation/spi/ F: Documentation/spi/
F: drivers/spi/ F: drivers/spi/
F: include/linux/spi/ F: include/linux/spi/
......
...@@ -411,6 +411,7 @@ config SPI_OMAP24XX ...@@ -411,6 +411,7 @@ config SPI_OMAP24XX
tristate "McSPI driver for OMAP" tristate "McSPI driver for OMAP"
depends on HAS_DMA depends on HAS_DMA
depends on ARCH_OMAP2PLUS || COMPILE_TEST depends on ARCH_OMAP2PLUS || COMPILE_TEST
select SG_SPLIT
help help
SPI master controller for OMAP24XX and later Multichannel SPI SPI master controller for OMAP24XX and later Multichannel SPI
(McSPI) modules. (McSPI) modules.
......
...@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o ...@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o
obj-$(CONFIG_SPI_MXS) += spi-mxs.o obj-$(CONFIG_SPI_MXS) += spi-mxs.o
obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
spi-octeon-objs := spi-cavium.o spi-cavium-octeon.o
obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o
obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o
......
...@@ -64,8 +64,6 @@ struct bfin_sport_spi_master_data { ...@@ -64,8 +64,6 @@ struct bfin_sport_spi_master_data {
/* Pin request list */ /* Pin request list */
u16 *pin_req; u16 *pin_req;
/* Driver message queue */
struct workqueue_struct *workqueue;
struct work_struct pump_messages; struct work_struct pump_messages;
spinlock_t lock; spinlock_t lock;
struct list_head queue; struct list_head queue;
...@@ -300,7 +298,7 @@ bfin_sport_spi_giveback(struct bfin_sport_spi_master_data *drv_data) ...@@ -300,7 +298,7 @@ bfin_sport_spi_giveback(struct bfin_sport_spi_master_data *drv_data)
drv_data->cur_msg = NULL; drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL; drv_data->cur_transfer = NULL;
drv_data->cur_chip = NULL; drv_data->cur_chip = NULL;
queue_work(drv_data->workqueue, &drv_data->pump_messages); schedule_work(&drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
if (!drv_data->cs_change) if (!drv_data->cs_change)
...@@ -556,7 +554,7 @@ bfin_sport_spi_transfer(struct spi_device *spi, struct spi_message *msg) ...@@ -556,7 +554,7 @@ bfin_sport_spi_transfer(struct spi_device *spi, struct spi_message *msg)
list_add_tail(&msg->queue, &drv_data->queue); list_add_tail(&msg->queue, &drv_data->queue);
if (drv_data->run && !drv_data->busy) if (drv_data->run && !drv_data->busy)
queue_work(drv_data->workqueue, &drv_data->pump_messages); schedule_work(&drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
...@@ -666,12 +664,7 @@ bfin_sport_spi_init_queue(struct bfin_sport_spi_master_data *drv_data) ...@@ -666,12 +664,7 @@ bfin_sport_spi_init_queue(struct bfin_sport_spi_master_data *drv_data)
tasklet_init(&drv_data->pump_transfers, tasklet_init(&drv_data->pump_transfers,
bfin_sport_spi_pump_transfers, (unsigned long)drv_data); bfin_sport_spi_pump_transfers, (unsigned long)drv_data);
/* init messages workqueue */
INIT_WORK(&drv_data->pump_messages, bfin_sport_spi_pump_messages); INIT_WORK(&drv_data->pump_messages, bfin_sport_spi_pump_messages);
drv_data->workqueue =
create_singlethread_workqueue(dev_name(drv_data->master->dev.parent));
if (drv_data->workqueue == NULL)
return -EBUSY;
return 0; return 0;
} }
...@@ -694,7 +687,7 @@ bfin_sport_spi_start_queue(struct bfin_sport_spi_master_data *drv_data) ...@@ -694,7 +687,7 @@ bfin_sport_spi_start_queue(struct bfin_sport_spi_master_data *drv_data)
drv_data->cur_chip = NULL; drv_data->cur_chip = NULL;
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
queue_work(drv_data->workqueue, &drv_data->pump_messages); schedule_work(&drv_data->pump_messages);
return 0; return 0;
} }
...@@ -738,7 +731,7 @@ bfin_sport_spi_destroy_queue(struct bfin_sport_spi_master_data *drv_data) ...@@ -738,7 +731,7 @@ bfin_sport_spi_destroy_queue(struct bfin_sport_spi_master_data *drv_data)
if (status) if (status)
return status; return status;
destroy_workqueue(drv_data->workqueue); flush_work(&drv_data->pump_messages);
return 0; return 0;
} }
......
...@@ -67,8 +67,6 @@ struct bfin_spi_master_data { ...@@ -67,8 +67,6 @@ struct bfin_spi_master_data {
/* BFIN hookup */ /* BFIN hookup */
struct bfin5xx_spi_master *master_info; struct bfin5xx_spi_master *master_info;
/* Driver message queue */
struct workqueue_struct *workqueue;
struct work_struct pump_messages; struct work_struct pump_messages;
spinlock_t lock; spinlock_t lock;
struct list_head queue; struct list_head queue;
...@@ -359,7 +357,7 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) ...@@ -359,7 +357,7 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
drv_data->cur_msg = NULL; drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL; drv_data->cur_transfer = NULL;
drv_data->cur_chip = NULL; drv_data->cur_chip = NULL;
queue_work(drv_data->workqueue, &drv_data->pump_messages); schedule_work(&drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
msg->state = NULL; msg->state = NULL;
...@@ -946,7 +944,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) ...@@ -946,7 +944,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
list_add_tail(&msg->queue, &drv_data->queue); list_add_tail(&msg->queue, &drv_data->queue);
if (drv_data->running && !drv_data->busy) if (drv_data->running && !drv_data->busy)
queue_work(drv_data->workqueue, &drv_data->pump_messages); schedule_work(&drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
...@@ -1177,12 +1175,7 @@ static int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data) ...@@ -1177,12 +1175,7 @@ static int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data)
tasklet_init(&drv_data->pump_transfers, tasklet_init(&drv_data->pump_transfers,
bfin_spi_pump_transfers, (unsigned long)drv_data); bfin_spi_pump_transfers, (unsigned long)drv_data);
/* init messages workqueue */
INIT_WORK(&drv_data->pump_messages, bfin_spi_pump_messages); INIT_WORK(&drv_data->pump_messages, bfin_spi_pump_messages);
drv_data->workqueue = create_singlethread_workqueue(
dev_name(drv_data->master->dev.parent));
if (drv_data->workqueue == NULL)
return -EBUSY;
return 0; return 0;
} }
...@@ -1204,7 +1197,7 @@ static int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data) ...@@ -1204,7 +1197,7 @@ static int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data)
drv_data->cur_chip = NULL; drv_data->cur_chip = NULL;
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
queue_work(drv_data->workqueue, &drv_data->pump_messages); schedule_work(&drv_data->pump_messages);
return 0; return 0;
} }
...@@ -1246,7 +1239,7 @@ static int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data) ...@@ -1246,7 +1239,7 @@ static int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
if (status != 0) if (status != 0)
return status; return status;
destroy_workqueue(drv_data->workqueue); flush_work(&drv_data->pump_messages);
return 0; return 0;
} }
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2011, 2012 Cavium, Inc.
*/
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
#include <asm/octeon/octeon.h>
#include "spi-cavium.h"
static int octeon_spi_probe(struct platform_device *pdev)
{
struct resource *res_mem;
void __iomem *reg_base;
struct spi_master *master;
struct octeon_spi *p;
int err = -ENOENT;
master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi));
if (!master)
return -ENOMEM;
p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, master);
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg_base = devm_ioremap_resource(&pdev->dev, res_mem);
if (IS_ERR(reg_base)) {
err = PTR_ERR(reg_base);
goto fail;
}
p->register_base = reg_base;
p->sys_freq = octeon_get_io_clock_rate();
p->regs.config = 0;
p->regs.status = 0x08;
p->regs.tx = 0x10;
p->regs.data = 0x80;
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
SPI_CPOL |
SPI_CS_HIGH |
SPI_LSB_FIRST |
SPI_3WIRE;
master->transfer_one_message = octeon_spi_transfer_one_message;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
master->dev.of_node = pdev->dev.of_node;
err = devm_spi_register_master(&pdev->dev, master);
if (err) {
dev_err(&pdev->dev, "register master failed: %d\n", err);
goto fail;
}
dev_info(&pdev->dev, "OCTEON SPI bus driver\n");
return 0;
fail:
spi_master_put(master);
return err;
}
static int octeon_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct octeon_spi *p = spi_master_get_devdata(master);
/* Clear the CSENA* and put everything in a known state. */
writeq(0, p->register_base + OCTEON_SPI_CFG(p));
return 0;
}
static const struct of_device_id octeon_spi_match[] = {
{ .compatible = "cavium,octeon-3010-spi", },
{},
};
MODULE_DEVICE_TABLE(of, octeon_spi_match);
static struct platform_driver octeon_spi_driver = {
.driver = {
.name = "spi-octeon",
.of_match_table = octeon_spi_match,
},
.probe = octeon_spi_probe,
.remove = octeon_spi_remove,
};
module_platform_driver(octeon_spi_driver);
MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
MODULE_AUTHOR("David Daney");
MODULE_LICENSE("GPL");
...@@ -6,31 +6,12 @@ ...@@ -6,31 +6,12 @@
* Copyright (C) 2011, 2012 Cavium, Inc. * Copyright (C) 2011, 2012 Cavium, Inc.
*/ */
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h>
#include <asm/octeon/octeon.h> #include "spi-cavium.h"
#include <asm/octeon/cvmx-mpi-defs.h>
#define OCTEON_SPI_CFG 0
#define OCTEON_SPI_STS 0x08
#define OCTEON_SPI_TX 0x10
#define OCTEON_SPI_DAT0 0x80
#define OCTEON_SPI_MAX_BYTES 9
#define OCTEON_SPI_MAX_CLOCK_HZ 16000000
struct octeon_spi {
u64 register_base;
u64 last_cfg;
u64 cs_enax;
};
static void octeon_spi_wait_ready(struct octeon_spi *p) static void octeon_spi_wait_ready(struct octeon_spi *p)
{ {
...@@ -40,7 +21,7 @@ static void octeon_spi_wait_ready(struct octeon_spi *p) ...@@ -40,7 +21,7 @@ static void octeon_spi_wait_ready(struct octeon_spi *p)
do { do {
if (loops++) if (loops++)
__delay(500); __delay(500);
mpi_sts.u64 = cvmx_read_csr(p->register_base + OCTEON_SPI_STS); mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS(p));
} while (mpi_sts.s.busy); } while (mpi_sts.s.busy);
} }
...@@ -53,7 +34,6 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, ...@@ -53,7 +34,6 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
union cvmx_mpi_cfg mpi_cfg; union cvmx_mpi_cfg mpi_cfg;
union cvmx_mpi_tx mpi_tx; union cvmx_mpi_tx mpi_tx;
unsigned int clkdiv; unsigned int clkdiv;
unsigned int speed_hz;
int mode; int mode;
bool cpha, cpol; bool cpha, cpol;
const u8 *tx_buf; const u8 *tx_buf;
...@@ -65,9 +45,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, ...@@ -65,9 +45,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
cpha = mode & SPI_CPHA; cpha = mode & SPI_CPHA;
cpol = mode & SPI_CPOL; cpol = mode & SPI_CPOL;
speed_hz = xfer->speed_hz; clkdiv = p->sys_freq / (2 * xfer->speed_hz);
clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz);
mpi_cfg.u64 = 0; mpi_cfg.u64 = 0;
...@@ -85,7 +63,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, ...@@ -85,7 +63,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
if (mpi_cfg.u64 != p->last_cfg) { if (mpi_cfg.u64 != p->last_cfg) {
p->last_cfg = mpi_cfg.u64; p->last_cfg = mpi_cfg.u64;
cvmx_write_csr(p->register_base + OCTEON_SPI_CFG, mpi_cfg.u64); writeq(mpi_cfg.u64, p->register_base + OCTEON_SPI_CFG(p));
} }
tx_buf = xfer->tx_buf; tx_buf = xfer->tx_buf;
rx_buf = xfer->rx_buf; rx_buf = xfer->rx_buf;
...@@ -97,19 +75,19 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, ...@@ -97,19 +75,19 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
d = *tx_buf++; d = *tx_buf++;
else else
d = 0; d = 0;
cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
} }
mpi_tx.u64 = 0; mpi_tx.u64 = 0;
mpi_tx.s.csid = spi->chip_select; mpi_tx.s.csid = spi->chip_select;
mpi_tx.s.leavecs = 1; mpi_tx.s.leavecs = 1;
mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p));
octeon_spi_wait_ready(p); octeon_spi_wait_ready(p);
if (rx_buf) if (rx_buf)
for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
*rx_buf++ = (u8)v; *rx_buf++ = (u8)v;
} }
len -= OCTEON_SPI_MAX_BYTES; len -= OCTEON_SPI_MAX_BYTES;
...@@ -121,7 +99,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, ...@@ -121,7 +99,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
d = *tx_buf++; d = *tx_buf++;
else else
d = 0; d = 0;
cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
} }
mpi_tx.u64 = 0; mpi_tx.u64 = 0;
...@@ -132,12 +110,12 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, ...@@ -132,12 +110,12 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
mpi_tx.s.leavecs = !xfer->cs_change; mpi_tx.s.leavecs = !xfer->cs_change;
mpi_tx.s.txnum = tx_buf ? len : 0; mpi_tx.s.txnum = tx_buf ? len : 0;
mpi_tx.s.totnum = len; mpi_tx.s.totnum = len;
cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p));
octeon_spi_wait_ready(p); octeon_spi_wait_ready(p);
if (rx_buf) if (rx_buf)
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
*rx_buf++ = (u8)v; *rx_buf++ = (u8)v;
} }
...@@ -147,8 +125,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, ...@@ -147,8 +125,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
return xfer->len; return xfer->len;
} }
static int octeon_spi_transfer_one_message(struct spi_master *master, int octeon_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg) struct spi_message *msg)
{ {
struct octeon_spi *p = spi_master_get_devdata(master); struct octeon_spi *p = spi_master_get_devdata(master);
unsigned int total_len = 0; unsigned int total_len = 0;
...@@ -171,85 +149,3 @@ static int octeon_spi_transfer_one_message(struct spi_master *master, ...@@ -171,85 +149,3 @@ static int octeon_spi_transfer_one_message(struct spi_master *master,
spi_finalize_current_message(master); spi_finalize_current_message(master);
return status; return status;
} }
static int octeon_spi_probe(struct platform_device *pdev)
{
struct resource *res_mem;
void __iomem *reg_base;
struct spi_master *master;
struct octeon_spi *p;
int err = -ENOENT;
master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi));
if (!master)
return -ENOMEM;
p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, master);
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg_base = devm_ioremap_resource(&pdev->dev, res_mem);
if (IS_ERR(reg_base)) {
err = PTR_ERR(reg_base);
goto fail;
}
p->register_base = (u64)reg_base;
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
SPI_CPOL |
SPI_CS_HIGH |
SPI_LSB_FIRST |
SPI_3WIRE;
master->transfer_one_message = octeon_spi_transfer_one_message;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
master->dev.of_node = pdev->dev.of_node;
err = devm_spi_register_master(&pdev->dev, master);
if (err) {
dev_err(&pdev->dev, "register master failed: %d\n", err);
goto fail;
}
dev_info(&pdev->dev, "OCTEON SPI bus driver\n");
return 0;
fail:
spi_master_put(master);
return err;
}
static int octeon_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct octeon_spi *p = spi_master_get_devdata(master);
u64 register_base = p->register_base;
/* Clear the CSENA* and put everything in a known state. */
cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0);
return 0;
}
static const struct of_device_id octeon_spi_match[] = {
{ .compatible = "cavium,octeon-3010-spi", },
{},
};
MODULE_DEVICE_TABLE(of, octeon_spi_match);
static struct platform_driver octeon_spi_driver = {
.driver = {
.name = "spi-octeon",
.of_match_table = octeon_spi_match,
},
.probe = octeon_spi_probe,
.remove = octeon_spi_remove,
};
module_platform_driver(octeon_spi_driver);
MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
MODULE_AUTHOR("David Daney");
MODULE_LICENSE("GPL");
/***********************license start*************** #ifndef __SPI_CAVIUM_H
* Author: Cavium Networks #define __SPI_CAVIUM_H
*
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
* Copyright (c) 2003-2012 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
* published by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* or visit http://www.gnu.org/licenses/.
*
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
***********************license end**************************************/
#ifndef __CVMX_MPI_DEFS_H__ #define OCTEON_SPI_MAX_BYTES 9
#define __CVMX_MPI_DEFS_H__ #define OCTEON_SPI_MAX_CLOCK_HZ 16000000
struct octeon_spi_regs {
int config;
int status;
int tx;
int data;
};
struct octeon_spi {
void __iomem *register_base;
u64 last_cfg;
u64 cs_enax;
int sys_freq;
struct octeon_spi_regs regs;
};
#define OCTEON_SPI_CFG(x) (x->regs.config)
#define OCTEON_SPI_STS(x) (x->regs.status)
#define OCTEON_SPI_TX(x) (x->regs.tx)
#define OCTEON_SPI_DAT0(x) (x->regs.data)
int octeon_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg);
/* MPI register descriptions */
#define CVMX_MPI_CFG (CVMX_ADD_IO_SEG(0x0001070000001000ull)) #define CVMX_MPI_CFG (CVMX_ADD_IO_SEG(0x0001070000001000ull))
#define CVMX_MPI_DATX(offset) (CVMX_ADD_IO_SEG(0x0001070000001080ull) + ((offset) & 15) * 8) #define CVMX_MPI_DATX(offset) (CVMX_ADD_IO_SEG(0x0001070000001080ull) + ((offset) & 15) * 8)
...@@ -325,4 +326,4 @@ union cvmx_mpi_tx { ...@@ -325,4 +326,4 @@ union cvmx_mpi_tx {
struct cvmx_mpi_tx_cn61xx cnf71xx; struct cvmx_mpi_tx_cn61xx cnf71xx;
}; };
#endif #endif /* __SPI_CAVIUM_H */
/* /*
* CLPS711X SPI bus driver * CLPS711X SPI bus driver
* *
* Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru> * Copyright (C) 2012-2016 Alexander Shiyan <shc_work@mail.ru>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -20,9 +19,8 @@ ...@@ -20,9 +19,8 @@
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/clps711x.h> #include <linux/mfd/syscon/clps711x.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/platform_data/spi-clps711x.h>
#define DRIVER_NAME "spi-clps711x" #define DRIVER_NAME "clps711x-spi"
#define SYNCIO_FRMLEN(x) ((x) << 8) #define SYNCIO_FRMLEN(x) ((x) << 8)
#define SYNCIO_TXFRMEN (1 << 14) #define SYNCIO_TXFRMEN (1 << 14)
...@@ -40,6 +38,17 @@ struct spi_clps711x_data { ...@@ -40,6 +38,17 @@ struct spi_clps711x_data {
static int spi_clps711x_setup(struct spi_device *spi) static int spi_clps711x_setup(struct spi_device *spi)
{ {
if (!spi->controller_state) {
int ret;
ret = devm_gpio_request(&spi->master->dev, spi->cs_gpio,
dev_name(&spi->master->dev));
if (ret)
return ret;
spi->controller_state = spi;
}
/* We are expect that SPI-device is not selected */ /* We are expect that SPI-device is not selected */
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
...@@ -104,20 +113,9 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) ...@@ -104,20 +113,9 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
static int spi_clps711x_probe(struct platform_device *pdev) static int spi_clps711x_probe(struct platform_device *pdev)
{ {
struct spi_clps711x_data *hw; struct spi_clps711x_data *hw;
struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
struct spi_master *master; struct spi_master *master;
struct resource *res; struct resource *res;
int i, irq, ret; int irq, ret;
if (!pdata) {
dev_err(&pdev->dev, "No platform data supplied\n");
return -EINVAL;
}
if (pdata->num_chipselect < 1) {
dev_err(&pdev->dev, "At least one CS must be defined\n");
return -EINVAL;
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
...@@ -127,40 +125,24 @@ static int spi_clps711x_probe(struct platform_device *pdev) ...@@ -127,40 +125,24 @@ static int spi_clps711x_probe(struct platform_device *pdev)
if (!master) if (!master)
return -ENOMEM; return -ENOMEM;
master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) * master->bus_num = -1;
pdata->num_chipselect, GFP_KERNEL);
if (!master->cs_gpios) {
ret = -ENOMEM;
goto err_out;
}
master->bus_num = pdev->id;
master->mode_bits = SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
master->num_chipselect = pdata->num_chipselect; master->dev.of_node = pdev->dev.of_node;
master->setup = spi_clps711x_setup; master->setup = spi_clps711x_setup;
master->prepare_message = spi_clps711x_prepare_message; master->prepare_message = spi_clps711x_prepare_message;
master->transfer_one = spi_clps711x_transfer_one; master->transfer_one = spi_clps711x_transfer_one;
hw = spi_master_get_devdata(master); hw = spi_master_get_devdata(master);
for (i = 0; i < master->num_chipselect; i++) {
master->cs_gpios[i] = pdata->chipselect[i];
ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
goto err_out;
}
}
hw->spi_clk = devm_clk_get(&pdev->dev, NULL); hw->spi_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(hw->spi_clk)) { if (IS_ERR(hw->spi_clk)) {
ret = PTR_ERR(hw->spi_clk); ret = PTR_ERR(hw->spi_clk);
goto err_out; goto err_out;
} }
hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3"); hw->syscon =
syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon3");
if (IS_ERR(hw->syscon)) { if (IS_ERR(hw->syscon)) {
ret = PTR_ERR(hw->syscon); ret = PTR_ERR(hw->syscon);
goto err_out; goto err_out;
...@@ -185,14 +167,8 @@ static int spi_clps711x_probe(struct platform_device *pdev) ...@@ -185,14 +167,8 @@ static int spi_clps711x_probe(struct platform_device *pdev)
goto err_out; goto err_out;
ret = devm_spi_register_master(&pdev->dev, master); ret = devm_spi_register_master(&pdev->dev, master);
if (!ret) { if (!ret)
dev_info(&pdev->dev,
"SPI bus driver initialized. Master clock %u Hz\n",
master->max_speed_hz);
return 0; return 0;
}
dev_err(&pdev->dev, "Failed to register master\n");
err_out: err_out:
spi_master_put(master); spi_master_put(master);
...@@ -200,9 +176,16 @@ static int spi_clps711x_probe(struct platform_device *pdev) ...@@ -200,9 +176,16 @@ static int spi_clps711x_probe(struct platform_device *pdev)
return ret; return ret;
} }
static const struct of_device_id clps711x_spi_dt_ids[] = {
{ .compatible = "cirrus,ep7209-spi", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_spi_dt_ids);
static struct platform_driver clps711x_spi_driver = { static struct platform_driver clps711x_spi_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = clps711x_spi_dt_ids,
}, },
.probe = spi_clps711x_probe, .probe = spi_clps711x_probe,
}; };
......
This diff is collapsed.
...@@ -536,7 +536,7 @@ static int spi_test_check_loopback_result(struct spi_device *spi, ...@@ -536,7 +536,7 @@ static int spi_test_check_loopback_result(struct spi_device *spi,
mismatch_error: mismatch_error:
dev_err(&spi->dev, dev_err(&spi->dev,
"loopback strangeness - transfer missmatch on byte %04zx - expected 0x%02x, but got 0x%02x\n", "loopback strangeness - transfer mismatch on byte %04zx - expected 0x%02x, but got 0x%02x\n",
i, txb, rxb); i, txb, rxb);
return -EINVAL; return -EINVAL;
......
...@@ -42,7 +42,6 @@ struct mpc52xx_psc_spi { ...@@ -42,7 +42,6 @@ struct mpc52xx_psc_spi {
u8 bits_per_word; u8 bits_per_word;
u8 busy; u8 busy;
struct workqueue_struct *workqueue;
struct work_struct work; struct work_struct work;
struct list_head queue; struct list_head queue;
...@@ -299,7 +298,7 @@ static int mpc52xx_psc_spi_transfer(struct spi_device *spi, ...@@ -299,7 +298,7 @@ static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
spin_lock_irqsave(&mps->lock, flags); spin_lock_irqsave(&mps->lock, flags);
list_add_tail(&m->queue, &mps->queue); list_add_tail(&m->queue, &mps->queue);
queue_work(mps->workqueue, &mps->work); schedule_work(&mps->work);
spin_unlock_irqrestore(&mps->lock, flags); spin_unlock_irqrestore(&mps->lock, flags);
return 0; return 0;
...@@ -425,21 +424,12 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, ...@@ -425,21 +424,12 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
INIT_WORK(&mps->work, mpc52xx_psc_spi_work); INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
INIT_LIST_HEAD(&mps->queue); INIT_LIST_HEAD(&mps->queue);
mps->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
if (mps->workqueue == NULL) {
ret = -EBUSY;
goto free_irq;
}
ret = spi_register_master(master); ret = spi_register_master(master);
if (ret < 0) if (ret < 0)
goto unreg_master; goto free_irq;
return ret; return ret;
unreg_master:
destroy_workqueue(mps->workqueue);
free_irq: free_irq:
free_irq(mps->irq, mps); free_irq(mps->irq, mps);
free_master: free_master:
...@@ -484,8 +474,7 @@ static int mpc52xx_psc_spi_of_remove(struct platform_device *op) ...@@ -484,8 +474,7 @@ static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
struct spi_master *master = spi_master_get(platform_get_drvdata(op)); struct spi_master *master = spi_master_get(platform_get_drvdata(op));
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master); struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
flush_workqueue(mps->workqueue); flush_work(&mps->work);
destroy_workqueue(mps->workqueue);
spi_unregister_master(master); spi_unregister_master(master);
free_irq(mps->irq, mps); free_irq(mps->irq, mps);
if (mps->psc) if (mps->psc)
......
...@@ -419,16 +419,13 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi, ...@@ -419,16 +419,13 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
if (mcspi_dma->dma_tx) { if (mcspi_dma->dma_tx) {
struct dma_async_tx_descriptor *tx; struct dma_async_tx_descriptor *tx;
struct scatterlist sg;
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
sg_init_table(&sg, 1); tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
sg_dma_address(&sg) = xfer->tx_dma; xfer->tx_sg.nents,
sg_dma_len(&sg) = xfer->len; DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (tx) { if (tx) {
tx->callback = omap2_mcspi_tx_callback; tx->callback = omap2_mcspi_tx_callback;
tx->callback_param = spi; tx->callback_param = spi;
...@@ -449,7 +446,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, ...@@ -449,7 +446,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
{ {
struct omap2_mcspi *mcspi; struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_dma *mcspi_dma;
unsigned int count, dma_count; unsigned int count, transfer_reduction = 0;
struct scatterlist *sg_out[2];
int nb_sizes = 0, out_mapped_nents[2], ret, x;
size_t sizes[2];
u32 l; u32 l;
int elements = 0; int elements = 0;
int word_len, element_count; int word_len, element_count;
...@@ -457,10 +457,14 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, ...@@ -457,10 +457,14 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select]; mcspi_dma = &mcspi->dma_channels[spi->chip_select];
count = xfer->len; count = xfer->len;
dma_count = xfer->len;
/*
* In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
* it mentions reducing DMA transfer length by one element in master
* normal mode.
*/
if (mcspi->fifo_depth == 0) if (mcspi->fifo_depth == 0)
dma_count -= es; transfer_reduction = es;
word_len = cs->word_len; word_len = cs->word_len;
l = mcspi_cached_chconf0(spi); l = mcspi_cached_chconf0(spi);
...@@ -474,20 +478,46 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, ...@@ -474,20 +478,46 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
if (mcspi_dma->dma_rx) { if (mcspi_dma->dma_rx) {
struct dma_async_tx_descriptor *tx; struct dma_async_tx_descriptor *tx;
struct scatterlist sg;
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
/*
* Reduce DMA transfer length by one more if McSPI is
* configured in turbo mode.
*/
if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
dma_count -= es; transfer_reduction += es;
if (transfer_reduction) {
/* Split sgl into two. The second sgl won't be used. */
sizes[0] = count - transfer_reduction;
sizes[1] = transfer_reduction;
nb_sizes = 2;
} else {
/*
* Don't bother splitting the sgl. This essentially
* clones the original sgl.
*/
sizes[0] = count;
nb_sizes = 1;
}
ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents,
0, nb_sizes,
sizes,
sg_out, out_mapped_nents,
GFP_KERNEL);
sg_init_table(&sg, 1); if (ret < 0) {
sg_dma_address(&sg) = xfer->rx_dma; dev_err(&spi->dev, "sg_split failed\n");
sg_dma_len(&sg) = dma_count; return 0;
}
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | sg_out[0],
DMA_CTRL_ACK); out_mapped_nents[0],
DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (tx) { if (tx) {
tx->callback = omap2_mcspi_rx_callback; tx->callback = omap2_mcspi_rx_callback;
tx->callback_param = spi; tx->callback_param = spi;
...@@ -501,12 +531,17 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, ...@@ -501,12 +531,17 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
omap2_mcspi_set_dma_req(spi, 1, 1); omap2_mcspi_set_dma_req(spi, 1, 1);
wait_for_completion(&mcspi_dma->dma_rx_completion); wait_for_completion(&mcspi_dma->dma_rx_completion);
dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
DMA_FROM_DEVICE); for (x = 0; x < nb_sizes; x++)
kfree(sg_out[x]);
if (mcspi->fifo_depth > 0) if (mcspi->fifo_depth > 0)
return count; return count;
/*
* Due to the DMA transfer length reduction the missing bytes must
* be read manually to receive all of the expected data.
*/
omap2_mcspi_set_enable(spi, 0); omap2_mcspi_set_enable(spi, 0);
elements = element_count - 1; elements = element_count - 1;
...@@ -615,8 +650,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -615,8 +650,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
if (tx != NULL) { if (tx != NULL) {
wait_for_completion(&mcspi_dma->dma_tx_completion); wait_for_completion(&mcspi_dma->dma_tx_completion);
dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
DMA_TO_DEVICE);
if (mcspi->fifo_depth > 0) { if (mcspi->fifo_depth > 0) {
irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
...@@ -1074,8 +1107,9 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) ...@@ -1074,8 +1107,9 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
gpio_free(spi->cs_gpio); gpio_free(spi->cs_gpio);
} }
static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, static int omap2_mcspi_transfer_one(struct spi_master *master,
struct spi_device *spi, struct spi_transfer *t) struct spi_device *spi,
struct spi_transfer *t)
{ {
/* We only enable one channel at a time -- the one whose message is /* We only enable one channel at a time -- the one whose message is
...@@ -1085,7 +1119,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, ...@@ -1085,7 +1119,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
* chipselect with the FORCE bit ... CS != channel enable. * chipselect with the FORCE bit ... CS != channel enable.
*/ */
struct spi_master *master; struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs; struct omap2_mcspi_cs *cs;
struct omap2_mcspi_device_config *cd; struct omap2_mcspi_device_config *cd;
...@@ -1093,7 +1127,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, ...@@ -1093,7 +1127,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
int status = 0; int status = 0;
u32 chconf; u32 chconf;
master = spi->master; mcspi = spi_master_get_devdata(master);
mcspi_dma = mcspi->dma_channels + spi->chip_select; mcspi_dma = mcspi->dma_channels + spi->chip_select;
cs = spi->controller_state; cs = spi->controller_state;
cd = spi->controller_data; cd = spi->controller_data;
...@@ -1153,7 +1187,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, ...@@ -1153,7 +1187,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
unsigned count; unsigned count;
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
(t->len >= DMA_MIN_BYTES)) master->cur_msg_mapped &&
master->can_dma(master, spi, t))
omap2_mcspi_set_fifo(spi, t, 1); omap2_mcspi_set_fifo(spi, t, 1);
omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 1);
...@@ -1164,7 +1199,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, ...@@ -1164,7 +1199,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
+ OMAP2_MCSPI_TX0); + OMAP2_MCSPI_TX0);
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
(t->len >= DMA_MIN_BYTES)) master->cur_msg_mapped &&
master->can_dma(master, spi, t))
count = omap2_mcspi_txrx_dma(spi, t); count = omap2_mcspi_txrx_dma(spi, t);
else else
count = omap2_mcspi_txrx_pio(spi, t); count = omap2_mcspi_txrx_pio(spi, t);
...@@ -1233,55 +1269,11 @@ static int omap2_mcspi_prepare_message(struct spi_master *master, ...@@ -1233,55 +1269,11 @@ static int omap2_mcspi_prepare_message(struct spi_master *master,
return 0; return 0;
} }
static int omap2_mcspi_transfer_one(struct spi_master *master, static bool omap2_mcspi_can_dma(struct spi_master *master,
struct spi_device *spi, struct spi_transfer *t) struct spi_device *spi,
struct spi_transfer *xfer)
{ {
struct omap2_mcspi *mcspi; return (xfer->len >= DMA_MIN_BYTES);
struct omap2_mcspi_dma *mcspi_dma;
const void *tx_buf = t->tx_buf;
void *rx_buf = t->rx_buf;
unsigned len = t->len;
mcspi = spi_master_get_devdata(master);
mcspi_dma = mcspi->dma_channels + spi->chip_select;
if ((len && !(rx_buf || tx_buf))) {
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
t->speed_hz,
len,
tx_buf ? "tx" : "",
rx_buf ? "rx" : "",
t->bits_per_word);
return -EINVAL;
}
if (len < DMA_MIN_BYTES)
goto skip_dma_map;
if (mcspi_dma->dma_tx && tx_buf != NULL) {
t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
len, DMA_TO_DEVICE);
if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
'T', len);
return -EINVAL;
}
}
if (mcspi_dma->dma_rx && rx_buf != NULL) {
t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
'R', len);
if (tx_buf != NULL)
dma_unmap_single(mcspi->dev, t->tx_dma,
len, DMA_TO_DEVICE);
return -EINVAL;
}
}
skip_dma_map:
return omap2_mcspi_work_one(mcspi, spi, t);
} }
static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
...@@ -1361,6 +1353,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) ...@@ -1361,6 +1353,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->setup = omap2_mcspi_setup; master->setup = omap2_mcspi_setup;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->prepare_message = omap2_mcspi_prepare_message; master->prepare_message = omap2_mcspi_prepare_message;
master->can_dma = omap2_mcspi_can_dma;
master->transfer_one = omap2_mcspi_transfer_one; master->transfer_one = omap2_mcspi_transfer_one;
master->set_cs = omap2_mcspi_set_cs; master->set_cs = omap2_mcspi_set_cs;
master->cleanup = omap2_mcspi_cleanup; master->cleanup = omap2_mcspi_cleanup;
......
...@@ -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_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/sizes.h> #include <linux/sizes.h>
...@@ -43,6 +44,9 @@ ...@@ -43,6 +44,9 @@
#define ORION_SPI_INT_CAUSE_REG 0x10 #define ORION_SPI_INT_CAUSE_REG 0x10
#define ORION_SPI_TIMING_PARAMS_REG 0x18 #define ORION_SPI_TIMING_PARAMS_REG 0x18
/* Register for the "Direct Mode" */
#define SPI_DIRECT_WRITE_CONFIG_REG 0x20
#define ORION_SPI_TMISO_SAMPLE_MASK (0x3 << 6) #define ORION_SPI_TMISO_SAMPLE_MASK (0x3 << 6)
#define ORION_SPI_TMISO_SAMPLE_1 (1 << 6) #define ORION_SPI_TMISO_SAMPLE_1 (1 << 6)
#define ORION_SPI_TMISO_SAMPLE_2 (2 << 6) #define ORION_SPI_TMISO_SAMPLE_2 (2 << 6)
...@@ -78,11 +82,18 @@ struct orion_spi_dev { ...@@ -78,11 +82,18 @@ struct orion_spi_dev {
bool is_errata_50mhz_ac; bool is_errata_50mhz_ac;
}; };
struct orion_direct_acc {
void __iomem *vaddr;
u32 size;
};
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; const struct orion_spi_dev *devdata;
struct orion_direct_acc direct_access[ORION_NUM_CHIPSELECTS];
}; };
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)
...@@ -372,10 +383,39 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -372,10 +383,39 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
{ {
unsigned int count; unsigned int count;
int word_len; int word_len;
struct orion_spi *orion_spi;
int cs = spi->chip_select;
word_len = spi->bits_per_word; word_len = spi->bits_per_word;
count = xfer->len; count = xfer->len;
orion_spi = spi_master_get_devdata(spi->master);
/*
* Use SPI direct write mode if base address is available. Otherwise
* fall back to PIO mode for this transfer.
*/
if ((orion_spi->direct_access[cs].vaddr) && (xfer->tx_buf) &&
(word_len == 8)) {
unsigned int cnt = count / 4;
unsigned int rem = count % 4;
/*
* Send the TX-data to the SPI device via the direct
* mapped address window
*/
iowrite32_rep(orion_spi->direct_access[cs].vaddr,
xfer->tx_buf, cnt);
if (rem) {
u32 *buf = (u32 *)xfer->tx_buf;
iowrite8_rep(orion_spi->direct_access[cs].vaddr,
&buf[cnt], rem);
}
return count;
}
if (word_len == 8) { if (word_len == 8) {
const u8 *tx = xfer->tx_buf; const u8 *tx = xfer->tx_buf;
u8 *rx = xfer->rx_buf; u8 *rx = xfer->rx_buf;
...@@ -425,6 +465,10 @@ static int orion_spi_reset(struct orion_spi *orion_spi) ...@@ -425,6 +465,10 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
{ {
/* Verify that the CS is deasserted */ /* Verify that the CS is deasserted */
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
/* Don't deassert CS between the direct mapped SPI transfers */
writel(0, spi_reg(orion_spi, SPI_DIRECT_WRITE_CONFIG_REG));
return 0; return 0;
} }
...@@ -504,6 +548,7 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -504,6 +548,7 @@ static int orion_spi_probe(struct platform_device *pdev)
struct resource *r; struct resource *r;
unsigned long tclk_hz; unsigned long tclk_hz;
int status = 0; int status = 0;
struct device_node *np;
master = spi_alloc_master(&pdev->dev, sizeof(*spi)); master = spi_alloc_master(&pdev->dev, sizeof(*spi));
if (master == NULL) { if (master == NULL) {
...@@ -576,6 +621,49 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -576,6 +621,49 @@ static int orion_spi_probe(struct platform_device *pdev)
goto out_rel_clk; goto out_rel_clk;
} }
/* Scan all SPI devices of this controller for direct mapped devices */
for_each_available_child_of_node(pdev->dev.of_node, np) {
u32 cs;
/* Get chip-select number from the "reg" property */
status = of_property_read_u32(np, "reg", &cs);
if (status) {
dev_err(&pdev->dev,
"%s has no valid 'reg' property (%d)\n",
np->full_name, status);
status = 0;
continue;
}
/*
* Check if an address is configured for this SPI device. If
* not, the MBus mapping via the 'ranges' property in the 'soc'
* node is not configured and this device should not use the
* direct mode. In this case, just continue with the next
* device.
*/
status = of_address_to_resource(pdev->dev.of_node, cs + 1, r);
if (status)
continue;
/*
* Only map one page for direct access. This is enough for the
* simple TX transfer which only writes to the first word.
* This needs to get extended for the direct SPI-NOR / SPI-NAND
* support, once this gets implemented.
*/
spi->direct_access[cs].vaddr = devm_ioremap(&pdev->dev,
r->start,
PAGE_SIZE);
if (!spi->direct_access[cs].vaddr) {
status = -ENOMEM;
goto out_rel_clk;
}
spi->direct_access[cs].size = PAGE_SIZE;
dev_info(&pdev->dev, "CS%d configured for direct access\n", cs);
}
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
......
...@@ -354,6 +354,7 @@ static int pic32_sqi_one_message(struct spi_master *master, ...@@ -354,6 +354,7 @@ static int pic32_sqi_one_message(struct spi_master *master,
struct spi_transfer *xfer; struct spi_transfer *xfer;
struct pic32_sqi *sqi; struct pic32_sqi *sqi;
int ret = 0, mode; int ret = 0, mode;
unsigned long timeout;
u32 val; u32 val;
sqi = spi_master_get_devdata(master); sqi = spi_master_get_devdata(master);
...@@ -419,10 +420,10 @@ static int pic32_sqi_one_message(struct spi_master *master, ...@@ -419,10 +420,10 @@ static int pic32_sqi_one_message(struct spi_master *master,
writel(val, sqi->regs + PESQI_BD_CTRL_REG); writel(val, sqi->regs + PESQI_BD_CTRL_REG);
/* wait for xfer completion */ /* wait for xfer completion */
ret = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ); timeout = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ);
if (ret <= 0) { if (timeout == 0) {
dev_err(&sqi->master->dev, "wait timedout/interrupted\n"); dev_err(&sqi->master->dev, "wait timedout/interrupted\n");
ret = -EIO; ret = -ETIMEDOUT;
msg->status = ret; msg->status = ret;
} else { } else {
/* success */ /* success */
......
...@@ -507,6 +507,7 @@ static int pic32_spi_one_transfer(struct spi_master *master, ...@@ -507,6 +507,7 @@ static int pic32_spi_one_transfer(struct spi_master *master,
{ {
struct pic32_spi *pic32s; struct pic32_spi *pic32s;
bool dma_issued = false; bool dma_issued = false;
unsigned long timeout;
int ret; int ret;
pic32s = spi_master_get_devdata(master); pic32s = spi_master_get_devdata(master);
...@@ -553,8 +554,8 @@ static int pic32_spi_one_transfer(struct spi_master *master, ...@@ -553,8 +554,8 @@ static int pic32_spi_one_transfer(struct spi_master *master,
} }
/* wait for completion */ /* wait for completion */
ret = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ); timeout = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ);
if (ret <= 0) { if (timeout == 0) {
dev_err(&spi->dev, "wait error/timedout\n"); dev_err(&spi->dev, "wait error/timedout\n");
if (dma_issued) { if (dma_issued) {
dmaengine_terminate_all(master->dma_rx); dmaengine_terminate_all(master->dma_rx);
......
...@@ -20,79 +20,6 @@ ...@@ -20,79 +20,6 @@
#include "spi-pxa2xx.h" #include "spi-pxa2xx.h"
static int pxa2xx_spi_map_dma_buffer(struct driver_data *drv_data,
enum dma_data_direction dir)
{
int i, nents, len = drv_data->len;
struct scatterlist *sg;
struct device *dmadev;
struct sg_table *sgt;
void *buf, *pbuf;
if (dir == DMA_TO_DEVICE) {
dmadev = drv_data->tx_chan->device->dev;
sgt = &drv_data->tx_sgt;
buf = drv_data->tx;
} else {
dmadev = drv_data->rx_chan->device->dev;
sgt = &drv_data->rx_sgt;
buf = drv_data->rx;
}
nents = DIV_ROUND_UP(len, SZ_2K);
if (nents != sgt->nents) {
int ret;
sg_free_table(sgt);
ret = sg_alloc_table(sgt, nents, GFP_ATOMIC);
if (ret)
return ret;
}
pbuf = buf;
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
size_t bytes = min_t(size_t, len, SZ_2K);
sg_set_buf(sg, pbuf, bytes);
pbuf += bytes;
len -= bytes;
}
nents = dma_map_sg(dmadev, sgt->sgl, sgt->nents, dir);
if (!nents)
return -ENOMEM;
return nents;
}
static void pxa2xx_spi_unmap_dma_buffer(struct driver_data *drv_data,
enum dma_data_direction dir)
{
struct device *dmadev;
struct sg_table *sgt;
if (dir == DMA_TO_DEVICE) {
dmadev = drv_data->tx_chan->device->dev;
sgt = &drv_data->tx_sgt;
} else {
dmadev = drv_data->rx_chan->device->dev;
sgt = &drv_data->rx_sgt;
}
dma_unmap_sg(dmadev, sgt->sgl, sgt->nents, dir);
}
static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
{
if (!drv_data->dma_mapped)
return;
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_FROM_DEVICE);
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
drv_data->dma_mapped = 0;
}
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
bool error) bool error)
{ {
...@@ -125,8 +52,6 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, ...@@ -125,8 +52,6 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
pxa2xx_spi_write(drv_data, SSTO, 0); pxa2xx_spi_write(drv_data, SSTO, 0);
if (!error) { if (!error) {
pxa2xx_spi_unmap_dma_buffers(drv_data);
msg->actual_length += drv_data->len; msg->actual_length += drv_data->len;
msg->state = pxa2xx_spi_next_transfer(drv_data); msg->state = pxa2xx_spi_next_transfer(drv_data);
} else { } else {
...@@ -152,11 +77,12 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, ...@@ -152,11 +77,12 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
enum dma_transfer_direction dir) enum dma_transfer_direction dir)
{ {
struct chip_data *chip = drv_data->cur_chip; struct chip_data *chip = drv_data->cur_chip;
struct spi_transfer *xfer = drv_data->cur_transfer;
enum dma_slave_buswidth width; enum dma_slave_buswidth width;
struct dma_slave_config cfg; struct dma_slave_config cfg;
struct dma_chan *chan; struct dma_chan *chan;
struct sg_table *sgt; struct sg_table *sgt;
int nents, ret; int ret;
switch (drv_data->n_bytes) { switch (drv_data->n_bytes) {
case 1: case 1:
...@@ -178,17 +104,15 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, ...@@ -178,17 +104,15 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
cfg.dst_addr_width = width; cfg.dst_addr_width = width;
cfg.dst_maxburst = chip->dma_burst_size; cfg.dst_maxburst = chip->dma_burst_size;
sgt = &drv_data->tx_sgt; sgt = &xfer->tx_sg;
nents = drv_data->tx_nents; chan = drv_data->master->dma_tx;
chan = drv_data->tx_chan;
} else { } else {
cfg.src_addr = drv_data->ssdr_physical; cfg.src_addr = drv_data->ssdr_physical;
cfg.src_addr_width = width; cfg.src_addr_width = width;
cfg.src_maxburst = chip->dma_burst_size; cfg.src_maxburst = chip->dma_burst_size;
sgt = &drv_data->rx_sgt; sgt = &xfer->rx_sg;
nents = drv_data->rx_nents; chan = drv_data->master->dma_rx;
chan = drv_data->rx_chan;
} }
ret = dmaengine_slave_config(chan, &cfg); ret = dmaengine_slave_config(chan, &cfg);
...@@ -197,46 +121,10 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, ...@@ -197,46 +121,10 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
return NULL; return NULL;
} }
return dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir, return dmaengine_prep_slave_sg(chan, sgt->sgl, sgt->nents, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
} }
bool pxa2xx_spi_dma_is_possible(size_t len)
{
return len <= MAX_DMA_LEN;
}
int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
{
const struct chip_data *chip = drv_data->cur_chip;
int ret;
if (!chip->enable_dma)
return 0;
/* Don't bother with DMA if we can't do even a single burst */
if (drv_data->len < chip->dma_burst_size)
return 0;
ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_TO_DEVICE);
if (ret <= 0) {
dev_warn(&drv_data->pdev->dev, "failed to DMA map TX\n");
return 0;
}
drv_data->tx_nents = ret;
ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_FROM_DEVICE);
if (ret <= 0) {
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
dev_warn(&drv_data->pdev->dev, "failed to DMA map RX\n");
return 0;
}
drv_data->rx_nents = ret;
return 1;
}
irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
{ {
u32 status; u32 status;
...@@ -245,8 +133,8 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) ...@@ -245,8 +133,8 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
if (status & SSSR_ROR) { if (status & SSSR_ROR) {
dev_err(&drv_data->pdev->dev, "FIFO overrun\n"); dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
dmaengine_terminate_async(drv_data->rx_chan); dmaengine_terminate_async(drv_data->master->dma_rx);
dmaengine_terminate_async(drv_data->tx_chan); dmaengine_terminate_async(drv_data->master->dma_tx);
pxa2xx_spi_dma_transfer_complete(drv_data, true); pxa2xx_spi_dma_transfer_complete(drv_data, true);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -285,16 +173,15 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst) ...@@ -285,16 +173,15 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
return 0; return 0;
err_rx: err_rx:
dmaengine_terminate_async(drv_data->tx_chan); dmaengine_terminate_async(drv_data->master->dma_tx);
err_tx: err_tx:
pxa2xx_spi_unmap_dma_buffers(drv_data);
return err; return err;
} }
void pxa2xx_spi_dma_start(struct driver_data *drv_data) void pxa2xx_spi_dma_start(struct driver_data *drv_data)
{ {
dma_async_issue_pending(drv_data->rx_chan); dma_async_issue_pending(drv_data->master->dma_rx);
dma_async_issue_pending(drv_data->tx_chan); dma_async_issue_pending(drv_data->master->dma_tx);
atomic_set(&drv_data->dma_running, 1); atomic_set(&drv_data->dma_running, 1);
} }
...@@ -303,21 +190,22 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data) ...@@ -303,21 +190,22 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
{ {
struct pxa2xx_spi_master *pdata = drv_data->master_info; struct pxa2xx_spi_master *pdata = drv_data->master_info;
struct device *dev = &drv_data->pdev->dev; struct device *dev = &drv_data->pdev->dev;
struct spi_master *master = drv_data->master;
dma_cap_mask_t mask; dma_cap_mask_t mask;
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
drv_data->tx_chan = dma_request_slave_channel_compat(mask, master->dma_tx = dma_request_slave_channel_compat(mask,
pdata->dma_filter, pdata->tx_param, dev, "tx"); pdata->dma_filter, pdata->tx_param, dev, "tx");
if (!drv_data->tx_chan) if (!master->dma_tx)
return -ENODEV; return -ENODEV;
drv_data->rx_chan = dma_request_slave_channel_compat(mask, master->dma_rx = dma_request_slave_channel_compat(mask,
pdata->dma_filter, pdata->rx_param, dev, "rx"); pdata->dma_filter, pdata->rx_param, dev, "rx");
if (!drv_data->rx_chan) { if (!master->dma_rx) {
dma_release_channel(drv_data->tx_chan); dma_release_channel(master->dma_tx);
drv_data->tx_chan = NULL; master->dma_tx = NULL;
return -ENODEV; return -ENODEV;
} }
...@@ -326,17 +214,17 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data) ...@@ -326,17 +214,17 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
void pxa2xx_spi_dma_release(struct driver_data *drv_data) void pxa2xx_spi_dma_release(struct driver_data *drv_data)
{ {
if (drv_data->rx_chan) { struct spi_master *master = drv_data->master;
dmaengine_terminate_sync(drv_data->rx_chan);
dma_release_channel(drv_data->rx_chan); if (master->dma_rx) {
sg_free_table(&drv_data->rx_sgt); dmaengine_terminate_sync(master->dma_rx);
drv_data->rx_chan = NULL; dma_release_channel(master->dma_rx);
master->dma_rx = NULL;
} }
if (drv_data->tx_chan) { if (master->dma_tx) {
dmaengine_terminate_sync(drv_data->tx_chan); dmaengine_terminate_sync(master->dma_tx);
dma_release_channel(drv_data->tx_chan); dma_release_channel(master->dma_tx);
sg_free_table(&drv_data->tx_sgt); master->dma_tx = NULL;
drv_data->tx_chan = NULL;
} }
} }
......
/* /*
* CE4100's SPI device is more or less the same one as found on PXA * CE4100's SPI device is more or less the same one as found on PXA
* *
* Copyright (C) 2016, Intel Corporation
*/ */
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/clk-provider.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/platform_data/dma-dw.h> #include <linux/platform_data/dma-dw.h>
enum { enum {
PORT_CE4100, PORT_QUARK_X1000,
PORT_BYT, PORT_BYT,
PORT_MRFLD,
PORT_BSW0, PORT_BSW0,
PORT_BSW1, PORT_BSW1,
PORT_BSW2, PORT_BSW2,
PORT_QUARK_X1000, PORT_CE4100,
PORT_LPT, PORT_LPT,
}; };
...@@ -29,8 +31,11 @@ struct pxa_spi_info { ...@@ -29,8 +31,11 @@ struct pxa_spi_info {
unsigned long max_clk_rate; unsigned long max_clk_rate;
/* DMA channel request parameters */ /* DMA channel request parameters */
bool (*dma_filter)(struct dma_chan *chan, void *param);
void *tx_param; void *tx_param;
void *rx_param; void *rx_param;
int (*setup)(struct pci_dev *pdev, struct pxa_spi_info *c);
}; };
static struct dw_dma_slave byt_tx_param = { .dst_id = 0 }; static struct dw_dma_slave byt_tx_param = { .dst_id = 0 };
...@@ -57,6 +62,56 @@ static bool lpss_dma_filter(struct dma_chan *chan, void *param) ...@@ -57,6 +62,56 @@ static bool lpss_dma_filter(struct dma_chan *chan, void *param)
return true; return true;
} }
static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c)
{
struct pci_dev *dma_dev;
c->num_chipselect = 1;
c->max_clk_rate = 50000000;
dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
if (c->tx_param) {
struct dw_dma_slave *slave = c->tx_param;
slave->dma_dev = &dma_dev->dev;
slave->m_master = 0;
slave->p_master = 1;
}
if (c->rx_param) {
struct dw_dma_slave *slave = c->rx_param;
slave->dma_dev = &dma_dev->dev;
slave->m_master = 0;
slave->p_master = 1;
}
c->dma_filter = lpss_dma_filter;
return 0;
}
static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c)
{
switch (PCI_FUNC(dev->devfn)) {
case 0:
c->port_id = 3;
c->num_chipselect = 1;
break;
case 1:
c->port_id = 5;
c->num_chipselect = 4;
break;
case 2:
c->port_id = 6;
c->num_chipselect = 1;
break;
default:
return -ENODEV;
}
return 0;
}
static struct pxa_spi_info spi_info_configs[] = { static struct pxa_spi_info spi_info_configs[] = {
[PORT_CE4100] = { [PORT_CE4100] = {
.type = PXA25x_SSP, .type = PXA25x_SSP,
...@@ -67,35 +122,36 @@ static struct pxa_spi_info spi_info_configs[] = { ...@@ -67,35 +122,36 @@ static struct pxa_spi_info spi_info_configs[] = {
[PORT_BYT] = { [PORT_BYT] = {
.type = LPSS_BYT_SSP, .type = LPSS_BYT_SSP,
.port_id = 0, .port_id = 0,
.num_chipselect = 1, .setup = lpss_spi_setup,
.max_clk_rate = 50000000,
.tx_param = &byt_tx_param, .tx_param = &byt_tx_param,
.rx_param = &byt_rx_param, .rx_param = &byt_rx_param,
}, },
[PORT_BSW0] = { [PORT_BSW0] = {
.type = LPSS_BYT_SSP, .type = LPSS_BSW_SSP,
.port_id = 0, .port_id = 0,
.num_chipselect = 1, .setup = lpss_spi_setup,
.max_clk_rate = 50000000,
.tx_param = &bsw0_tx_param, .tx_param = &bsw0_tx_param,
.rx_param = &bsw0_rx_param, .rx_param = &bsw0_rx_param,
}, },
[PORT_BSW1] = { [PORT_BSW1] = {
.type = LPSS_BYT_SSP, .type = LPSS_BSW_SSP,
.port_id = 1, .port_id = 1,
.num_chipselect = 1, .setup = lpss_spi_setup,
.max_clk_rate = 50000000,
.tx_param = &bsw1_tx_param, .tx_param = &bsw1_tx_param,
.rx_param = &bsw1_rx_param, .rx_param = &bsw1_rx_param,
}, },
[PORT_BSW2] = { [PORT_BSW2] = {
.type = LPSS_BYT_SSP, .type = LPSS_BSW_SSP,
.port_id = 2, .port_id = 2,
.num_chipselect = 1, .setup = lpss_spi_setup,
.max_clk_rate = 50000000,
.tx_param = &bsw2_tx_param, .tx_param = &bsw2_tx_param,
.rx_param = &bsw2_rx_param, .rx_param = &bsw2_rx_param,
}, },
[PORT_MRFLD] = {
.type = PXA27x_SSP,
.max_clk_rate = 25000000,
.setup = mrfld_spi_setup,
},
[PORT_QUARK_X1000] = { [PORT_QUARK_X1000] = {
.type = QUARK_X1000_SSP, .type = QUARK_X1000_SSP,
.port_id = -1, .port_id = -1,
...@@ -105,8 +161,7 @@ static struct pxa_spi_info spi_info_configs[] = { ...@@ -105,8 +161,7 @@ static struct pxa_spi_info spi_info_configs[] = {
[PORT_LPT] = { [PORT_LPT] = {
.type = LPSS_LPT_SSP, .type = LPSS_LPT_SSP,
.port_id = 0, .port_id = 0,
.num_chipselect = 1, .setup = lpss_spi_setup,
.max_clk_rate = 50000000,
.tx_param = &lpt_tx_param, .tx_param = &lpt_tx_param,
.rx_param = &lpt_rx_param, .rx_param = &lpt_rx_param,
}, },
...@@ -122,7 +177,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -122,7 +177,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
struct ssp_device *ssp; struct ssp_device *ssp;
struct pxa_spi_info *c; struct pxa_spi_info *c;
char buf[40]; char buf[40];
struct pci_dev *dma_dev;
ret = pcim_enable_device(dev); ret = pcim_enable_device(dev);
if (ret) if (ret)
...@@ -133,30 +187,15 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -133,30 +187,15 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
return ret; return ret;
c = &spi_info_configs[ent->driver_data]; c = &spi_info_configs[ent->driver_data];
if (c->setup) {
memset(&spi_pdata, 0, sizeof(spi_pdata)); ret = c->setup(dev, c);
spi_pdata.num_chipselect = (c->num_chipselect > 0) ? if (ret)
c->num_chipselect : dev->devfn; return ret;
dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
if (c->tx_param) {
struct dw_dma_slave *slave = c->tx_param;
slave->dma_dev = &dma_dev->dev;
slave->m_master = 0;
slave->p_master = 1;
} }
if (c->rx_param) { memset(&spi_pdata, 0, sizeof(spi_pdata));
struct dw_dma_slave *slave = c->rx_param; spi_pdata.num_chipselect = (c->num_chipselect > 0) ? c->num_chipselect : dev->devfn;
spi_pdata.dma_filter = c->dma_filter;
slave->dma_dev = &dma_dev->dev;
slave->m_master = 0;
slave->p_master = 1;
}
spi_pdata.dma_filter = lpss_dma_filter;
spi_pdata.tx_param = c->tx_param; spi_pdata.tx_param = c->tx_param;
spi_pdata.rx_param = c->rx_param; spi_pdata.rx_param = c->rx_param;
spi_pdata.enable_dma = c->rx_param && c->tx_param; spi_pdata.enable_dma = c->rx_param && c->tx_param;
...@@ -164,10 +203,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -164,10 +203,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
ssp = &spi_pdata.ssp; ssp = &spi_pdata.ssp;
ssp->phys_base = pci_resource_start(dev, 0); ssp->phys_base = pci_resource_start(dev, 0);
ssp->mmio_base = pcim_iomap_table(dev)[0]; ssp->mmio_base = pcim_iomap_table(dev)[0];
if (!ssp->mmio_base) {
dev_err(&dev->dev, "failed to ioremap() registers\n");
return -EIO;
}
ssp->irq = dev->irq; ssp->irq = dev->irq;
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;
...@@ -208,12 +243,13 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev) ...@@ -208,12 +243,13 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
} }
static const struct pci_device_id pxa2xx_spi_pci_devices[] = { static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
{ PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
{ PCI_VDEVICE(INTEL, 0x0935), PORT_QUARK_X1000 }, { PCI_VDEVICE(INTEL, 0x0935), PORT_QUARK_X1000 },
{ PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT }, { PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT },
{ PCI_VDEVICE(INTEL, 0x1194), PORT_MRFLD },
{ PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 }, { PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 },
{ PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 }, { PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 },
{ PCI_VDEVICE(INTEL, 0x22ac), PORT_BSW2 }, { PCI_VDEVICE(INTEL, 0x22ac), PORT_BSW2 },
{ PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
{ PCI_VDEVICE(INTEL, 0x9ce6), PORT_LPT }, { PCI_VDEVICE(INTEL, 0x9ce6), PORT_LPT },
{ }, { },
}; };
......
...@@ -585,7 +585,14 @@ static void reset_sccr1(struct driver_data *drv_data) ...@@ -585,7 +585,14 @@ static void reset_sccr1(struct driver_data *drv_data)
u32 sccr1_reg; u32 sccr1_reg;
sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1; sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1;
sccr1_reg &= ~SSCR1_RFT; switch (drv_data->ssp_type) {
case QUARK_X1000_SSP:
sccr1_reg &= ~QUARK_X1000_SSCR1_RFT;
break;
default:
sccr1_reg &= ~SSCR1_RFT;
break;
}
sccr1_reg |= chip->threshold; sccr1_reg |= chip->threshold;
pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
} }
...@@ -912,9 +919,21 @@ static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data, ...@@ -912,9 +919,21 @@ static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
return clk_div << 8; return clk_div << 8;
} }
static bool pxa2xx_spi_can_dma(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct chip_data *chip = spi_get_ctldata(spi);
return chip->enable_dma &&
xfer->len <= MAX_DMA_LEN &&
xfer->len >= chip->dma_burst_size;
}
static void pump_transfers(unsigned long data) static void pump_transfers(unsigned long data)
{ {
struct driver_data *drv_data = (struct driver_data *)data; struct driver_data *drv_data = (struct driver_data *)data;
struct spi_master *master = drv_data->master;
struct spi_message *message = NULL; struct spi_message *message = NULL;
struct spi_transfer *transfer = NULL; struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL; struct spi_transfer *previous = NULL;
...@@ -928,6 +947,7 @@ static void pump_transfers(unsigned long data) ...@@ -928,6 +947,7 @@ static void pump_transfers(unsigned long data)
u32 dma_burst = drv_data->cur_chip->dma_burst_size; u32 dma_burst = drv_data->cur_chip->dma_burst_size;
u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data); u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data);
int err; int err;
int dma_mapped;
/* Get current state information */ /* Get current state information */
message = drv_data->cur_msg; message = drv_data->cur_msg;
...@@ -962,7 +982,7 @@ static void pump_transfers(unsigned long data) ...@@ -962,7 +982,7 @@ static void pump_transfers(unsigned long data)
} }
/* Check if we can DMA this transfer */ /* Check if we can DMA this transfer */
if (!pxa2xx_spi_dma_is_possible(transfer->len) && chip->enable_dma) { if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
/* reject already-mapped transfers; PIO won't always work */ /* reject already-mapped transfers; PIO won't always work */
if (message->is_dma_mapped if (message->is_dma_mapped
...@@ -1039,10 +1059,10 @@ static void pump_transfers(unsigned long data) ...@@ -1039,10 +1059,10 @@ static void pump_transfers(unsigned long data)
message->state = RUNNING_STATE; message->state = RUNNING_STATE;
drv_data->dma_mapped = 0; dma_mapped = master->can_dma &&
if (pxa2xx_spi_dma_is_possible(drv_data->len)) master->can_dma(master, message->spi, transfer) &&
drv_data->dma_mapped = pxa2xx_spi_map_dma_buffers(drv_data); master->cur_msg_mapped;
if (drv_data->dma_mapped) { if (dma_mapped) {
/* Ensure we have the correct interrupt handler */ /* Ensure we have the correct interrupt handler */
drv_data->transfer_handler = pxa2xx_spi_dma_transfer; drv_data->transfer_handler = pxa2xx_spi_dma_transfer;
...@@ -1072,14 +1092,14 @@ static void pump_transfers(unsigned long data) ...@@ -1072,14 +1092,14 @@ static void pump_transfers(unsigned long data)
cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits); cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
if (!pxa25x_ssp_comp(drv_data)) if (!pxa25x_ssp_comp(drv_data))
dev_dbg(&message->spi->dev, "%u Hz actual, %s\n", dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
drv_data->master->max_speed_hz master->max_speed_hz
/ (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)), / (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)),
drv_data->dma_mapped ? "DMA" : "PIO"); dma_mapped ? "DMA" : "PIO");
else else
dev_dbg(&message->spi->dev, "%u Hz actual, %s\n", dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
drv_data->master->max_speed_hz / 2 master->max_speed_hz / 2
/ (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)), / (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)),
drv_data->dma_mapped ? "DMA" : "PIO"); dma_mapped ? "DMA" : "PIO");
if (is_lpss_ssp(drv_data)) { if (is_lpss_ssp(drv_data)) {
if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff) if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
...@@ -1240,7 +1260,7 @@ static int setup(struct spi_device *spi) ...@@ -1240,7 +1260,7 @@ static int setup(struct spi_device *spi)
chip->frm = spi->chip_select; chip->frm = spi->chip_select;
} else } else
chip->gpio_cs = -1; chip->gpio_cs = -1;
chip->enable_dma = 0; chip->enable_dma = drv_data->master_info->enable_dma;
chip->timeout = TIMOUT_DFLT; chip->timeout = TIMOUT_DFLT;
} }
...@@ -1259,17 +1279,9 @@ static int setup(struct spi_device *spi) ...@@ -1259,17 +1279,9 @@ static int setup(struct spi_device *spi)
tx_hi_thres = chip_info->tx_hi_threshold; tx_hi_thres = chip_info->tx_hi_threshold;
if (chip_info->rx_threshold) if (chip_info->rx_threshold)
rx_thres = chip_info->rx_threshold; rx_thres = chip_info->rx_threshold;
chip->enable_dma = drv_data->master_info->enable_dma;
chip->dma_threshold = 0; chip->dma_threshold = 0;
if (chip_info->enable_loopback) if (chip_info->enable_loopback)
chip->cr1 = SSCR1_LBM; chip->cr1 = SSCR1_LBM;
} else if (ACPI_HANDLE(&spi->dev)) {
/*
* Slave devices enumerated from ACPI namespace don't
* usually have chip_info but we still might want to use
* DMA with them.
*/
chip->enable_dma = drv_data->master_info->enable_dma;
} }
chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres); chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
...@@ -1389,6 +1401,9 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { ...@@ -1389,6 +1401,9 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
/* SPT-H */ /* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP }, { PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP },
{ PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP }, { PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP },
/* KBL-H */
{ PCI_VDEVICE(INTEL, 0xa2a9), LPSS_SPT_SSP },
{ PCI_VDEVICE(INTEL, 0xa2aa), LPSS_SPT_SSP },
/* BXT A-Step */ /* BXT A-Step */
{ PCI_VDEVICE(INTEL, 0x0ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x0ac2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x0ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x0ac4), LPSS_BXT_SSP },
...@@ -1601,6 +1616,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1601,6 +1616,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
if (status) { if (status) {
dev_dbg(dev, "no DMA channels available, using PIO\n"); dev_dbg(dev, "no DMA channels available, using PIO\n");
platform_info->enable_dma = false; platform_info->enable_dma = false;
} else {
master->can_dma = pxa2xx_spi_can_dma;
} }
} }
......
...@@ -50,12 +50,6 @@ struct driver_data { ...@@ -50,12 +50,6 @@ struct driver_data {
struct tasklet_struct pump_transfers; struct tasklet_struct pump_transfers;
/* DMA engine support */ /* DMA engine support */
struct dma_chan *rx_chan;
struct dma_chan *tx_chan;
struct sg_table rx_sgt;
struct sg_table tx_sgt;
int rx_nents;
int tx_nents;
atomic_t dma_running; atomic_t dma_running;
/* Current message transfer state info */ /* Current message transfer state info */
...@@ -67,7 +61,6 @@ struct driver_data { ...@@ -67,7 +61,6 @@ struct driver_data {
void *tx_end; void *tx_end;
void *rx; void *rx;
void *rx_end; void *rx_end;
int dma_mapped;
u8 n_bytes; u8 n_bytes;
int (*write)(struct driver_data *drv_data); int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data); int (*read)(struct driver_data *drv_data);
...@@ -145,8 +138,6 @@ extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data); ...@@ -145,8 +138,6 @@ extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data);
#define MAX_DMA_LEN SZ_64K #define MAX_DMA_LEN SZ_64K
#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL) #define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL)
extern bool pxa2xx_spi_dma_is_possible(size_t len);
extern int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data);
extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data); extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data);
extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst); extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst);
extern void pxa2xx_spi_dma_start(struct driver_data *drv_data); extern void pxa2xx_spi_dma_start(struct driver_data *drv_data);
......
...@@ -142,6 +142,12 @@ ...@@ -142,6 +142,12 @@
/* sclk_out: spi master internal logic in rk3x can support 50Mhz */ /* sclk_out: spi master internal logic in rk3x can support 50Mhz */
#define MAX_SCLK_OUT 50000000 #define MAX_SCLK_OUT 50000000
/*
* SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However,
* the controller seems to hang when given 0x10000, so stick with this for now.
*/
#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff
enum rockchip_ssi_type { enum rockchip_ssi_type {
SSI_MOTO_SPI = 0, SSI_MOTO_SPI = 0,
SSI_TI_SSP, SSI_TI_SSP,
...@@ -573,6 +579,11 @@ static void rockchip_spi_config(struct rockchip_spi *rs) ...@@ -573,6 +579,11 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div); dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
} }
static size_t rockchip_spi_max_transfer_size(struct spi_device *spi)
{
return ROCKCHIP_SPI_MAX_TRANLEN;
}
static int rockchip_spi_transfer_one( static int rockchip_spi_transfer_one(
struct spi_master *master, struct spi_master *master,
struct spi_device *spi, struct spi_device *spi,
...@@ -589,6 +600,11 @@ static int rockchip_spi_transfer_one( ...@@ -589,6 +600,11 @@ static int rockchip_spi_transfer_one(
return -EINVAL; return -EINVAL;
} }
if (xfer->len > ROCKCHIP_SPI_MAX_TRANLEN) {
dev_err(rs->dev, "Transfer is too long (%d)\n", xfer->len);
return -EINVAL;
}
rs->speed = xfer->speed_hz; rs->speed = xfer->speed_hz;
rs->bpw = xfer->bits_per_word; rs->bpw = xfer->bits_per_word;
rs->n_bytes = rs->bpw >> 3; rs->n_bytes = rs->bpw >> 3;
...@@ -730,6 +746,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -730,6 +746,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->prepare_message = rockchip_spi_prepare_message; master->prepare_message = rockchip_spi_prepare_message;
master->unprepare_message = rockchip_spi_unprepare_message; master->unprepare_message = rockchip_spi_unprepare_message;
master->transfer_one = rockchip_spi_transfer_one; master->transfer_one = rockchip_spi_transfer_one;
master->max_transfer_size = rockchip_spi_max_transfer_size;
master->handle_err = rockchip_spi_handle_err; master->handle_err = rockchip_spi_handle_err;
rs->dma_tx.ch = dma_request_chan(rs->dev, "tx"); rs->dma_tx.ch = dma_request_chan(rs->dev, "tx");
...@@ -894,9 +911,12 @@ static const struct dev_pm_ops rockchip_spi_pm = { ...@@ -894,9 +911,12 @@ static const struct dev_pm_ops rockchip_spi_pm = {
}; };
static const struct of_device_id rockchip_spi_dt_match[] = { static const struct of_device_id rockchip_spi_dt_match[] = {
{ .compatible = "rockchip,rk3036-spi", },
{ .compatible = "rockchip,rk3066-spi", }, { .compatible = "rockchip,rk3066-spi", },
{ .compatible = "rockchip,rk3188-spi", }, { .compatible = "rockchip,rk3188-spi", },
{ .compatible = "rockchip,rk3228-spi", },
{ .compatible = "rockchip,rk3288-spi", }, { .compatible = "rockchip,rk3288-spi", },
{ .compatible = "rockchip,rk3368-spi", },
{ .compatible = "rockchip,rk3399-spi", }, { .compatible = "rockchip,rk3399-spi", },
{ }, { },
}; };
......
This diff is collapsed.
...@@ -45,7 +45,6 @@ struct sh_msiof_spi_priv { ...@@ -45,7 +45,6 @@ struct sh_msiof_spi_priv {
void __iomem *mapbase; void __iomem *mapbase;
struct clk *clk; struct clk *clk;
struct platform_device *pdev; struct platform_device *pdev;
const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info; struct sh_msiof_spi_info *info;
struct completion done; struct completion done;
unsigned int tx_fifo_size; unsigned int tx_fifo_size;
...@@ -271,7 +270,7 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, ...@@ -271,7 +270,7 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps); scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps);
sh_msiof_write(p, TSCR, scr); sh_msiof_write(p, TSCR, scr);
if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX)) if (!(p->master->flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, RSCR, scr); sh_msiof_write(p, RSCR, scr);
} }
...@@ -336,7 +335,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, ...@@ -336,7 +335,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
tmp |= lsb_first << MDR1_BITLSB_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT;
tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) { if (p->master->flags & SPI_MASTER_MUST_TX) {
/* These bits are reserved if RX needs TX */ /* These bits are reserved if RX needs TX */
tmp &= ~0x0000ffff; tmp &= ~0x0000ffff;
} }
...@@ -360,7 +359,7 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, ...@@ -360,7 +359,7 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
{ {
u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words); u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words);
if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX)) if (tx_buf || (p->master->flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, TMDR2, dr2); sh_msiof_write(p, TMDR2, dr2);
else else
sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1); sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
...@@ -1152,6 +1151,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ...@@ -1152,6 +1151,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
{ {
struct resource *r; struct resource *r;
struct spi_master *master; struct spi_master *master;
const struct sh_msiof_chipdata *chipdata;
const struct of_device_id *of_id; const struct of_device_id *of_id;
struct sh_msiof_spi_priv *p; struct sh_msiof_spi_priv *p;
int i; int i;
...@@ -1170,10 +1170,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ...@@ -1170,10 +1170,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
of_id = of_match_device(sh_msiof_match, &pdev->dev); of_id = of_match_device(sh_msiof_match, &pdev->dev);
if (of_id) { if (of_id) {
p->chipdata = of_id->data; chipdata = of_id->data;
p->info = sh_msiof_spi_parse_dt(&pdev->dev); p->info = sh_msiof_spi_parse_dt(&pdev->dev);
} else { } else {
p->chipdata = (const void *)pdev->id_entry->driver_data; chipdata = (const void *)pdev->id_entry->driver_data;
p->info = dev_get_platdata(&pdev->dev); p->info = dev_get_platdata(&pdev->dev);
} }
...@@ -1217,8 +1217,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ...@@ -1217,8 +1217,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
/* Platform data may override FIFO sizes */ /* Platform data may override FIFO sizes */
p->tx_fifo_size = p->chipdata->tx_fifo_size; p->tx_fifo_size = chipdata->tx_fifo_size;
p->rx_fifo_size = p->chipdata->rx_fifo_size; p->rx_fifo_size = chipdata->rx_fifo_size;
if (p->info->tx_fifo_override) if (p->info->tx_fifo_override)
p->tx_fifo_size = p->info->tx_fifo_override; p->tx_fifo_size = p->info->tx_fifo_override;
if (p->info->rx_fifo_override) if (p->info->rx_fifo_override)
...@@ -1227,7 +1227,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ...@@ -1227,7 +1227,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
/* init master code */ /* init master code */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
master->flags = p->chipdata->master_flags; master->flags = chipdata->master_flags;
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect; master->num_chipselect = p->info->num_chipselect;
......
...@@ -82,7 +82,6 @@ struct spi_sh_data { ...@@ -82,7 +82,6 @@ struct spi_sh_data {
int irq; int irq;
struct spi_master *master; struct spi_master *master;
struct list_head queue; struct list_head queue;
struct workqueue_struct *workqueue;
struct work_struct ws; struct work_struct ws;
unsigned long cr1; unsigned long cr1;
wait_queue_head_t wait; wait_queue_head_t wait;
...@@ -380,7 +379,7 @@ static int spi_sh_transfer(struct spi_device *spi, struct spi_message *mesg) ...@@ -380,7 +379,7 @@ static int spi_sh_transfer(struct spi_device *spi, struct spi_message *mesg)
spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1); spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1);
list_add_tail(&mesg->queue, &ss->queue); list_add_tail(&mesg->queue, &ss->queue);
queue_work(ss->workqueue, &ss->ws); schedule_work(&ss->ws);
spin_unlock_irqrestore(&ss->lock, flags); spin_unlock_irqrestore(&ss->lock, flags);
...@@ -425,7 +424,7 @@ static int spi_sh_remove(struct platform_device *pdev) ...@@ -425,7 +424,7 @@ static int spi_sh_remove(struct platform_device *pdev)
struct spi_sh_data *ss = platform_get_drvdata(pdev); struct spi_sh_data *ss = platform_get_drvdata(pdev);
spi_unregister_master(ss->master); spi_unregister_master(ss->master);
destroy_workqueue(ss->workqueue); flush_work(&ss->ws);
free_irq(ss->irq, ss); free_irq(ss->irq, ss);
return 0; return 0;
...@@ -484,18 +483,11 @@ static int spi_sh_probe(struct platform_device *pdev) ...@@ -484,18 +483,11 @@ static int spi_sh_probe(struct platform_device *pdev)
spin_lock_init(&ss->lock); spin_lock_init(&ss->lock);
INIT_WORK(&ss->ws, spi_sh_work); INIT_WORK(&ss->ws, spi_sh_work);
init_waitqueue_head(&ss->wait); init_waitqueue_head(&ss->wait);
ss->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
if (ss->workqueue == NULL) {
dev_err(&pdev->dev, "create workqueue error\n");
ret = -EBUSY;
goto error1;
}
ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss); ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "request_irq error\n"); dev_err(&pdev->dev, "request_irq error\n");
goto error2; goto error1;
} }
master->num_chipselect = 2; master->num_chipselect = 2;
...@@ -514,8 +506,6 @@ static int spi_sh_probe(struct platform_device *pdev) ...@@ -514,8 +506,6 @@ static int spi_sh_probe(struct platform_device *pdev)
error3: error3:
free_irq(irq, ss); free_irq(irq, ss);
error2:
destroy_workqueue(ss->workqueue);
error1: error1:
spi_master_put(master); spi_master_put(master);
......
...@@ -167,6 +167,11 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool enable) ...@@ -167,6 +167,11 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
} }
static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
{
return SUN4I_FIFO_DEPTH - 1;
}
static int sun4i_spi_transfer_one(struct spi_master *master, static int sun4i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *tfr) struct spi_transfer *tfr)
...@@ -402,6 +407,8 @@ static int sun4i_spi_probe(struct platform_device *pdev) ...@@ -402,6 +407,8 @@ static int sun4i_spi_probe(struct platform_device *pdev)
} }
sspi->master = master; sspi->master = master;
master->max_speed_hz = 100 * 1000 * 1000;
master->min_speed_hz = 3 * 1000;
master->set_cs = sun4i_spi_set_cs; master->set_cs = sun4i_spi_set_cs;
master->transfer_one = sun4i_spi_transfer_one; master->transfer_one = sun4i_spi_transfer_one;
master->num_chipselect = 4; master->num_chipselect = 4;
...@@ -409,6 +416,7 @@ static int sun4i_spi_probe(struct platform_device *pdev) ...@@ -409,6 +416,7 @@ static int sun4i_spi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_MASK(8); master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->max_transfer_size = sun4i_spi_max_transfer_size;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) { if (IS_ERR(sspi->hclk)) {
......
...@@ -153,6 +153,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable) ...@@ -153,6 +153,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
} }
static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
{
return SUN6I_FIFO_DEPTH - 1;
}
static int sun6i_spi_transfer_one(struct spi_master *master, static int sun6i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi, struct spi_device *spi,
...@@ -394,6 +398,8 @@ static int sun6i_spi_probe(struct platform_device *pdev) ...@@ -394,6 +398,8 @@ static int sun6i_spi_probe(struct platform_device *pdev)
} }
sspi->master = master; sspi->master = master;
master->max_speed_hz = 100 * 1000 * 1000;
master->min_speed_hz = 3 * 1000;
master->set_cs = sun6i_spi_set_cs; master->set_cs = sun6i_spi_set_cs;
master->transfer_one = sun6i_spi_transfer_one; master->transfer_one = sun6i_spi_transfer_one;
master->num_chipselect = 4; master->num_chipselect = 4;
...@@ -401,6 +407,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) ...@@ -401,6 +407,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_MASK(8); master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->max_transfer_size = sun6i_spi_max_transfer_size;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) { if (IS_ERR(sspi->hclk)) {
......
...@@ -141,7 +141,7 @@ static int ti_qspi_setup(struct spi_device *spi) ...@@ -141,7 +141,7 @@ static int ti_qspi_setup(struct spi_device *spi)
u32 clk_ctrl_reg, clk_rate, clk_mask; u32 clk_ctrl_reg, clk_rate, clk_mask;
if (spi->master->busy) { if (spi->master->busy) {
dev_dbg(qspi->dev, "master busy doing other trasnfers\n"); dev_dbg(qspi->dev, "master busy doing other transfers\n");
return -EBUSY; return -EBUSY;
} }
......
...@@ -133,8 +133,6 @@ struct pch_spi_dma_ctrl { ...@@ -133,8 +133,6 @@ struct pch_spi_dma_ctrl {
* @io_remap_addr: The remapped PCI base address * @io_remap_addr: The remapped PCI base address
* @master: Pointer to the SPI master structure * @master: Pointer to the SPI master structure
* @work: Reference to work queue handler * @work: Reference to work queue handler
* @wk: Workqueue for carrying out execution of the
* requests
* @wait: Wait queue for waking up upon receiving an * @wait: Wait queue for waking up upon receiving an
* interrupt. * interrupt.
* @transfer_complete: Status of SPI Transfer * @transfer_complete: Status of SPI Transfer
...@@ -169,7 +167,6 @@ struct pch_spi_data { ...@@ -169,7 +167,6 @@ struct pch_spi_data {
unsigned long io_base_addr; unsigned long io_base_addr;
struct spi_master *master; struct spi_master *master;
struct work_struct work; struct work_struct work;
struct workqueue_struct *wk;
wait_queue_head_t wait; wait_queue_head_t wait;
u8 transfer_complete; u8 transfer_complete;
u8 bcurrent_msg_processing; u8 bcurrent_msg_processing;
...@@ -517,8 +514,7 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) ...@@ -517,8 +514,7 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
dev_dbg(&pspi->dev, "%s - Invoked list_add_tail\n", __func__); dev_dbg(&pspi->dev, "%s - Invoked list_add_tail\n", __func__);
/* schedule work queue to run */ schedule_work(&data->work);
queue_work(data->wk, &data->work);
dev_dbg(&pspi->dev, "%s - Invoked queue work\n", __func__); dev_dbg(&pspi->dev, "%s - Invoked queue work\n", __func__);
retval = 0; retval = 0;
...@@ -674,7 +670,7 @@ static void pch_spi_nomore_transfer(struct pch_spi_data *data) ...@@ -674,7 +670,7 @@ static void pch_spi_nomore_transfer(struct pch_spi_data *data)
*more messages) *more messages)
*/ */
dev_dbg(&data->master->dev, "%s:Invoke queue_work\n", __func__); dev_dbg(&data->master->dev, "%s:Invoke queue_work\n", __func__);
queue_work(data->wk, &data->work); schedule_work(&data->work);
} else if (data->board_dat->suspend_sts || } else if (data->board_dat->suspend_sts ||
data->status == STATUS_EXITING) { data->status == STATUS_EXITING) {
dev_dbg(&data->master->dev, dev_dbg(&data->master->dev,
...@@ -1266,14 +1262,7 @@ static void pch_spi_free_resources(struct pch_spi_board_data *board_dat, ...@@ -1266,14 +1262,7 @@ static void pch_spi_free_resources(struct pch_spi_board_data *board_dat,
{ {
dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__);
/* free workqueue */ flush_work(&data->work);
if (data->wk != NULL) {
destroy_workqueue(data->wk);
data->wk = NULL;
dev_dbg(&board_dat->pdev->dev,
"%s destroy_workqueue invoked successfully\n",
__func__);
}
} }
static int pch_spi_get_resources(struct pch_spi_board_data *board_dat, static int pch_spi_get_resources(struct pch_spi_board_data *board_dat,
...@@ -1283,14 +1272,6 @@ static int pch_spi_get_resources(struct pch_spi_board_data *board_dat, ...@@ -1283,14 +1272,6 @@ static int pch_spi_get_resources(struct pch_spi_board_data *board_dat,
dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__);
/* create workqueue */
data->wk = create_singlethread_workqueue(KBUILD_MODNAME);
if (!data->wk) {
dev_err(&board_dat->pdev->dev,
"%s create_singlet hread_workqueue failed\n", __func__);
retval = -EBUSY;
goto err_return;
}
/* reset PCH SPI h/w */ /* reset PCH SPI h/w */
pch_spi_reset(data->master); pch_spi_reset(data->master);
...@@ -1299,7 +1280,6 @@ static int pch_spi_get_resources(struct pch_spi_board_data *board_dat, ...@@ -1299,7 +1280,6 @@ static int pch_spi_get_resources(struct pch_spi_board_data *board_dat,
dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true\n", __func__); dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true\n", __func__);
err_return:
if (retval != 0) { if (retval != 0) {
dev_err(&board_dat->pdev->dev, dev_err(&board_dat->pdev->dev,
"%s FAIL:invoking pch_spi_free_resources\n", __func__); "%s FAIL:invoking pch_spi_free_resources\n", __func__);
......
...@@ -72,7 +72,6 @@ ...@@ -72,7 +72,6 @@
struct txx9spi { struct txx9spi {
struct workqueue_struct *workqueue;
struct work_struct work; struct work_struct work;
spinlock_t lock; /* protect 'queue' */ spinlock_t lock; /* protect 'queue' */
struct list_head queue; struct list_head queue;
...@@ -315,7 +314,7 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) ...@@ -315,7 +314,7 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
spin_lock_irqsave(&c->lock, flags); spin_lock_irqsave(&c->lock, flags);
list_add_tail(&m->queue, &c->queue); list_add_tail(&m->queue, &c->queue);
queue_work(c->workqueue, &c->work); schedule_work(&c->work);
spin_unlock_irqrestore(&c->lock, flags); spin_unlock_irqrestore(&c->lock, flags);
return 0; return 0;
...@@ -374,10 +373,6 @@ static int txx9spi_probe(struct platform_device *dev) ...@@ -374,10 +373,6 @@ static int txx9spi_probe(struct platform_device *dev)
if (ret) if (ret)
goto exit; goto exit;
c->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
if (!c->workqueue)
goto exit_busy;
c->last_chipselect = -1; c->last_chipselect = -1;
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n", dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
...@@ -400,8 +395,6 @@ static int txx9spi_probe(struct platform_device *dev) ...@@ -400,8 +395,6 @@ static int txx9spi_probe(struct platform_device *dev)
exit_busy: exit_busy:
ret = -EBUSY; ret = -EBUSY;
exit: exit:
if (c->workqueue)
destroy_workqueue(c->workqueue);
clk_disable(c->clk); clk_disable(c->clk);
spi_master_put(master); spi_master_put(master);
return ret; return ret;
...@@ -412,7 +405,7 @@ static int txx9spi_remove(struct platform_device *dev) ...@@ -412,7 +405,7 @@ static int txx9spi_remove(struct platform_device *dev)
struct spi_master *master = platform_get_drvdata(dev); struct spi_master *master = platform_get_drvdata(dev);
struct txx9spi *c = spi_master_get_devdata(master); struct txx9spi *c = spi_master_get_devdata(master);
destroy_workqueue(c->workqueue); flush_work(&c->work);
clk_disable(c->clk); clk_disable(c->clk);
return 0; return 0;
} }
......
...@@ -341,9 +341,10 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) ...@@ -341,9 +341,10 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */ if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
complete(&xspi->done); complete(&xspi->done);
return IRQ_HANDLED;
} }
return IRQ_HANDLED; return IRQ_NONE;
} }
static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi) static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
...@@ -455,7 +456,10 @@ static int xilinx_spi_probe(struct platform_device *pdev) ...@@ -455,7 +456,10 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->buffer_size = xilinx_spi_find_buffer_size(xspi); xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
xspi->irq = platform_get_irq(pdev, 0); xspi->irq = platform_get_irq(pdev, 0);
if (xspi->irq >= 0) { if (xspi->irq < 0 && xspi->irq != -ENXIO) {
ret = xspi->irq;
goto put_master;
} else if (xspi->irq >= 0) {
/* Register for SPI Interrupt */ /* Register for SPI Interrupt */
ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
dev_name(&pdev->dev), xspi); dev_name(&pdev->dev), xspi);
......
...@@ -851,6 +851,20 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) ...@@ -851,6 +851,20 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
return 0; return 0;
} }
#else /* !CONFIG_HAS_DMA */ #else /* !CONFIG_HAS_DMA */
static inline int spi_map_buf(struct spi_master *master,
struct device *dev, struct sg_table *sgt,
void *buf, size_t len,
enum dma_data_direction dir)
{
return -EINVAL;
}
static inline void spi_unmap_buf(struct spi_master *master,
struct device *dev, struct sg_table *sgt,
enum dma_data_direction dir)
{
}
static inline int __spi_map_msg(struct spi_master *master, static inline int __spi_map_msg(struct spi_master *master,
struct spi_message *msg) struct spi_message *msg)
{ {
...@@ -1057,7 +1071,6 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); ...@@ -1057,7 +1071,6 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
* __spi_pump_messages - function which processes spi message queue * __spi_pump_messages - function which processes spi message queue
* @master: master to process queue for * @master: master to process queue for
* @in_kthread: true if we are in the context of the message pump thread * @in_kthread: true if we are in the context of the message pump thread
* @bus_locked: true if the bus mutex is held when calling this function
* *
* This function checks if there is any spi message in the queue that * This function checks if there is any spi message in the queue that
* needs processing and if so call out to the driver to initialize hardware * needs processing and if so call out to the driver to initialize hardware
...@@ -1067,8 +1080,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); ...@@ -1067,8 +1080,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
* inside spi_sync(); the queue extraction handling at the top of the * inside spi_sync(); the queue extraction handling at the top of the
* function should deal with this safely. * function should deal with this safely.
*/ */
static void __spi_pump_messages(struct spi_master *master, bool in_kthread, static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
bool bus_locked)
{ {
unsigned long flags; unsigned long flags;
bool was_busy = false; bool was_busy = false;
...@@ -1140,6 +1152,8 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread, ...@@ -1140,6 +1152,8 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
master->busy = true; master->busy = true;
spin_unlock_irqrestore(&master->queue_lock, flags); spin_unlock_irqrestore(&master->queue_lock, flags);
mutex_lock(&master->io_mutex);
if (!was_busy && master->auto_runtime_pm) { if (!was_busy && master->auto_runtime_pm) {
ret = pm_runtime_get_sync(master->dev.parent); ret = pm_runtime_get_sync(master->dev.parent);
if (ret < 0) { if (ret < 0) {
...@@ -1164,9 +1178,6 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread, ...@@ -1164,9 +1178,6 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
} }
} }
if (!bus_locked)
mutex_lock(&master->bus_lock_mutex);
trace_spi_message_start(master->cur_msg); trace_spi_message_start(master->cur_msg);
if (master->prepare_message) { if (master->prepare_message) {
...@@ -1196,8 +1207,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread, ...@@ -1196,8 +1207,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
} }
out: out:
if (!bus_locked) mutex_unlock(&master->io_mutex);
mutex_unlock(&master->bus_lock_mutex);
/* Prod the scheduler in case transfer_one() was busy waiting */ /* Prod the scheduler in case transfer_one() was busy waiting */
if (!ret) if (!ret)
...@@ -1213,7 +1223,7 @@ static void spi_pump_messages(struct kthread_work *work) ...@@ -1213,7 +1223,7 @@ static void spi_pump_messages(struct kthread_work *work)
struct spi_master *master = struct spi_master *master =
container_of(work, struct spi_master, pump_messages); container_of(work, struct spi_master, pump_messages);
__spi_pump_messages(master, true, master->bus_lock_flag); __spi_pump_messages(master, true);
} }
static int spi_init_queue(struct spi_master *master) static int spi_init_queue(struct spi_master *master)
...@@ -1886,6 +1896,7 @@ int spi_register_master(struct spi_master *master) ...@@ -1886,6 +1896,7 @@ int spi_register_master(struct spi_master *master)
spin_lock_init(&master->queue_lock); spin_lock_init(&master->queue_lock);
spin_lock_init(&master->bus_lock_spinlock); spin_lock_init(&master->bus_lock_spinlock);
mutex_init(&master->bus_lock_mutex); mutex_init(&master->bus_lock_mutex);
mutex_init(&master->io_mutex);
master->bus_lock_flag = 0; master->bus_lock_flag = 0;
init_completion(&master->xfer_completion); init_completion(&master->xfer_completion);
if (!master->max_dma_len) if (!master->max_dma_len)
...@@ -2738,6 +2749,7 @@ int spi_flash_read(struct spi_device *spi, ...@@ -2738,6 +2749,7 @@ int spi_flash_read(struct spi_device *spi,
{ {
struct spi_master *master = spi->master; struct spi_master *master = spi->master;
struct device *rx_dev = NULL;
int ret; int ret;
if ((msg->opcode_nbits == SPI_NBITS_DUAL || if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
...@@ -2763,9 +2775,24 @@ int spi_flash_read(struct spi_device *spi, ...@@ -2763,9 +2775,24 @@ int spi_flash_read(struct spi_device *spi,
return ret; return ret;
} }
} }
mutex_lock(&master->bus_lock_mutex); mutex_lock(&master->bus_lock_mutex);
mutex_lock(&master->io_mutex);
if (master->dma_rx) {
rx_dev = master->dma_rx->device->dev;
ret = spi_map_buf(master, rx_dev, &msg->rx_sg,
msg->buf, msg->len,
DMA_FROM_DEVICE);
if (!ret)
msg->cur_msg_mapped = true;
}
ret = master->spi_flash_read(spi, msg); ret = master->spi_flash_read(spi, msg);
if (msg->cur_msg_mapped)
spi_unmap_buf(master, rx_dev, &msg->rx_sg,
DMA_FROM_DEVICE);
mutex_unlock(&master->io_mutex);
mutex_unlock(&master->bus_lock_mutex); mutex_unlock(&master->bus_lock_mutex);
if (master->auto_runtime_pm) if (master->auto_runtime_pm)
pm_runtime_put(master->dev.parent); pm_runtime_put(master->dev.parent);
...@@ -2785,8 +2812,7 @@ static void spi_complete(void *arg) ...@@ -2785,8 +2812,7 @@ static void spi_complete(void *arg)
complete(arg); complete(arg);
} }
static int __spi_sync(struct spi_device *spi, struct spi_message *message, static int __spi_sync(struct spi_device *spi, struct spi_message *message)
int bus_locked)
{ {
DECLARE_COMPLETION_ONSTACK(done); DECLARE_COMPLETION_ONSTACK(done);
int status; int status;
...@@ -2804,9 +2830,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, ...@@ -2804,9 +2830,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync); SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync); SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
if (!bus_locked)
mutex_lock(&master->bus_lock_mutex);
/* If we're not using the legacy transfer method then we will /* If we're not using the legacy transfer method then we will
* try to transfer in the calling context so special case. * try to transfer in the calling context so special case.
* This code would be less tricky if we could remove the * This code would be less tricky if we could remove the
...@@ -2824,9 +2847,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, ...@@ -2824,9 +2847,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
status = spi_async_locked(spi, message); status = spi_async_locked(spi, message);
} }
if (!bus_locked)
mutex_unlock(&master->bus_lock_mutex);
if (status == 0) { if (status == 0) {
/* Push out the messages in the calling context if we /* Push out the messages in the calling context if we
* can. * can.
...@@ -2836,7 +2856,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, ...@@ -2836,7 +2856,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
spi_sync_immediate); spi_sync_immediate);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
spi_sync_immediate); spi_sync_immediate);
__spi_pump_messages(master, false, bus_locked); __spi_pump_messages(master, false);
} }
wait_for_completion(&done); wait_for_completion(&done);
...@@ -2869,7 +2889,13 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, ...@@ -2869,7 +2889,13 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
*/ */
int spi_sync(struct spi_device *spi, struct spi_message *message) int spi_sync(struct spi_device *spi, struct spi_message *message)
{ {
return __spi_sync(spi, message, spi->master->bus_lock_flag); int ret;
mutex_lock(&spi->master->bus_lock_mutex);
ret = __spi_sync(spi, message);
mutex_unlock(&spi->master->bus_lock_mutex);
return ret;
} }
EXPORT_SYMBOL_GPL(spi_sync); EXPORT_SYMBOL_GPL(spi_sync);
...@@ -2891,7 +2917,7 @@ EXPORT_SYMBOL_GPL(spi_sync); ...@@ -2891,7 +2917,7 @@ EXPORT_SYMBOL_GPL(spi_sync);
*/ */
int spi_sync_locked(struct spi_device *spi, struct spi_message *message) int spi_sync_locked(struct spi_device *spi, struct spi_message *message)
{ {
return __spi_sync(spi, message, 1); return __spi_sync(spi, message);
} }
EXPORT_SYMBOL_GPL(spi_sync_locked); EXPORT_SYMBOL_GPL(spi_sync_locked);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spidev.h> #include <linux/spi/spidev.h>
...@@ -700,6 +701,43 @@ static const struct of_device_id spidev_dt_ids[] = { ...@@ -700,6 +701,43 @@ static const struct of_device_id spidev_dt_ids[] = {
MODULE_DEVICE_TABLE(of, spidev_dt_ids); MODULE_DEVICE_TABLE(of, spidev_dt_ids);
#endif #endif
#ifdef CONFIG_ACPI
/* Dummy SPI devices not to be used in production systems */
#define SPIDEV_ACPI_DUMMY 1
static const struct acpi_device_id spidev_acpi_ids[] = {
/*
* The ACPI SPT000* devices are only meant for development and
* testing. Systems used in production should have a proper ACPI
* description of the connected peripheral and they should also use
* a proper driver instead of poking directly to the SPI bus.
*/
{ "SPT0001", SPIDEV_ACPI_DUMMY },
{ "SPT0002", SPIDEV_ACPI_DUMMY },
{ "SPT0003", SPIDEV_ACPI_DUMMY },
{},
};
MODULE_DEVICE_TABLE(acpi, spidev_acpi_ids);
static void spidev_probe_acpi(struct spi_device *spi)
{
const struct acpi_device_id *id;
if (!has_acpi_companion(&spi->dev))
return;
id = acpi_match_device(spidev_acpi_ids, &spi->dev);
if (WARN_ON(!id))
return;
if (id->driver_data == SPIDEV_ACPI_DUMMY)
dev_warn(&spi->dev, "do not use this driver in production systems!\n");
}
#else
static inline void spidev_probe_acpi(struct spi_device *spi) {}
#endif
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int spidev_probe(struct spi_device *spi) static int spidev_probe(struct spi_device *spi)
...@@ -719,6 +757,8 @@ static int spidev_probe(struct spi_device *spi) ...@@ -719,6 +757,8 @@ static int spidev_probe(struct spi_device *spi)
!of_match_device(spidev_dt_ids, &spi->dev)); !of_match_device(spidev_dt_ids, &spi->dev));
} }
spidev_probe_acpi(spi);
/* Allocate driver data */ /* Allocate driver data */
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
if (!spidev) if (!spidev)
...@@ -789,6 +829,7 @@ static struct spi_driver spidev_spi_driver = { ...@@ -789,6 +829,7 @@ static struct spi_driver spidev_spi_driver = {
.driver = { .driver = {
.name = "spidev", .name = "spidev",
.of_match_table = of_match_ptr(spidev_dt_ids), .of_match_table = of_match_ptr(spidev_dt_ids),
.acpi_match_table = ACPI_PTR(spidev_acpi_ids),
}, },
.probe = spidev_probe, .probe = spidev_probe,
.remove = spidev_remove, .remove = spidev_remove,
......
...@@ -38,6 +38,7 @@ struct s3c64xx_spi_csinfo { ...@@ -38,6 +38,7 @@ struct s3c64xx_spi_csinfo {
struct s3c64xx_spi_info { struct s3c64xx_spi_info {
int src_clk_nr; int src_clk_nr;
int num_cs; int num_cs;
bool no_cs;
int (*cfg_gpio)(void); int (*cfg_gpio)(void);
dma_filter_fn filter; dma_filter_fn filter;
void *dma_tx; void *dma_tx;
......
...@@ -312,8 +312,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) ...@@ -312,8 +312,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @flags: other constraints relevant to this driver * @flags: other constraints relevant to this driver
* @max_transfer_size: function that returns the max transfer size for * @max_transfer_size: function that returns the max transfer size for
* a &spi_device; may be %NULL, so the default %SIZE_MAX will be used. * a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
* @io_mutex: mutex for physical bus access
* @bus_lock_spinlock: spinlock for SPI bus locking * @bus_lock_spinlock: spinlock for SPI bus locking
* @bus_lock_mutex: mutex for SPI bus locking * @bus_lock_mutex: mutex for exclusion of multiple callers
* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use * @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
* @setup: updates the device mode and clocking records used by a * @setup: updates the device mode and clocking records used by a
* device's SPI controller; protocol code may call this. This * device's SPI controller; protocol code may call this. This
...@@ -446,6 +447,9 @@ struct spi_master { ...@@ -446,6 +447,9 @@ struct spi_master {
*/ */
size_t (*max_transfer_size)(struct spi_device *spi); size_t (*max_transfer_size)(struct spi_device *spi);
/* I/O mutex */
struct mutex io_mutex;
/* lock and mutex for SPI bus locking */ /* lock and mutex for SPI bus locking */
spinlock_t bus_lock_spinlock; spinlock_t bus_lock_spinlock;
struct mutex bus_lock_mutex; struct mutex bus_lock_mutex;
...@@ -1143,6 +1147,8 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd) ...@@ -1143,6 +1147,8 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd)
* @opcode_nbits: number of lines to send opcode * @opcode_nbits: number of lines to send opcode
* @addr_nbits: number of lines to send address * @addr_nbits: number of lines to send address
* @data_nbits: number of lines for data * @data_nbits: number of lines for data
* @rx_sg: Scatterlist for receive data read from flash
* @cur_msg_mapped: message has been mapped for DMA
*/ */
struct spi_flash_read_message { struct spi_flash_read_message {
void *buf; void *buf;
...@@ -1155,6 +1161,8 @@ struct spi_flash_read_message { ...@@ -1155,6 +1161,8 @@ struct spi_flash_read_message {
u8 opcode_nbits; u8 opcode_nbits;
u8 addr_nbits; u8 addr_nbits;
u8 data_nbits; u8 data_nbits;
struct sg_table rx_sg;
bool cur_msg_mapped;
}; };
/* SPI core interface for flash read support */ /* SPI core interface for flash read support */
......
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