Commit b39de277 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull spi updates from Mark Brown:
 "There's only one big change in this release but it's a very big
  change: Geert Uytterhoeven has implemented support for SPI slave mode.

  This feature has been on the cards since the subsystem was originally
  merged back in the mists of time so it's great that Geert stepped up
  and finally implemented it.

   - SPI slave support, together with wholesale renaming of SPI
     controllers from master to controller which went surprisingly
     smoothly. This is already used with Renesas SoCs and support is in
     the works for i.MX too.

   - New drivers for Meson SPICC and ST STM32"

* tag 'spi-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (57 commits)
  spi: loopback-test: Fix kfree() NULL pointer error.
  spi: loopback-test: fix spelling mistake: "reruning" -> "rerunning"
  spi: sirf: fix spelling mistake: "registerred" -> "registered"
  spi: stm32: fix potential dereference null return value
  spi: stm32: enhance DMA error management
  spi: stm32: add runtime PM support
  spi: stm32: use normal conditional statements instead of ternary operator
  spi: stm32: replace st, spi-midi with st, spi-midi-ns to fit bindings
  spi: stm32: fix example with st, spi-midi-ns property
  spi: stm32: fix compatible to fit with new bindings
  spi: stm32: use SoC specific compatible
  spi: rockchip: Disable Runtime PM when chip select is asserted
  spi: rockchip: Set GPIO_SS flag to enable Slave Select with GPIO CS
  spi: atmel: fix corrupted data issue on SAM9 family SoCs
  spi: stm32: fix error check on mbr being -ve
  spi: add driver for STM32 SPI controller
  spi: Document the STM32 SPI bindings
  spi/bcm63xx: Fix checkpatch warnings
  spi: imx: Check for allocation failure earlier
  spi: mediatek: add spi support for mt2712 IC
  ...
parents d62eb5ed 082f6968
...@@ -38,6 +38,8 @@ Optional properties: ...@@ -38,6 +38,8 @@ Optional properties:
specifiers, one for transmission, and one for specifiers, one for transmission, and one for
reception. reception.
- dma-names : Must contain a list of two DMA names, "tx" and "rx". - dma-names : Must contain a list of two DMA names, "tx" and "rx".
- spi-slave : Empty property indicating the SPI controller is used
in slave mode.
- renesas,dtdl : delay sync signal (setup) in transmit mode. - renesas,dtdl : delay sync signal (setup) in transmit mode.
Must contain one of the following values: Must contain one of the following values:
0 (no bit delay) 0 (no bit delay)
......
SPI (Serial Peripheral Interface) busses SPI (Serial Peripheral Interface) busses
SPI busses can be described with a node for the SPI master device SPI busses can be described with a node for the SPI controller device
and a set of child nodes for each SPI slave on the bus. For this and a set of child nodes for each SPI slave on the bus. The system's SPI
discussion, it is assumed that the system's SPI controller is in controller may be described for use in SPI master mode or in SPI slave mode,
SPI master mode. This binding does not describe SPI controllers but not for both at the same time.
in slave mode.
The SPI master node requires the following properties: The SPI controller node requires the following properties:
- compatible - Name of SPI bus controller following generic names
recommended practice.
In master mode, the SPI controller node requires the following additional
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
recommended practice. In slave mode, the SPI controller node requires one additional property:
- spi-slave - Empty property.
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
...@@ -21,7 +27,7 @@ assumption that board specific platform code will be used to manage ...@@ -21,7 +27,7 @@ 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 properties: Optional properties (master mode only):
- cs-gpios - gpios chip select. - cs-gpios - gpios chip select.
- num-cs - total number of chipselects. - num-cs - total number of chipselects.
...@@ -41,28 +47,36 @@ cs1 : native ...@@ -41,28 +47,36 @@ cs1 : native
cs2 : &gpio1 1 0 cs2 : &gpio1 1 0
cs3 : &gpio1 2 0 cs3 : &gpio1 2 0
SPI slave nodes must be children of the SPI master node and can
contain the following properties. SPI slave nodes must be children of the SPI controller node.
- reg - (required) chip select address of device.
- compatible - (required) name of SPI device following generic names In master mode, one or more slave nodes (up to the number of chip selects) can
recommended practice. be present. Required properties are:
- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz. - compatible - Name of SPI device following generic names recommended
- spi-cpol - (optional) Empty property indicating device requires practice.
inverse clock polarity (CPOL) mode. - reg - Chip select address of device.
- spi-cpha - (optional) Empty property indicating device requires - spi-max-frequency - Maximum SPI clocking speed of device in Hz.
shifted clock phase (CPHA) mode.
- spi-cs-high - (optional) Empty property indicating device requires In slave mode, the (single) slave node is optional.
chip select active high. If present, it must be called "slave". Required properties are:
- spi-3wire - (optional) Empty property indicating device requires - compatible - Name of SPI device following generic names recommended
3-wire mode. practice.
- spi-lsb-first - (optional) Empty property indicating device requires
LSB first mode. All slave nodes can contain the following optional properties:
- spi-tx-bus-width - (optional) The bus width (number of data wires) that is - spi-cpol - Empty property indicating device requires inverse clock
used for MOSI. Defaults to 1 if not present. polarity (CPOL) mode.
- spi-rx-bus-width - (optional) The bus width (number of data wires) that is - spi-cpha - Empty property indicating device requires shifted clock
used for MISO. Defaults to 1 if not present. phase (CPHA) mode.
- spi-rx-delay-us - (optional) Microsecond delay after a read transfer. - spi-cs-high - Empty property indicating device requires chip select
- spi-tx-delay-us - (optional) Microsecond delay after a write transfer. active high.
- spi-3wire - Empty property indicating device requires 3-wire mode.
- spi-lsb-first - Empty property indicating device requires LSB first mode.
- spi-tx-bus-width - The bus width (number of data wires) that is used for MOSI.
Defaults to 1 if not present.
- spi-rx-bus-width - The bus width (number of data wires) that is used for MISO.
Defaults to 1 if not present.
- spi-rx-delay-us - Microsecond delay after a read transfer.
- spi-tx-delay-us - 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 using 2 wires (DUAL) or 4 It allows data in the SPI system to be transferred using 2 wires (DUAL) or 4
......
...@@ -20,3 +20,34 @@ Required properties: ...@@ -20,3 +20,34 @@ Required properties:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
}; };
* SPICC (SPI Communication Controller)
The Meson SPICC is generic SPI controller for general purpose Full-Duplex
communications with dedicated 16 words RX/TX PIO FIFOs.
Required properties:
- compatible: should be "amlogic,meson-gx-spicc" on Amlogic GX SoCs.
- reg: physical base address and length of the controller registers
- interrupts: The interrupt specifier
- clock-names: Must contain "core"
- clocks: phandle of the input clock for the baud rate generator
- #address-cells: should be 1
- #size-cells: should be 0
Optional properties:
- resets: phandle of the internal reset line
See ../spi/spi-bus.txt for more details on SPI bus master and slave devices
required and optional properties.
Example :
spi@c1108d80 {
compatible = "amlogic,meson-gx-spicc";
reg = <0xc1108d80 0x80>;
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "core";
clocks = <&clk81>;
#address-cells = <1>;
#size-cells = <0>;
};
...@@ -3,7 +3,9 @@ Binding for MTK SPI controller ...@@ -3,7 +3,9 @@ Binding for MTK SPI controller
Required properties: Required properties:
- compatible: should be one of the following. - compatible: should be one of the following.
- mediatek,mt2701-spi: for mt2701 platforms - mediatek,mt2701-spi: for mt2701 platforms
- mediatek,mt2712-spi: for mt2712 platforms
- mediatek,mt6589-spi: for mt6589 platforms - mediatek,mt6589-spi: for mt6589 platforms
- mediatek,mt7622-spi: for mt7622 platforms
- mediatek,mt8135-spi: for mt8135 platforms - mediatek,mt8135-spi: for mt8135 platforms
- mediatek,mt8173-spi: for mt8173 platforms - mediatek,mt8173-spi: for mt8173 platforms
......
STMicroelectronics STM32 SPI Controller
The STM32 SPI controller is used to communicate with external devices using
the Serial Peripheral Interface. It supports full-duplex, half-duplex and
simplex synchronous serial communication with external devices. It supports
from 4 to 32-bit data size. Although it can be configured as master or slave,
only master is supported by the driver.
Required properties:
- compatible: Must be "st,stm32h7-spi".
- reg: Offset and length of the device's register set.
- interrupts: Must contain the interrupt id.
- clocks: Must contain an entry for spiclk (which feeds the internal clock
generator).
- #address-cells: Number of cells required to define a chip select address.
- #size-cells: Should be zero.
Optional properties:
- resets: Must contain the phandle to the reset controller.
- A pinctrl state named "default" may be defined to set pins in mode of
operation for SPI transfer.
- dmas: DMA specifiers for tx and rx dma. DMA fifo mode must be used. See the
STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt.
- dma-names: DMA request names should include "tx" and "rx" if present.
- cs-gpios: list of GPIO chip selects. See the SPI bus bindings,
Documentation/devicetree/bindings/spi/spi-bus.txt
Child nodes represent devices on the SPI bus
See ../spi/spi-bus.txt
Optional properties:
- st,spi-midi-ns: (Master Inter-Data Idleness) minimum time delay in
nanoseconds inserted between two consecutive data frames.
Example:
spi2: spi@40003800 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "st,stm32h7-spi";
reg = <0x40003800 0x400>;
interrupts = <36>;
clocks = <&rcc SPI2_CK>;
resets = <&rcc 1166>;
dmas = <&dmamux1 0 39 0x400 0x01>,
<&dmamux1 1 40 0x400 0x01>;
dma-names = "rx", "tx";
pinctrl-0 = <&spi2_pins_b>;
pinctrl-names = "default";
cs-gpios = <&gpioa 11 0>;
aardvark@0 {
compatible = "totalphase,aardvark";
reg = <0>;
spi-max-frequency = <4000000>;
st,spi-midi-ns = <4000>;
};
};
...@@ -62,8 +62,8 @@ chips described as using "three wire" signaling: SCK, data, nCSx. ...@@ -62,8 +62,8 @@ chips described as using "three wire" signaling: SCK, data, nCSx.
(That data line is sometimes called MOMI or SISO.) (That data line is sometimes called MOMI or SISO.)
Microcontrollers often support both master and slave sides of the SPI Microcontrollers often support both master and slave sides of the SPI
protocol. This document (and Linux) currently only supports the master protocol. This document (and Linux) supports both the master and slave
side of SPI interactions. sides of SPI interactions.
Who uses it? On what kinds of systems? Who uses it? On what kinds of systems?
...@@ -154,9 +154,8 @@ control audio interfaces, present touchscreen sensors as input interfaces, ...@@ -154,9 +154,8 @@ control audio interfaces, present touchscreen sensors as input interfaces,
or monitor temperature and voltage levels during industrial processing. or monitor temperature and voltage levels during industrial processing.
And those might all be sharing the same controller driver. And those might all be sharing the same controller driver.
A "struct spi_device" encapsulates the master-side interface between A "struct spi_device" encapsulates the controller-side interface between
those two types of driver. At this writing, Linux has no slave side those two types of drivers.
programming interface.
There is a minimal core of SPI programming interfaces, focussing on There is a minimal core of SPI programming interfaces, focussing on
using the driver model to connect controller and protocol drivers using using the driver model to connect controller and protocol drivers using
...@@ -177,10 +176,24 @@ shows up in sysfs in several locations: ...@@ -177,10 +176,24 @@ shows up in sysfs in several locations:
/sys/bus/spi/drivers/D ... driver for one or more spi*.* devices /sys/bus/spi/drivers/D ... driver for one or more spi*.* devices
/sys/class/spi_master/spiB ... symlink (or actual device node) to /sys/class/spi_master/spiB ... symlink (or actual device node) to
a logical node which could hold class related state for the a logical node which could hold class related state for the SPI
controller managing bus "B". All spiB.* devices share one master controller managing bus "B". All spiB.* devices share one
physical SPI bus segment, with SCLK, MOSI, and MISO. physical SPI bus segment, with SCLK, MOSI, and MISO.
/sys/devices/.../CTLR/slave ... virtual file for (un)registering the
slave device for an SPI slave controller.
Writing the driver name of an SPI slave handler to this file
registers the slave device; writing "(null)" unregisters the slave
device.
Reading from this file shows the name of the slave device ("(null)"
if not registered).
/sys/class/spi_slave/spiB ... symlink (or actual device node) to
a logical node which could hold class related state for the SPI
slave controller on bus "B". When registered, a single spiB.*
device is present here, possible sharing the physical SPI bus
segment with other SPI slave devices.
Note that the actual location of the controller's class state depends Note that the actual location of the controller's class state depends
on whether you enabled CONFIG_SYSFS_DEPRECATED or not. At this time, on whether you enabled CONFIG_SYSFS_DEPRECATED or not. At this time,
the only class-specific state is the bus number ("B" in "spiB"), so the only class-specific state is the bus number ("B" in "spiB"), so
......
...@@ -393,6 +393,13 @@ config SPI_FSL_ESPI ...@@ -393,6 +393,13 @@ config SPI_FSL_ESPI
From MPC8536, 85xx platform uses the controller, and all P10xx, From MPC8536, 85xx platform uses the controller, and all P10xx,
P20xx, P30xx,P40xx, P50xx uses this controller. P20xx, P30xx,P40xx, P50xx uses this controller.
config SPI_MESON_SPICC
tristate "Amlogic Meson SPICC controller"
depends on ARCH_MESON || COMPILE_TEST
help
This enables master mode support for the SPICC (SPI communication
controller) available in Amlogic Meson SoCs.
config SPI_MESON_SPIFC config SPI_MESON_SPIFC
tristate "Amlogic Meson SPIFC controller" tristate "Amlogic Meson SPIFC controller"
depends on ARCH_MESON || COMPILE_TEST depends on ARCH_MESON || COMPILE_TEST
...@@ -457,6 +464,7 @@ config SPI_OMAP24XX ...@@ -457,6 +464,7 @@ config SPI_OMAP24XX
config SPI_TI_QSPI config SPI_TI_QSPI
tristate "DRA7xxx QSPI controller support" tristate "DRA7xxx QSPI controller support"
depends on HAS_DMA
depends on ARCH_OMAP2PLUS || COMPILE_TEST depends on ARCH_OMAP2PLUS || COMPILE_TEST
help help
QSPI master controller for DRA7xxx used for flash devices. QSPI master controller for DRA7xxx used for flash devices.
...@@ -619,6 +627,16 @@ config SPI_SIRF ...@@ -619,6 +627,16 @@ config SPI_SIRF
help help
SPI driver for CSR SiRFprimaII SoCs SPI driver for CSR SiRFprimaII SoCs
config SPI_STM32
tristate "STMicroelectronics STM32 SPI controller"
depends on ARCH_STM32 || COMPILE_TEST
help
SPI driver for STMicroelectonics STM32 SoCs.
STM32 SPI controller supports DMA and PIO modes. When DMA
is not available, the driver automatically falls back to
PIO mode.
config SPI_ST_SSC4 config SPI_ST_SSC4
tristate "STMicroelectronics SPI SSC-based driver" tristate "STMicroelectronics SPI SSC-based driver"
depends on ARCH_STI || COMPILE_TEST depends on ARCH_STI || COMPILE_TEST
...@@ -784,6 +802,30 @@ config SPI_TLE62X0 ...@@ -784,6 +802,30 @@ config SPI_TLE62X0
endif # SPI_MASTER endif # SPI_MASTER
# (slave support would go here) #
# SLAVE side ... listening to other SPI masters
#
config SPI_SLAVE
bool "SPI slave protocol handlers"
help
If your system has a slave-capable SPI controller, you can enable
slave protocol handlers.
if SPI_SLAVE
config SPI_SLAVE_TIME
tristate "SPI slave handler reporting boot up time"
help
SPI slave handler responding with the time of reception of the last
SPI message.
config SPI_SLAVE_SYSTEM_CONTROL
tristate "SPI slave handler controlling system state"
help
SPI slave handler to allow remote control of system reboot, power
off, halt, and suspend.
endif # SPI_SLAVE
endif # SPI endif # SPI
...@@ -53,6 +53,7 @@ obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o ...@@ -53,6 +53,7 @@ obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o
obj-$(CONFIG_SPI_JCORE) += spi-jcore.o obj-$(CONFIG_SPI_JCORE) += spi-jcore.o
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o
obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
...@@ -89,6 +90,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o ...@@ -89,6 +90,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_STM32) += spi-stm32.o
obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
...@@ -105,3 +107,7 @@ obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o ...@@ -105,3 +107,7 @@ obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
obj-$(CONFIG_SPI_XLP) += spi-xlp.o obj-$(CONFIG_SPI_XLP) += spi-xlp.o
obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o
# SPI slave protocol handlers
obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o
obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL) += spi-slave-system-control.o
...@@ -269,6 +269,7 @@ struct atmel_spi_caps { ...@@ -269,6 +269,7 @@ struct atmel_spi_caps {
bool is_spi2; bool is_spi2;
bool has_wdrbt; bool has_wdrbt;
bool has_dma_support; bool has_dma_support;
bool has_pdc_support;
}; };
/* /*
...@@ -1422,11 +1423,31 @@ static void atmel_get_caps(struct atmel_spi *as) ...@@ -1422,11 +1423,31 @@ static void atmel_get_caps(struct atmel_spi *as)
unsigned int version; unsigned int version;
version = atmel_get_version(as); version = atmel_get_version(as);
dev_info(&as->pdev->dev, "version: 0x%x\n", version);
as->caps.is_spi2 = version > 0x121; as->caps.is_spi2 = version > 0x121;
as->caps.has_wdrbt = version >= 0x210; as->caps.has_wdrbt = version >= 0x210;
#ifdef CONFIG_SOC_SAM_V4_V5
/*
* Atmel SoCs based on ARM9 (SAM9x) cores should not use spi_map_buf()
* since this later function tries to map buffers with dma_map_sg()
* even if they have not been allocated inside DMA-safe areas.
* On SoCs based on Cortex A5 (SAMA5Dx), it works anyway because for
* those ARM cores, the data cache follows the PIPT model.
* Also the L2 cache controller of SAMA5D2 uses the PIPT model too.
* In case of PIPT caches, there cannot be cache aliases.
* However on ARM9 cores, the data cache follows the VIVT model, hence
* the cache aliases issue can occur when buffers are allocated from
* DMA-unsafe areas, by vmalloc() for instance, where cache coherency is
* not taken into account or at least not handled completely (cache
* lines of aliases are not invalidated).
* This is not a theorical issue: it was reproduced when trying to mount
* a UBI file-system on a at91sam9g35ek board.
*/
as->caps.has_dma_support = false;
#else
as->caps.has_dma_support = version >= 0x212; as->caps.has_dma_support = version >= 0x212;
#endif
as->caps.has_pdc_support = version < 0x212;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1567,7 +1588,7 @@ static int atmel_spi_probe(struct platform_device *pdev) ...@@ -1567,7 +1588,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
} else if (ret == -EPROBE_DEFER) { } else if (ret == -EPROBE_DEFER) {
return ret; return ret;
} }
} else { } else if (as->caps.has_pdc_support) {
as->use_pdc = true; as->use_pdc = true;
} }
...@@ -1609,8 +1630,9 @@ static int atmel_spi_probe(struct platform_device *pdev) ...@@ -1609,8 +1630,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
goto out_free_dma; goto out_free_dma;
/* go! */ /* go! */
dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n", dev_info(&pdev->dev, "Atmel SPI Controller version 0x%x at 0x%08lx (irq %d)\n",
(unsigned long)regs->start, irq); atmel_get_version(as), (unsigned long)regs->start,
irq);
return 0; return 0;
......
...@@ -484,6 +484,7 @@ static const struct of_device_id bcm63xx_hsspi_of_match[] = { ...@@ -484,6 +484,7 @@ static const struct of_device_id bcm63xx_hsspi_of_match[] = {
{ .compatible = "brcm,bcm6328-hsspi", }, { .compatible = "brcm,bcm6328-hsspi", },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, bcm63xx_hsspi_of_match);
static struct platform_driver bcm63xx_hsspi_driver = { static struct platform_driver bcm63xx_hsspi_driver = {
.driver = { .driver = {
......
...@@ -147,7 +147,7 @@ struct bcm63xx_spi { ...@@ -147,7 +147,7 @@ struct bcm63xx_spi {
/* Platform data */ /* Platform data */
const unsigned long *reg_offsets; const unsigned long *reg_offsets;
unsigned fifo_size; unsigned int fifo_size;
unsigned int msg_type_shift; unsigned int msg_type_shift;
unsigned int msg_ctl_width; unsigned int msg_ctl_width;
...@@ -191,7 +191,7 @@ static inline void bcm_spi_writew(struct bcm63xx_spi *bs, ...@@ -191,7 +191,7 @@ static inline void bcm_spi_writew(struct bcm63xx_spi *bs,
#endif #endif
} }
static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = { static const unsigned int bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
{ 20000000, SPI_CLK_20MHZ }, { 20000000, SPI_CLK_20MHZ },
{ 12500000, SPI_CLK_12_50MHZ }, { 12500000, SPI_CLK_12_50MHZ },
{ 6250000, SPI_CLK_6_250MHZ }, { 6250000, SPI_CLK_6_250MHZ },
......
...@@ -873,9 +873,8 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, ...@@ -873,9 +873,8 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
return 0; return 0;
} }
#else #else
static struct davinci_spi_platform_data static int spi_davinci_get_pdata(struct platform_device *pdev,
*spi_davinci_get_pdata(struct platform_device *pdev, struct davinci_spi *dspi)
struct davinci_spi *dspi)
{ {
return -ENODEV; return -ENODEV;
} }
...@@ -965,7 +964,9 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -965,7 +964,9 @@ static int davinci_spi_probe(struct platform_device *pdev)
ret = -ENODEV; ret = -ENODEV;
goto free_master; goto free_master;
} }
clk_prepare_enable(dspi->clk); ret = clk_prepare_enable(dspi->clk);
if (ret)
goto free_master;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->bus_num = pdev->id; master->bus_num = pdev->id;
......
...@@ -1032,7 +1032,8 @@ static int dspi_probe(struct platform_device *pdev) ...@@ -1032,7 +1032,8 @@ static int dspi_probe(struct platform_device *pdev)
goto out_master_put; goto out_master_put;
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) { if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
if (dspi_request_dma(dspi, res->start)) { ret = dspi_request_dma(dspi, res->start);
if (ret < 0) {
dev_err(&pdev->dev, "can't get dma channels\n"); dev_err(&pdev->dev, "can't get dma channels\n");
goto out_clk_put; goto out_clk_put;
} }
......
...@@ -56,10 +56,6 @@ ...@@ -56,10 +56,6 @@
/* The maximum bytes that a sdma BD can transfer.*/ /* The maximum bytes that a sdma BD can transfer.*/
#define MAX_SDMA_BD_BYTES (1 << 15) #define MAX_SDMA_BD_BYTES (1 << 15)
struct spi_imx_config {
unsigned int speed_hz;
unsigned int bpw;
};
enum spi_imx_devtype { enum spi_imx_devtype {
IMX1_CSPI, IMX1_CSPI,
...@@ -74,7 +70,7 @@ struct spi_imx_data; ...@@ -74,7 +70,7 @@ struct spi_imx_data;
struct spi_imx_devtype_data { struct spi_imx_devtype_data {
void (*intctrl)(struct spi_imx_data *, int); void (*intctrl)(struct spi_imx_data *, int);
int (*config)(struct spi_device *, struct spi_imx_config *); int (*config)(struct spi_device *);
void (*trigger)(struct spi_imx_data *); void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *);
void (*reset)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *);
...@@ -94,7 +90,8 @@ struct spi_imx_data { ...@@ -94,7 +90,8 @@ struct spi_imx_data {
unsigned long spi_clk; unsigned long spi_clk;
unsigned int spi_bus_clk; unsigned int spi_bus_clk;
unsigned int bytes_per_word; unsigned int speed_hz;
unsigned int bits_per_word;
unsigned int spi_drctl; unsigned int spi_drctl;
unsigned int count; unsigned int count;
...@@ -203,34 +200,27 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, ...@@ -203,34 +200,27 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
return i; return i;
} }
static int spi_imx_bytes_per_word(const int bpw) static int spi_imx_bytes_per_word(const int bits_per_word)
{ {
return DIV_ROUND_UP(bpw, BITS_PER_BYTE); return DIV_ROUND_UP(bits_per_word, BITS_PER_BYTE);
} }
static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *transfer) struct spi_transfer *transfer)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(master); struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
unsigned int bpw, i; unsigned int bytes_per_word, i;
if (!master->dma_rx) if (!master->dma_rx)
return false; return false;
if (!transfer) bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
return false;
bpw = transfer->bits_per_word;
if (!bpw)
bpw = spi->bits_per_word;
bpw = spi_imx_bytes_per_word(bpw);
if (bpw != 1 && bpw != 2 && bpw != 4) if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
return false; return false;
for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) { for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) {
if (!(transfer->len % (i * bpw))) if (!(transfer->len % (i * bytes_per_word)))
break; break;
} }
...@@ -340,12 +330,11 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx) ...@@ -340,12 +330,11 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MX51_ECSPI_CTRL); writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
} }
static int mx51_ecspi_config(struct spi_device *spi, static int mx51_ecspi_config(struct spi_device *spi)
struct spi_imx_config *config)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
u32 ctrl = MX51_ECSPI_CTRL_ENABLE; u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
u32 clk = config->speed_hz, delay, reg; u32 clk = spi_imx->speed_hz, delay, reg;
u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG); u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
/* /*
...@@ -364,13 +353,13 @@ static int mx51_ecspi_config(struct spi_device *spi, ...@@ -364,13 +353,13 @@ static int mx51_ecspi_config(struct spi_device *spi,
ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl); ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl);
/* set clock speed */ /* set clock speed */
ctrl |= mx51_ecspi_clkdiv(spi_imx, config->speed_hz, &clk); ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->speed_hz, &clk);
spi_imx->spi_bus_clk = clk; spi_imx->spi_bus_clk = clk;
/* set chip select to use */ /* set chip select to use */
ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select); ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET; ctrl |= (spi_imx->bits_per_word - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select); cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
...@@ -501,21 +490,21 @@ static void mx31_trigger(struct spi_imx_data *spi_imx) ...@@ -501,21 +490,21 @@ static void mx31_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MXC_CSPICTRL); writel(reg, spi_imx->base + MXC_CSPICTRL);
} }
static int mx31_config(struct spi_device *spi, struct spi_imx_config *config) static int mx31_config(struct spi_device *spi)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER; unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
unsigned int clk; unsigned int clk;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz, &clk) << reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->speed_hz, &clk) <<
MX31_CSPICTRL_DR_SHIFT; MX31_CSPICTRL_DR_SHIFT;
spi_imx->spi_bus_clk = clk; spi_imx->spi_bus_clk = clk;
if (is_imx35_cspi(spi_imx)) { if (is_imx35_cspi(spi_imx)) {
reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT; reg |= (spi_imx->bits_per_word - 1) << MX35_CSPICTRL_BL_SHIFT;
reg |= MX31_CSPICTRL_SSCTL; reg |= MX31_CSPICTRL_SSCTL;
} else { } else {
reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT; reg |= (spi_imx->bits_per_word - 1) << MX31_CSPICTRL_BC_SHIFT;
} }
if (spi->mode & SPI_CPHA) if (spi->mode & SPI_CPHA)
...@@ -597,18 +586,18 @@ static void mx21_trigger(struct spi_imx_data *spi_imx) ...@@ -597,18 +586,18 @@ static void mx21_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MXC_CSPICTRL); writel(reg, spi_imx->base + MXC_CSPICTRL);
} }
static int mx21_config(struct spi_device *spi, struct spi_imx_config *config) static int mx21_config(struct spi_device *spi)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER; unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER;
unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
unsigned int clk; unsigned int clk;
reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz, max, &clk) reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, spi_imx->speed_hz, max, &clk)
<< MX21_CSPICTRL_DR_SHIFT; << MX21_CSPICTRL_DR_SHIFT;
spi_imx->spi_bus_clk = clk; spi_imx->spi_bus_clk = clk;
reg |= config->bpw - 1; reg |= spi_imx->bits_per_word - 1;
if (spi->mode & SPI_CPHA) if (spi->mode & SPI_CPHA)
reg |= MX21_CSPICTRL_PHA; reg |= MX21_CSPICTRL_PHA;
...@@ -666,17 +655,17 @@ static void mx1_trigger(struct spi_imx_data *spi_imx) ...@@ -666,17 +655,17 @@ static void mx1_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MXC_CSPICTRL); writel(reg, spi_imx->base + MXC_CSPICTRL);
} }
static int mx1_config(struct spi_device *spi, struct spi_imx_config *config) static int mx1_config(struct spi_device *spi)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER; unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
unsigned int clk; unsigned int clk;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz, &clk) << reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->speed_hz, &clk) <<
MX1_CSPICTRL_DR_SHIFT; MX1_CSPICTRL_DR_SHIFT;
spi_imx->spi_bus_clk = clk; spi_imx->spi_bus_clk = clk;
reg |= config->bpw - 1; reg |= spi_imx->bits_per_word - 1;
if (spi->mode & SPI_CPHA) if (spi->mode & SPI_CPHA)
reg |= MX1_CSPICTRL_PHA; reg |= MX1_CSPICTRL_PHA;
...@@ -841,15 +830,14 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id) ...@@ -841,15 +830,14 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int spi_imx_dma_configure(struct spi_master *master, static int spi_imx_dma_configure(struct spi_master *master)
int bytes_per_word)
{ {
int ret; int ret;
enum dma_slave_buswidth buswidth; enum dma_slave_buswidth buswidth;
struct dma_slave_config rx = {}, tx = {}; struct dma_slave_config rx = {}, tx = {};
struct spi_imx_data *spi_imx = spi_master_get_devdata(master); struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
switch (bytes_per_word) { switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
case 4: case 4:
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
break; break;
...@@ -883,8 +871,6 @@ static int spi_imx_dma_configure(struct spi_master *master, ...@@ -883,8 +871,6 @@ static int spi_imx_dma_configure(struct spi_master *master,
return ret; return ret;
} }
spi_imx->bytes_per_word = bytes_per_word;
return 0; return 0;
} }
...@@ -892,22 +878,19 @@ static int spi_imx_setupxfer(struct spi_device *spi, ...@@ -892,22 +878,19 @@ static int spi_imx_setupxfer(struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
struct spi_imx_config config;
int ret; int ret;
config.bpw = t ? t->bits_per_word : spi->bits_per_word; if (!t)
config.speed_hz = t ? t->speed_hz : spi->max_speed_hz; return 0;
if (!config.speed_hz) spi_imx->bits_per_word = t->bits_per_word;
config.speed_hz = spi->max_speed_hz; spi_imx->speed_hz = t->speed_hz;
if (!config.bpw)
config.bpw = spi->bits_per_word;
/* Initialize the functions for transfer */ /* Initialize the functions for transfer */
if (config.bpw <= 8) { if (spi_imx->bits_per_word <= 8) {
spi_imx->rx = spi_imx_buf_rx_u8; spi_imx->rx = spi_imx_buf_rx_u8;
spi_imx->tx = spi_imx_buf_tx_u8; spi_imx->tx = spi_imx_buf_tx_u8;
} else if (config.bpw <= 16) { } else if (spi_imx->bits_per_word <= 16) {
spi_imx->rx = spi_imx_buf_rx_u16; spi_imx->rx = spi_imx_buf_rx_u16;
spi_imx->tx = spi_imx_buf_tx_u16; spi_imx->tx = spi_imx_buf_tx_u16;
} else { } else {
...@@ -921,13 +904,12 @@ static int spi_imx_setupxfer(struct spi_device *spi, ...@@ -921,13 +904,12 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->usedma = 0; spi_imx->usedma = 0;
if (spi_imx->usedma) { if (spi_imx->usedma) {
ret = spi_imx_dma_configure(spi->master, ret = spi_imx_dma_configure(spi->master);
spi_imx_bytes_per_word(config.bpw));
if (ret) if (ret)
return ret; return ret;
} }
spi_imx->devtype_data->config(spi, &config); spi_imx->devtype_data->config(spi);
return 0; return 0;
} }
...@@ -976,8 +958,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, ...@@ -976,8 +958,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
goto err; goto err;
} }
spi_imx_dma_configure(master, 1);
init_completion(&spi_imx->dma_rx_completion); init_completion(&spi_imx->dma_rx_completion);
init_completion(&spi_imx->dma_tx_completion); init_completion(&spi_imx->dma_tx_completion);
master->can_dma = spi_imx_can_dma; master->can_dma = spi_imx_can_dma;
...@@ -1189,15 +1169,15 @@ static int spi_imx_probe(struct platform_device *pdev) ...@@ -1189,15 +1169,15 @@ static int spi_imx_probe(struct platform_device *pdev)
} }
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data)); master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
if (!master)
return -ENOMEM;
ret = of_property_read_u32(np, "fsl,spi-rdy-drctl", &spi_drctl); ret = of_property_read_u32(np, "fsl,spi-rdy-drctl", &spi_drctl);
if ((ret < 0) || (spi_drctl >= 0x3)) { if ((ret < 0) || (spi_drctl >= 0x3)) {
/* '11' is reserved */ /* '11' is reserved */
spi_drctl = 0; spi_drctl = 0;
} }
if (!master)
return -ENOMEM;
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
......
...@@ -894,7 +894,7 @@ int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test, ...@@ -894,7 +894,7 @@ int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test,
test->elapsed_time = ktime_to_ns(ktime_sub(ktime_get(), start)); test->elapsed_time = ktime_to_ns(ktime_sub(ktime_get(), start));
if (ret == -ETIMEDOUT) { if (ret == -ETIMEDOUT) {
dev_info(&spi->dev, dev_info(&spi->dev,
"spi-message timed out - reruning...\n"); "spi-message timed out - rerunning...\n");
/* rerun after a few explicit schedules */ /* rerun after a few explicit schedules */
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
schedule(); schedule();
...@@ -1021,10 +1021,9 @@ int spi_test_run_tests(struct spi_device *spi, ...@@ -1021,10 +1021,9 @@ int spi_test_run_tests(struct spi_device *spi,
rx = vmalloc(SPI_TEST_MAX_SIZE_PLUS); rx = vmalloc(SPI_TEST_MAX_SIZE_PLUS);
else else
rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL); rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
if (!rx) { if (!rx)
ret = -ENOMEM; return -ENOMEM;
goto out;
}
if (use_vmalloc) if (use_vmalloc)
tx = vmalloc(SPI_TEST_MAX_SIZE_PLUS); tx = vmalloc(SPI_TEST_MAX_SIZE_PLUS);
...@@ -1032,7 +1031,7 @@ int spi_test_run_tests(struct spi_device *spi, ...@@ -1032,7 +1031,7 @@ int spi_test_run_tests(struct spi_device *spi,
tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL); tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
if (!tx) { if (!tx) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto err_tx;
} }
/* now run the individual tests in the table */ /* now run the individual tests in the table */
...@@ -1057,8 +1056,9 @@ int spi_test_run_tests(struct spi_device *spi, ...@@ -1057,8 +1056,9 @@ int spi_test_run_tests(struct spi_device *spi,
} }
out: out:
kvfree(rx);
kvfree(tx); kvfree(tx);
err_tx:
kvfree(rx);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(spi_test_run_tests); EXPORT_SYMBOL_GPL(spi_test_run_tests);
This diff is collapsed.
...@@ -35,11 +35,15 @@ ...@@ -35,11 +35,15 @@
#define SPI_CMD_REG 0x0018 #define SPI_CMD_REG 0x0018
#define SPI_STATUS0_REG 0x001c #define SPI_STATUS0_REG 0x001c
#define SPI_PAD_SEL_REG 0x0024 #define SPI_PAD_SEL_REG 0x0024
#define SPI_CFG2_REG 0x0028
#define SPI_CFG0_SCK_HIGH_OFFSET 0 #define SPI_CFG0_SCK_HIGH_OFFSET 0
#define SPI_CFG0_SCK_LOW_OFFSET 8 #define SPI_CFG0_SCK_LOW_OFFSET 8
#define SPI_CFG0_CS_HOLD_OFFSET 16 #define SPI_CFG0_CS_HOLD_OFFSET 16
#define SPI_CFG0_CS_SETUP_OFFSET 24 #define SPI_CFG0_CS_SETUP_OFFSET 24
#define SPI_ADJUST_CFG0_SCK_LOW_OFFSET 16
#define SPI_ADJUST_CFG0_CS_HOLD_OFFSET 0
#define SPI_ADJUST_CFG0_CS_SETUP_OFFSET 16
#define SPI_CFG1_CS_IDLE_OFFSET 0 #define SPI_CFG1_CS_IDLE_OFFSET 0
#define SPI_CFG1_PACKET_LOOP_OFFSET 8 #define SPI_CFG1_PACKET_LOOP_OFFSET 8
...@@ -55,6 +59,8 @@ ...@@ -55,6 +59,8 @@
#define SPI_CMD_RST BIT(2) #define SPI_CMD_RST BIT(2)
#define SPI_CMD_PAUSE_EN BIT(4) #define SPI_CMD_PAUSE_EN BIT(4)
#define SPI_CMD_DEASSERT BIT(5) #define SPI_CMD_DEASSERT BIT(5)
#define SPI_CMD_SAMPLE_SEL BIT(6)
#define SPI_CMD_CS_POL BIT(7)
#define SPI_CMD_CPHA BIT(8) #define SPI_CMD_CPHA BIT(8)
#define SPI_CMD_CPOL BIT(9) #define SPI_CMD_CPOL BIT(9)
#define SPI_CMD_RX_DMA BIT(10) #define SPI_CMD_RX_DMA BIT(10)
...@@ -80,6 +86,8 @@ struct mtk_spi_compatible { ...@@ -80,6 +86,8 @@ struct mtk_spi_compatible {
bool need_pad_sel; bool need_pad_sel;
/* Must explicitly send dummy Tx bytes to do Rx only transfer */ /* Must explicitly send dummy Tx bytes to do Rx only transfer */
bool must_tx; bool must_tx;
/* some IC design adjust cfg register to enhance time accuracy */
bool enhance_timing;
}; };
struct mtk_spi { struct mtk_spi {
...@@ -96,6 +104,16 @@ struct mtk_spi { ...@@ -96,6 +104,16 @@ struct mtk_spi {
}; };
static const struct mtk_spi_compatible mtk_common_compat; static const struct mtk_spi_compatible mtk_common_compat;
static const struct mtk_spi_compatible mt2712_compat = {
.must_tx = true,
};
static const struct mtk_spi_compatible mt7622_compat = {
.must_tx = true,
.enhance_timing = true,
};
static const struct mtk_spi_compatible mt8173_compat = { static const struct mtk_spi_compatible mt8173_compat = {
.need_pad_sel = true, .need_pad_sel = true,
.must_tx = true, .must_tx = true,
...@@ -108,15 +126,23 @@ static const struct mtk_spi_compatible mt8173_compat = { ...@@ -108,15 +126,23 @@ static const struct mtk_spi_compatible mt8173_compat = {
static const struct mtk_chip_config mtk_default_chip_info = { static const struct mtk_chip_config mtk_default_chip_info = {
.rx_mlsb = 1, .rx_mlsb = 1,
.tx_mlsb = 1, .tx_mlsb = 1,
.cs_pol = 0,
.sample_sel = 0,
}; };
static const struct of_device_id mtk_spi_of_match[] = { static const struct of_device_id mtk_spi_of_match[] = {
{ .compatible = "mediatek,mt2701-spi", { .compatible = "mediatek,mt2701-spi",
.data = (void *)&mtk_common_compat, .data = (void *)&mtk_common_compat,
}, },
{ .compatible = "mediatek,mt2712-spi",
.data = (void *)&mt2712_compat,
},
{ .compatible = "mediatek,mt6589-spi", { .compatible = "mediatek,mt6589-spi",
.data = (void *)&mtk_common_compat, .data = (void *)&mtk_common_compat,
}, },
{ .compatible = "mediatek,mt7622-spi",
.data = (void *)&mt7622_compat,
},
{ .compatible = "mediatek,mt8135-spi", { .compatible = "mediatek,mt8135-spi",
.data = (void *)&mtk_common_compat, .data = (void *)&mtk_common_compat,
}, },
...@@ -182,6 +208,17 @@ static int mtk_spi_prepare_message(struct spi_master *master, ...@@ -182,6 +208,17 @@ static int mtk_spi_prepare_message(struct spi_master *master,
reg_val |= SPI_CMD_RX_ENDIAN; reg_val |= SPI_CMD_RX_ENDIAN;
#endif #endif
if (mdata->dev_comp->enhance_timing) {
if (chip_config->cs_pol)
reg_val |= SPI_CMD_CS_POL;
else
reg_val &= ~SPI_CMD_CS_POL;
if (chip_config->sample_sel)
reg_val |= SPI_CMD_SAMPLE_SEL;
else
reg_val &= ~SPI_CMD_SAMPLE_SEL;
}
/* set finish and pause interrupt always enable */ /* set finish and pause interrupt always enable */
reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_IE; reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_IE;
...@@ -233,11 +270,25 @@ static void mtk_spi_prepare_transfer(struct spi_master *master, ...@@ -233,11 +270,25 @@ static void mtk_spi_prepare_transfer(struct spi_master *master,
sck_time = (div + 1) / 2; sck_time = (div + 1) / 2;
cs_time = sck_time * 2; cs_time = sck_time * 2;
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_HIGH_OFFSET); if (mdata->dev_comp->enhance_timing) {
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET); reg_val |= (((sck_time - 1) & 0xffff)
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET); << SPI_CFG0_SCK_HIGH_OFFSET);
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET); reg_val |= (((sck_time - 1) & 0xffff)
writel(reg_val, mdata->base + SPI_CFG0_REG); << SPI_ADJUST_CFG0_SCK_LOW_OFFSET);
writel(reg_val, mdata->base + SPI_CFG2_REG);
reg_val |= (((cs_time - 1) & 0xffff)
<< SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
reg_val |= (((cs_time - 1) & 0xffff)
<< SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
writel(reg_val, mdata->base + SPI_CFG0_REG);
} else {
reg_val |= (((sck_time - 1) & 0xff)
<< SPI_CFG0_SCK_HIGH_OFFSET);
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET);
writel(reg_val, mdata->base + SPI_CFG0_REG);
}
reg_val = readl(mdata->base + SPI_CFG1_REG); reg_val = readl(mdata->base + SPI_CFG1_REG);
reg_val &= ~SPI_CFG1_CS_IDLE_MASK; reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
......
...@@ -1412,9 +1412,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev) ...@@ -1412,9 +1412,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i); sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
} }
if (status < 0)
goto free_master;
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);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#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>
#include <linux/gpio.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define DRIVER_NAME "orion_spi" #define DRIVER_NAME "orion_spi"
...@@ -320,12 +321,18 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -320,12 +321,18 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static void orion_spi_set_cs(struct spi_device *spi, bool enable) static void orion_spi_set_cs(struct spi_device *spi, bool enable)
{ {
struct orion_spi *orion_spi; struct orion_spi *orion_spi;
int cs;
if (gpio_is_valid(spi->cs_gpio))
cs = 0;
else
cs = spi->chip_select;
orion_spi = spi_master_get_devdata(spi->master); orion_spi = spi_master_get_devdata(spi->master);
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK); orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK);
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG,
ORION_SPI_CS(spi->chip_select)); ORION_SPI_CS(cs));
/* Chip select logic is inverted from spi_set_cs */ /* Chip select logic is inverted from spi_set_cs */
if (!enable) if (!enable)
...@@ -606,6 +613,7 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -606,6 +613,7 @@ static int orion_spi_probe(struct platform_device *pdev)
master->setup = orion_spi_setup; master->setup = orion_spi_setup;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->flags = SPI_MASTER_GPIO_SS;
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
......
...@@ -151,6 +151,18 @@ static const struct lpss_config lpss_platforms[] = { ...@@ -151,6 +151,18 @@ static const struct lpss_config lpss_platforms[] = {
.cs_sel_shift = 8, .cs_sel_shift = 8,
.cs_sel_mask = 3 << 8, .cs_sel_mask = 3 << 8,
}, },
{ /* LPSS_CNL_SSP */
.offset = 0x200,
.reg_general = -1,
.reg_ssp = 0x20,
.reg_cs_ctrl = 0x24,
.reg_capabilities = 0xfc,
.rx_threshold = 1,
.tx_threshold_lo = 32,
.tx_threshold_hi = 56,
.cs_sel_shift = 8,
.cs_sel_mask = 3 << 8,
},
}; };
static inline const struct lpss_config static inline const struct lpss_config
...@@ -167,6 +179,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data) ...@@ -167,6 +179,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data)
case LPSS_BSW_SSP: case LPSS_BSW_SSP:
case LPSS_SPT_SSP: case LPSS_SPT_SSP:
case LPSS_BXT_SSP: case LPSS_BXT_SSP:
case LPSS_CNL_SSP:
return true; return true;
default: default:
return false; return false;
...@@ -1275,6 +1288,7 @@ static int setup(struct spi_device *spi) ...@@ -1275,6 +1288,7 @@ static int setup(struct spi_device *spi)
case LPSS_BSW_SSP: case LPSS_BSW_SSP:
case LPSS_SPT_SSP: case LPSS_SPT_SSP:
case LPSS_BXT_SSP: case LPSS_BXT_SSP:
case LPSS_CNL_SSP:
config = lpss_get_config(drv_data); config = lpss_get_config(drv_data);
tx_thres = config->tx_threshold_lo; tx_thres = config->tx_threshold_lo;
tx_hi_thres = config->tx_threshold_hi; tx_hi_thres = config->tx_threshold_hi;
...@@ -1470,6 +1484,14 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { ...@@ -1470,6 +1484,14 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
{ PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x5ac6), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac6), LPSS_BXT_SSP },
/* CNL-LP */
{ PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x9dfb), LPSS_CNL_SSP },
/* CNL-H */
{ PCI_VDEVICE(INTEL, 0xa32a), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0xa32b), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0xa37b), LPSS_CNL_SSP },
{ }, { },
}; };
......
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
#define DRIVER_NAME "rockchip-spi" #define DRIVER_NAME "rockchip-spi"
#define ROCKCHIP_SPI_CLR_BITS(reg, bits) \
writel_relaxed(readl_relaxed(reg) & ~(bits), reg)
#define ROCKCHIP_SPI_SET_BITS(reg, bits) \
writel_relaxed(readl_relaxed(reg) | (bits), reg)
/* SPI register offsets */ /* SPI register offsets */
#define ROCKCHIP_SPI_CTRLR0 0x0000 #define ROCKCHIP_SPI_CTRLR0 0x0000
#define ROCKCHIP_SPI_CTRLR1 0x0004 #define ROCKCHIP_SPI_CTRLR1 0x0004
...@@ -149,6 +154,8 @@ ...@@ -149,6 +154,8 @@
*/ */
#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff #define ROCKCHIP_SPI_MAX_TRANLEN 0xffff
#define ROCKCHIP_SPI_MAX_CS_NUM 2
enum rockchip_ssi_type { enum rockchip_ssi_type {
SSI_MOTO_SPI = 0, SSI_MOTO_SPI = 0,
SSI_TI_SSP, SSI_TI_SSP,
...@@ -193,6 +200,8 @@ struct rockchip_spi { ...@@ -193,6 +200,8 @@ struct rockchip_spi {
/* protect state */ /* protect state */
spinlock_t lock; spinlock_t lock;
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
u32 use_dma; u32 use_dma;
struct sg_table tx_sg; struct sg_table tx_sg;
struct sg_table rx_sg; struct sg_table rx_sg;
...@@ -264,37 +273,29 @@ static inline u32 rx_max(struct rockchip_spi *rs) ...@@ -264,37 +273,29 @@ static inline u32 rx_max(struct rockchip_spi *rs)
static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
{ {
u32 ser;
struct spi_master *master = spi->master; struct spi_master *master = spi->master;
struct rockchip_spi *rs = spi_master_get_devdata(master); struct rockchip_spi *rs = spi_master_get_devdata(master);
bool cs_asserted = !enable;
pm_runtime_get_sync(rs->dev); /* Return immediately for no-op */
if (cs_asserted == rs->cs_asserted[spi->chip_select])
return;
ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK; if (cs_asserted) {
/* Keep things powered as long as CS is asserted */
pm_runtime_get_sync(rs->dev);
/* ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER,
* drivers/spi/spi.c: BIT(spi->chip_select));
* static void spi_set_cs(struct spi_device *spi, bool enable) } else {
* { ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER,
* if (spi->mode & SPI_CS_HIGH) BIT(spi->chip_select));
* enable = !enable;
*
* if (spi->cs_gpio >= 0)
* gpio_set_value(spi->cs_gpio, !enable);
* else if (spi->master->set_cs)
* spi->master->set_cs(spi, !enable);
* }
*
* Note: enable(rockchip_spi_set_cs) = !enable(spi_set_cs)
*/
if (!enable)
ser |= 1 << spi->chip_select;
else
ser &= ~(1 << spi->chip_select);
writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER); /* Drop reference from when we first asserted CS */
pm_runtime_put(rs->dev);
}
pm_runtime_put_sync(rs->dev); rs->cs_asserted[spi->chip_select] = cs_asserted;
} }
static int rockchip_spi_prepare_message(struct spi_master *master, static int rockchip_spi_prepare_message(struct spi_master *master,
...@@ -684,33 +685,33 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -684,33 +685,33 @@ static int rockchip_spi_probe(struct platform_device *pdev)
rs->regs = devm_ioremap_resource(&pdev->dev, mem); rs->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(rs->regs)) { if (IS_ERR(rs->regs)) {
ret = PTR_ERR(rs->regs); ret = PTR_ERR(rs->regs);
goto err_ioremap_resource; goto err_put_master;
} }
rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk"); rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk");
if (IS_ERR(rs->apb_pclk)) { if (IS_ERR(rs->apb_pclk)) {
dev_err(&pdev->dev, "Failed to get apb_pclk\n"); dev_err(&pdev->dev, "Failed to get apb_pclk\n");
ret = PTR_ERR(rs->apb_pclk); ret = PTR_ERR(rs->apb_pclk);
goto err_ioremap_resource; goto err_put_master;
} }
rs->spiclk = devm_clk_get(&pdev->dev, "spiclk"); rs->spiclk = devm_clk_get(&pdev->dev, "spiclk");
if (IS_ERR(rs->spiclk)) { if (IS_ERR(rs->spiclk)) {
dev_err(&pdev->dev, "Failed to get spi_pclk\n"); dev_err(&pdev->dev, "Failed to get spi_pclk\n");
ret = PTR_ERR(rs->spiclk); ret = PTR_ERR(rs->spiclk);
goto err_ioremap_resource; goto err_put_master;
} }
ret = clk_prepare_enable(rs->apb_pclk); ret = clk_prepare_enable(rs->apb_pclk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to enable apb_pclk\n"); dev_err(&pdev->dev, "Failed to enable apb_pclk\n");
goto err_ioremap_resource; goto err_put_master;
} }
ret = clk_prepare_enable(rs->spiclk); ret = clk_prepare_enable(rs->spiclk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to enable spi_clk\n"); dev_err(&pdev->dev, "Failed to enable spi_clk\n");
goto err_spiclk_enable; goto err_disable_apbclk;
} }
spi_enable_chip(rs, 0); spi_enable_chip(rs, 0);
...@@ -728,7 +729,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -728,7 +729,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
if (!rs->fifo_len) { if (!rs->fifo_len) {
dev_err(&pdev->dev, "Failed to get fifo length\n"); dev_err(&pdev->dev, "Failed to get fifo length\n");
ret = -EINVAL; ret = -EINVAL;
goto err_get_fifo_len; goto err_disable_spiclk;
} }
spin_lock_init(&rs->lock); spin_lock_init(&rs->lock);
...@@ -739,7 +740,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -739,7 +740,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
master->num_chipselect = 2; master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8); master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
...@@ -749,13 +750,14 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -749,13 +750,14 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->transfer_one = rockchip_spi_transfer_one; master->transfer_one = rockchip_spi_transfer_one;
master->max_transfer_size = rockchip_spi_max_transfer_size; master->max_transfer_size = rockchip_spi_max_transfer_size;
master->handle_err = rockchip_spi_handle_err; master->handle_err = rockchip_spi_handle_err;
master->flags = SPI_MASTER_GPIO_SS;
rs->dma_tx.ch = dma_request_chan(rs->dev, "tx"); rs->dma_tx.ch = dma_request_chan(rs->dev, "tx");
if (IS_ERR(rs->dma_tx.ch)) { if (IS_ERR(rs->dma_tx.ch)) {
/* Check tx to see if we need defer probing driver */ /* Check tx to see if we need defer probing driver */
if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) { if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
goto err_get_fifo_len; goto err_disable_pm_runtime;
} }
dev_warn(rs->dev, "Failed to request TX DMA channel\n"); dev_warn(rs->dev, "Failed to request TX DMA channel\n");
rs->dma_tx.ch = NULL; rs->dma_tx.ch = NULL;
...@@ -786,23 +788,24 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -786,23 +788,24 @@ static int rockchip_spi_probe(struct platform_device *pdev)
ret = devm_spi_register_master(&pdev->dev, master); ret = devm_spi_register_master(&pdev->dev, master);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to register master\n"); dev_err(&pdev->dev, "Failed to register master\n");
goto err_register_master; goto err_free_dma_rx;
} }
return 0; return 0;
err_register_master: err_free_dma_rx:
pm_runtime_disable(&pdev->dev);
if (rs->dma_rx.ch) if (rs->dma_rx.ch)
dma_release_channel(rs->dma_rx.ch); dma_release_channel(rs->dma_rx.ch);
err_free_dma_tx: err_free_dma_tx:
if (rs->dma_tx.ch) if (rs->dma_tx.ch)
dma_release_channel(rs->dma_tx.ch); dma_release_channel(rs->dma_tx.ch);
err_get_fifo_len: err_disable_pm_runtime:
pm_runtime_disable(&pdev->dev);
err_disable_spiclk:
clk_disable_unprepare(rs->spiclk); clk_disable_unprepare(rs->spiclk);
err_spiclk_enable: err_disable_apbclk:
clk_disable_unprepare(rs->apb_pclk); clk_disable_unprepare(rs->apb_pclk);
err_ioremap_resource: err_put_master:
spi_master_put(master); spi_master_put(master);
return ret; return ret;
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
* SuperH MSIOF SPI Master Interface * SuperH MSIOF SPI Master Interface
* *
* Copyright (c) 2009 Magnus Damm * Copyright (c) 2009 Magnus Damm
* Copyright (C) 2014 Glider bvba * Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2014-2017 Glider bvba
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -33,7 +34,6 @@ ...@@ -33,7 +34,6 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
struct sh_msiof_chipdata { struct sh_msiof_chipdata {
u16 tx_fifo_size; u16 tx_fifo_size;
u16 rx_fifo_size; u16 rx_fifo_size;
...@@ -53,6 +53,7 @@ struct sh_msiof_spi_priv { ...@@ -53,6 +53,7 @@ struct sh_msiof_spi_priv {
void *rx_dma_page; void *rx_dma_page;
dma_addr_t tx_dma_addr; dma_addr_t tx_dma_addr;
dma_addr_t rx_dma_addr; dma_addr_t rx_dma_addr;
bool slave_aborted;
}; };
#define TMDR1 0x00 /* Transmit Mode Register 1 */ #define TMDR1 0x00 /* Transmit Mode Register 1 */
...@@ -337,7 +338,10 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, ...@@ -337,7 +338,10 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
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); if (spi_controller_is_slave(p->master))
sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON);
else
sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
if (p->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;
...@@ -564,17 +568,19 @@ static int sh_msiof_prepare_message(struct spi_master *master, ...@@ -564,17 +568,19 @@ static int sh_msiof_prepare_message(struct spi_master *master,
static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
{ {
int ret; bool slave = spi_controller_is_slave(p->master);
int ret = 0;
/* setup clock and rx/tx signals */ /* setup clock and rx/tx signals */
ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); if (!slave)
ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE);
if (rx_buf && !ret) if (rx_buf && !ret)
ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE);
if (!ret) if (!ret)
ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE);
/* start by setting frame bit */ /* start by setting frame bit */
if (!ret) if (!ret && !slave)
ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE);
return ret; return ret;
...@@ -582,20 +588,49 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) ...@@ -582,20 +588,49 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf) static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf)
{ {
int ret; bool slave = spi_controller_is_slave(p->master);
int ret = 0;
/* shut down frame, rx/tx and clock signals */ /* shut down frame, rx/tx and clock signals */
ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); if (!slave)
ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
if (!ret) if (!ret)
ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
if (rx_buf && !ret) if (rx_buf && !ret)
ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0);
if (!ret) if (!ret && !slave)
ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0);
return ret; return ret;
} }
static int sh_msiof_slave_abort(struct spi_master *master)
{
struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
p->slave_aborted = true;
complete(&p->done);
return 0;
}
static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p)
{
if (spi_controller_is_slave(p->master)) {
if (wait_for_completion_interruptible(&p->done) ||
p->slave_aborted) {
dev_dbg(&p->pdev->dev, "interrupted\n");
return -EINTR;
}
} else {
if (!wait_for_completion_timeout(&p->done, HZ)) {
dev_err(&p->pdev->dev, "timeout\n");
return -ETIMEDOUT;
}
}
return 0;
}
static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
void (*tx_fifo)(struct sh_msiof_spi_priv *, void (*tx_fifo)(struct sh_msiof_spi_priv *,
const void *, int, int), const void *, int, int),
...@@ -628,6 +663,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, ...@@ -628,6 +663,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
tx_fifo(p, tx_buf, words, fifo_shift); tx_fifo(p, tx_buf, words, fifo_shift);
reinit_completion(&p->done); reinit_completion(&p->done);
p->slave_aborted = false;
ret = sh_msiof_spi_start(p, rx_buf); ret = sh_msiof_spi_start(p, rx_buf);
if (ret) { if (ret) {
...@@ -636,11 +672,9 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, ...@@ -636,11 +672,9 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
} }
/* wait for tx fifo to be emptied / rx fifo to be filled */ /* wait for tx fifo to be emptied / rx fifo to be filled */
if (!wait_for_completion_timeout(&p->done, HZ)) { ret = sh_msiof_wait_for_completion(p);
dev_err(&p->pdev->dev, "PIO timeout\n"); if (ret)
ret = -ETIMEDOUT;
goto stop_reset; goto stop_reset;
}
/* read rx fifo */ /* read rx fifo */
if (rx_buf) if (rx_buf)
...@@ -732,6 +766,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, ...@@ -732,6 +766,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
sh_msiof_write(p, IER, ier_bits); sh_msiof_write(p, IER, ier_bits);
reinit_completion(&p->done); reinit_completion(&p->done);
p->slave_aborted = false;
/* Now start DMA */ /* Now start DMA */
if (rx) if (rx)
...@@ -746,11 +781,9 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, ...@@ -746,11 +781,9 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
} }
/* wait for tx fifo to be emptied / rx fifo to be filled */ /* wait for tx fifo to be emptied / rx fifo to be filled */
if (!wait_for_completion_timeout(&p->done, HZ)) { ret = sh_msiof_wait_for_completion(p);
dev_err(&p->pdev->dev, "DMA timeout\n"); if (ret)
ret = -ETIMEDOUT;
goto stop_reset; goto stop_reset;
}
/* clear status bits */ /* clear status bits */
sh_msiof_reset_str(p); sh_msiof_reset_str(p);
...@@ -843,7 +876,8 @@ static int sh_msiof_transfer_one(struct spi_master *master, ...@@ -843,7 +876,8 @@ static int sh_msiof_transfer_one(struct spi_master *master,
int ret; int ret;
/* setup clocks (clock already enabled in chipselect()) */ /* setup clocks (clock already enabled in chipselect()) */
sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); if (!spi_controller_is_slave(p->master))
sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
while (master->dma_tx && len > 15) { while (master->dma_tx && len > 15) {
/* /*
...@@ -998,8 +1032,12 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) ...@@ -998,8 +1032,12 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
if (!info) if (!info)
return NULL; return NULL;
info->mode = of_property_read_bool(np, "spi-slave") ? MSIOF_SPI_SLAVE
: MSIOF_SPI_MASTER;
/* Parse the MSIOF properties */ /* Parse the MSIOF properties */
of_property_read_u32(np, "num-cs", &num_cs); if (info->mode == MSIOF_SPI_MASTER)
of_property_read_u32(np, "num-cs", &num_cs);
of_property_read_u32(np, "renesas,tx-fifo-size", of_property_read_u32(np, "renesas,tx-fifo-size",
&info->tx_fifo_override); &info->tx_fifo_override);
of_property_read_u32(np, "renesas,rx-fifo-size", of_property_read_u32(np, "renesas,rx-fifo-size",
...@@ -1159,34 +1197,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ...@@ -1159,34 +1197,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
struct spi_master *master; struct spi_master *master;
const struct sh_msiof_chipdata *chipdata; const struct sh_msiof_chipdata *chipdata;
const struct of_device_id *of_id; const struct of_device_id *of_id;
struct sh_msiof_spi_info *info;
struct sh_msiof_spi_priv *p; struct sh_msiof_spi_priv *p;
int i; int i;
int ret; int ret;
master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv));
if (master == NULL)
return -ENOMEM;
p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, p);
p->master = master;
of_id = of_match_device(sh_msiof_match, &pdev->dev); of_id = of_match_device(sh_msiof_match, &pdev->dev);
if (of_id) { if (of_id) {
chipdata = of_id->data; chipdata = of_id->data;
p->info = sh_msiof_spi_parse_dt(&pdev->dev); info = sh_msiof_spi_parse_dt(&pdev->dev);
} else { } else {
chipdata = (const void *)pdev->id_entry->driver_data; chipdata = (const void *)pdev->id_entry->driver_data;
p->info = dev_get_platdata(&pdev->dev); info = dev_get_platdata(&pdev->dev);
} }
if (!p->info) { if (!info) {
dev_err(&pdev->dev, "failed to obtain device info\n"); dev_err(&pdev->dev, "failed to obtain device info\n");
ret = -ENXIO; return -ENXIO;
goto err1;
} }
if (info->mode == MSIOF_SPI_SLAVE)
master = spi_alloc_slave(&pdev->dev,
sizeof(struct sh_msiof_spi_priv));
else
master = spi_alloc_master(&pdev->dev,
sizeof(struct sh_msiof_spi_priv));
if (master == NULL)
return -ENOMEM;
p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, p);
p->master = master;
p->info = info;
init_completion(&p->done); init_completion(&p->done);
p->clk = devm_clk_get(&pdev->dev, NULL); p->clk = devm_clk_get(&pdev->dev, NULL);
...@@ -1237,6 +1281,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ...@@ -1237,6 +1281,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
master->num_chipselect = p->info->num_chipselect; master->num_chipselect = p->info->num_chipselect;
master->setup = sh_msiof_spi_setup; master->setup = sh_msiof_spi_setup;
master->prepare_message = sh_msiof_prepare_message; master->prepare_message = sh_msiof_prepare_message;
master->slave_abort = sh_msiof_slave_abort;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->transfer_one = sh_msiof_transfer_one; master->transfer_one = sh_msiof_transfer_one;
......
...@@ -1158,7 +1158,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ...@@ -1158,7 +1158,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
ret = spi_bitbang_start(&sspi->bitbang); ret = spi_bitbang_start(&sspi->bitbang);
if (ret) if (ret)
goto free_clk; goto free_clk;
dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num); dev_info(&pdev->dev, "registered, bus number = %d\n", master->bus_num);
return 0; return 0;
free_clk: free_clk:
......
/*
* SPI slave handler controlling system state
*
* This SPI slave handler allows remote control of system reboot, power off,
* halt, and suspend.
*
* Copyright (C) 2016-2017 Glider bvba
*
* 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.
*
* Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote
* system):
*
* # reboot='\x7c\x50'
* # poweroff='\x71\x3f'
* # halt='\x38\x76'
* # suspend='\x1b\x1b'
* # spidev_test -D /dev/spidev2.0 -p $suspend # or $reboot, $poweroff, $halt
*/
#include <linux/completion.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/suspend.h>
#include <linux/spi/spi.h>
/*
* The numbers are chosen to display something human-readable on two 7-segment
* displays connected to two 74HC595 shift registers
*/
#define CMD_REBOOT 0x7c50 /* rb */
#define CMD_POWEROFF 0x713f /* OF */
#define CMD_HALT 0x3876 /* HL */
#define CMD_SUSPEND 0x1b1b /* ZZ */
struct spi_slave_system_control_priv {
struct spi_device *spi;
struct completion finished;
struct spi_transfer xfer;
struct spi_message msg;
__be16 cmd;
};
static
int spi_slave_system_control_submit(struct spi_slave_system_control_priv *priv);
static void spi_slave_system_control_complete(void *arg)
{
struct spi_slave_system_control_priv *priv = arg;
u16 cmd;
int ret;
if (priv->msg.status)
goto terminate;
cmd = be16_to_cpu(priv->cmd);
switch (cmd) {
case CMD_REBOOT:
dev_info(&priv->spi->dev, "Rebooting system...\n");
kernel_restart(NULL);
case CMD_POWEROFF:
dev_info(&priv->spi->dev, "Powering off system...\n");
kernel_power_off();
break;
case CMD_HALT:
dev_info(&priv->spi->dev, "Halting system...\n");
kernel_halt();
break;
case CMD_SUSPEND:
dev_info(&priv->spi->dev, "Suspending system...\n");
pm_suspend(PM_SUSPEND_MEM);
break;
default:
dev_warn(&priv->spi->dev, "Unknown command 0x%x\n", cmd);
break;
}
ret = spi_slave_system_control_submit(priv);
if (ret)
goto terminate;
return;
terminate:
dev_info(&priv->spi->dev, "Terminating\n");
complete(&priv->finished);
}
static
int spi_slave_system_control_submit(struct spi_slave_system_control_priv *priv)
{
int ret;
spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
priv->msg.complete = spi_slave_system_control_complete;
priv->msg.context = priv;
ret = spi_async(priv->spi, &priv->msg);
if (ret)
dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret);
return ret;
}
static int spi_slave_system_control_probe(struct spi_device *spi)
{
struct spi_slave_system_control_priv *priv;
int ret;
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->spi = spi;
init_completion(&priv->finished);
priv->xfer.rx_buf = &priv->cmd;
priv->xfer.len = sizeof(priv->cmd);
ret = spi_slave_system_control_submit(priv);
if (ret)
return ret;
spi_set_drvdata(spi, priv);
return 0;
}
static int spi_slave_system_control_remove(struct spi_device *spi)
{
struct spi_slave_system_control_priv *priv = spi_get_drvdata(spi);
spi_slave_abort(spi);
wait_for_completion(&priv->finished);
return 0;
}
static struct spi_driver spi_slave_system_control_driver = {
.driver = {
.name = "spi-slave-system-control",
},
.probe = spi_slave_system_control_probe,
.remove = spi_slave_system_control_remove,
};
module_spi_driver(spi_slave_system_control_driver);
MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
MODULE_DESCRIPTION("SPI slave handler controlling system state");
MODULE_LICENSE("GPL v2");
/*
* SPI slave handler reporting uptime at reception of previous SPI message
*
* This SPI slave handler sends the time of reception of the last SPI message
* as two 32-bit unsigned integers in binary format and in network byte order,
* representing the number of seconds and fractional seconds (in microseconds)
* since boot up.
*
* Copyright (C) 2016-2017 Glider bvba
*
* 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.
*
* Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote
* system):
*
* # spidev_test -D /dev/spidev2.0 -p dummy-8B
* spi mode: 0x0
* bits per word: 8
* max speed: 500000 Hz (500 KHz)
* RX | 00 00 04 6D 00 09 5B BB ...
* ^^^^^ ^^^^^^^^
* seconds microseconds
*/
#include <linux/completion.h>
#include <linux/module.h>
#include <linux/sched/clock.h>
#include <linux/spi/spi.h>
struct spi_slave_time_priv {
struct spi_device *spi;
struct completion finished;
struct spi_transfer xfer;
struct spi_message msg;
__be32 buf[2];
};
static int spi_slave_time_submit(struct spi_slave_time_priv *priv);
static void spi_slave_time_complete(void *arg)
{
struct spi_slave_time_priv *priv = arg;
int ret;
ret = priv->msg.status;
if (ret)
goto terminate;
ret = spi_slave_time_submit(priv);
if (ret)
goto terminate;
return;
terminate:
dev_info(&priv->spi->dev, "Terminating\n");
complete(&priv->finished);
}
static int spi_slave_time_submit(struct spi_slave_time_priv *priv)
{
u32 rem_us;
int ret;
u64 ts;
ts = local_clock();
rem_us = do_div(ts, 1000000000) / 1000;
priv->buf[0] = cpu_to_be32(ts);
priv->buf[1] = cpu_to_be32(rem_us);
spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
priv->msg.complete = spi_slave_time_complete;
priv->msg.context = priv;
ret = spi_async(priv->spi, &priv->msg);
if (ret)
dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret);
return ret;
}
static int spi_slave_time_probe(struct spi_device *spi)
{
struct spi_slave_time_priv *priv;
int ret;
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->spi = spi;
init_completion(&priv->finished);
priv->xfer.tx_buf = priv->buf;
priv->xfer.len = sizeof(priv->buf);
ret = spi_slave_time_submit(priv);
if (ret)
return ret;
spi_set_drvdata(spi, priv);
return 0;
}
static int spi_slave_time_remove(struct spi_device *spi)
{
struct spi_slave_time_priv *priv = spi_get_drvdata(spi);
spi_slave_abort(spi);
wait_for_completion(&priv->finished);
return 0;
}
static struct spi_driver spi_slave_time_driver = {
.driver = {
.name = "spi-slave-time",
},
.probe = spi_slave_time_probe,
.remove = spi_slave_time_remove,
};
module_spi_driver(spi_slave_time_driver);
MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
MODULE_DESCRIPTION("SPI slave reporting uptime at previous SPI message");
MODULE_LICENSE("GPL v2");
...@@ -229,42 +229,42 @@ static int spi_st_setup(struct spi_device *spi) ...@@ -229,42 +229,42 @@ static int spi_st_setup(struct spi_device *spi)
"setting baudrate:target= %u hz, actual= %u hz, sscbrg= %u\n", "setting baudrate:target= %u hz, actual= %u hz, sscbrg= %u\n",
hz, spi_st->baud, sscbrg); hz, spi_st->baud, sscbrg);
/* Set SSC_CTL and enable SSC */ /* Set SSC_CTL and enable SSC */
var = readl_relaxed(spi_st->base + SSC_CTL); var = readl_relaxed(spi_st->base + SSC_CTL);
var |= SSC_CTL_MS; var |= SSC_CTL_MS;
if (spi->mode & SPI_CPOL) if (spi->mode & SPI_CPOL)
var |= SSC_CTL_PO; var |= SSC_CTL_PO;
else else
var &= ~SSC_CTL_PO; var &= ~SSC_CTL_PO;
if (spi->mode & SPI_CPHA) if (spi->mode & SPI_CPHA)
var |= SSC_CTL_PH; var |= SSC_CTL_PH;
else else
var &= ~SSC_CTL_PH; var &= ~SSC_CTL_PH;
if ((spi->mode & SPI_LSB_FIRST) == 0) if ((spi->mode & SPI_LSB_FIRST) == 0)
var |= SSC_CTL_HB; var |= SSC_CTL_HB;
else else
var &= ~SSC_CTL_HB; var &= ~SSC_CTL_HB;
if (spi->mode & SPI_LOOP) if (spi->mode & SPI_LOOP)
var |= SSC_CTL_LPB; var |= SSC_CTL_LPB;
else else
var &= ~SSC_CTL_LPB; var &= ~SSC_CTL_LPB;
var &= ~SSC_CTL_DATA_WIDTH_MSK; var &= ~SSC_CTL_DATA_WIDTH_MSK;
var |= (spi->bits_per_word - 1); var |= (spi->bits_per_word - 1);
var |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO; var |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO;
var |= SSC_CTL_EN; var |= SSC_CTL_EN;
writel_relaxed(var, spi_st->base + SSC_CTL); writel_relaxed(var, spi_st->base + SSC_CTL);
/* Clear the status register */ /* Clear the status register */
readl_relaxed(spi_st->base + SSC_RBUF); readl_relaxed(spi_st->base + SSC_RBUF);
return 0; return 0;
out_free_gpio: out_free_gpio:
gpio_free(cs); gpio_free(cs);
......
This diff is collapsed.
This diff is collapsed.
...@@ -99,7 +99,6 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); ...@@ -99,7 +99,6 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
static ssize_t static ssize_t
spidev_sync(struct spidev_data *spidev, struct spi_message *message) spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{ {
DECLARE_COMPLETION_ONSTACK(done);
int status; int status;
struct spi_device *spi; struct spi_device *spi;
...@@ -325,7 +324,6 @@ static struct spi_ioc_transfer * ...@@ -325,7 +324,6 @@ static struct spi_ioc_transfer *
spidev_get_ioc_message(unsigned int cmd, struct spi_ioc_transfer __user *u_ioc, spidev_get_ioc_message(unsigned int cmd, struct spi_ioc_transfer __user *u_ioc,
unsigned *n_ioc) unsigned *n_ioc)
{ {
struct spi_ioc_transfer *ioc;
u32 tmp; u32 tmp;
/* Check type, command number and direction */ /* Check type, command number and direction */
...@@ -342,14 +340,7 @@ spidev_get_ioc_message(unsigned int cmd, struct spi_ioc_transfer __user *u_ioc, ...@@ -342,14 +340,7 @@ spidev_get_ioc_message(unsigned int cmd, struct spi_ioc_transfer __user *u_ioc,
return NULL; return NULL;
/* copy into scratch area */ /* copy into scratch area */
ioc = kmalloc(tmp, GFP_KERNEL); return memdup_user(u_ioc, tmp);
if (!ioc)
return ERR_PTR(-ENOMEM);
if (__copy_from_user(ioc, u_ioc, tmp)) {
kfree(ioc);
return ERR_PTR(-EFAULT);
}
return ioc;
} }
static long static long
......
...@@ -16,5 +16,7 @@ ...@@ -16,5 +16,7 @@
struct mtk_chip_config { struct mtk_chip_config {
u32 tx_mlsb; u32 tx_mlsb;
u32 rx_mlsb; u32 rx_mlsb;
u32 cs_pol;
u32 sample_sel;
}; };
#endif #endif
...@@ -196,6 +196,7 @@ enum pxa_ssp_type { ...@@ -196,6 +196,7 @@ enum pxa_ssp_type {
LPSS_BSW_SSP, LPSS_BSW_SSP,
LPSS_SPT_SSP, LPSS_SPT_SSP,
LPSS_BXT_SSP, LPSS_BXT_SSP,
LPSS_CNL_SSP,
}; };
struct ssp_device { struct ssp_device {
......
#ifndef __SPI_SH_MSIOF_H__ #ifndef __SPI_SH_MSIOF_H__
#define __SPI_SH_MSIOF_H__ #define __SPI_SH_MSIOF_H__
enum {
MSIOF_SPI_MASTER,
MSIOF_SPI_SLAVE,
};
struct sh_msiof_spi_info { struct sh_msiof_spi_info {
int tx_fifo_override; int tx_fifo_override;
int rx_fifo_override; int rx_fifo_override;
u16 num_chipselect; u16 num_chipselect;
int mode;
unsigned int dma_tx_id; unsigned int dma_tx_id;
unsigned int dma_rx_id; unsigned int dma_rx_id;
u32 dtdl; u32 dtdl;
......
This diff is collapsed.
...@@ -7,37 +7,37 @@ ...@@ -7,37 +7,37 @@
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
DECLARE_EVENT_CLASS(spi_master, DECLARE_EVENT_CLASS(spi_controller,
TP_PROTO(struct spi_master *master), TP_PROTO(struct spi_controller *controller),
TP_ARGS(master), TP_ARGS(controller),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( int, bus_num ) __field( int, bus_num )
), ),
TP_fast_assign( TP_fast_assign(
__entry->bus_num = master->bus_num; __entry->bus_num = controller->bus_num;
), ),
TP_printk("spi%d", (int)__entry->bus_num) TP_printk("spi%d", (int)__entry->bus_num)
); );
DEFINE_EVENT(spi_master, spi_master_idle, DEFINE_EVENT(spi_controller, spi_controller_idle,
TP_PROTO(struct spi_master *master), TP_PROTO(struct spi_controller *controller),
TP_ARGS(master) TP_ARGS(controller)
); );
DEFINE_EVENT(spi_master, spi_master_busy, DEFINE_EVENT(spi_controller, spi_controller_busy,
TP_PROTO(struct spi_master *master), TP_PROTO(struct spi_controller *controller),
TP_ARGS(master) TP_ARGS(controller)
); );
...@@ -54,7 +54,7 @@ DECLARE_EVENT_CLASS(spi_message, ...@@ -54,7 +54,7 @@ DECLARE_EVENT_CLASS(spi_message,
), ),
TP_fast_assign( TP_fast_assign(
__entry->bus_num = msg->spi->master->bus_num; __entry->bus_num = msg->spi->controller->bus_num;
__entry->chip_select = msg->spi->chip_select; __entry->chip_select = msg->spi->chip_select;
__entry->msg = msg; __entry->msg = msg;
), ),
...@@ -95,7 +95,7 @@ TRACE_EVENT(spi_message_done, ...@@ -95,7 +95,7 @@ TRACE_EVENT(spi_message_done,
), ),
TP_fast_assign( TP_fast_assign(
__entry->bus_num = msg->spi->master->bus_num; __entry->bus_num = msg->spi->controller->bus_num;
__entry->chip_select = msg->spi->chip_select; __entry->chip_select = msg->spi->chip_select;
__entry->msg = msg; __entry->msg = msg;
__entry->frame = msg->frame_length; __entry->frame = msg->frame_length;
...@@ -122,7 +122,7 @@ DECLARE_EVENT_CLASS(spi_transfer, ...@@ -122,7 +122,7 @@ DECLARE_EVENT_CLASS(spi_transfer,
), ),
TP_fast_assign( TP_fast_assign(
__entry->bus_num = msg->spi->master->bus_num; __entry->bus_num = msg->spi->controller->bus_num;
__entry->chip_select = msg->spi->chip_select; __entry->chip_select = msg->spi->chip_select;
__entry->xfer = xfer; __entry->xfer = xfer;
__entry->len = xfer->len; __entry->len = xfer->len;
......
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