Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
106dbe24
Commit
106dbe24
authored
Jul 04, 2019
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'spi-5.3' into spi-next
parents
2337ff45
8cc77204
Changes
33
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
2283 additions
and
540 deletions
+2283
-540
Documentation/devicetree/bindings/mfd/atmel-usart.txt
Documentation/devicetree/bindings/mfd/atmel-usart.txt
+15
-5
Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml
...tion/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml
+86
-0
Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
...tion/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
+106
-0
Documentation/devicetree/bindings/spi/spi-bus.txt
Documentation/devicetree/bindings/spi/spi-bus.txt
+1
-111
Documentation/devicetree/bindings/spi/spi-controller.yaml
Documentation/devicetree/bindings/spi/spi-controller.yaml
+161
-0
Documentation/devicetree/bindings/spi/spi-gpio.txt
Documentation/devicetree/bindings/spi/spi-gpio.txt
+0
-43
Documentation/devicetree/bindings/spi/spi-gpio.yaml
Documentation/devicetree/bindings/spi/spi-gpio.yaml
+72
-0
Documentation/devicetree/bindings/spi/spi-pl022.yaml
Documentation/devicetree/bindings/spi/spi-pl022.yaml
+165
-0
Documentation/devicetree/bindings/spi/spi-stm32-qspi.txt
Documentation/devicetree/bindings/spi/spi-stm32-qspi.txt
+4
-1
Documentation/devicetree/bindings/spi/spi-sun4i.txt
Documentation/devicetree/bindings/spi/spi-sun4i.txt
+0
-23
Documentation/devicetree/bindings/spi/spi-sun6i.txt
Documentation/devicetree/bindings/spi/spi-sun6i.txt
+0
-44
Documentation/devicetree/bindings/spi/spi-synquacer.txt
Documentation/devicetree/bindings/spi/spi-synquacer.txt
+27
-0
Documentation/devicetree/bindings/spi/spi_pl022.txt
Documentation/devicetree/bindings/spi/spi_pl022.txt
+0
-70
MAINTAINERS
MAINTAINERS
+8
-0
drivers/spi/Kconfig
drivers/spi/Kconfig
+12
-2
drivers/spi/Makefile
drivers/spi/Makefile
+1
-0
drivers/spi/atmel-quadspi.c
drivers/spi/atmel-quadspi.c
+11
-10
drivers/spi/spi-at91-usart.c
drivers/spi/spi-at91-usart.c
+219
-2
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm2835.c
+204
-124
drivers/spi/spi-bcm2835aux.c
drivers/spi/spi-bcm2835aux.c
+1
-3
drivers/spi/spi-meson-spifc.c
drivers/spi/spi-meson-spifc.c
+6
-6
drivers/spi/spi-mt65xx.c
drivers/spi/spi-mt65xx.c
+6
-9
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-pxa2xx.c
+14
-0
drivers/spi/spi-qup.c
drivers/spi/spi-qup.c
+0
-4
drivers/spi/spi-rockchip.c
drivers/spi/spi-rockchip.c
+2
-2
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sh-msiof.c
+1
-1
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-stm32-qspi.c
+3
-7
drivers/spi/spi-synquacer.c
drivers/spi/spi-synquacer.c
+828
-0
drivers/spi/spi-tegra114.c
drivers/spi/spi-tegra114.c
+154
-16
drivers/spi/spi.c
drivers/spi/spi.c
+139
-55
drivers/spi/spidev.c
drivers/spi/spidev.c
+2
-0
include/linux/platform_data/spi-mt65xx.h
include/linux/platform_data/spi-mt65xx.h
+0
-2
include/linux/spi/spi.h
include/linux/spi/spi.h
+35
-0
No files found.
Documentation/devicetree/bindings/mfd/atmel-usart.txt
View file @
106dbe24
...
...
@@ -17,17 +17,24 @@ Required properties for USART in SPI mode:
- cs-gpios: chipselects (internal cs not supported)
- atmel,usart-mode : Must be <AT91_USART_MODE_SPI> (found in dt-bindings/mfd/at91-usart.h)
Optional properties in serial and SPI mode:
- dma bindings for dma transfer:
- dmas: DMA specifier, consisting of a phandle to DMA controller node,
memory peripheral interface and USART DMA channel ID, FIFO configuration.
The order of DMA channels is fixed. The first DMA channel must be TX
associated channel and the second one must be RX associated channel.
Refer to dma.txt and atmel-dma.txt for details.
- dma-names: "tx" for TX channel.
"rx" for RX channel.
The order of dma-names is also fixed. The first name must be "tx"
and the second one must be "rx" as in the examples below.
Optional properties in serial mode:
- atmel,use-dma-rx: use of PDC or DMA for receiving data
- atmel,use-dma-tx: use of PDC or DMA for transmitting data
- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively.
It will use specified PIO instead of the peripheral function pin for the USART feature.
If unsure, don't specify this property.
- add dma bindings for dma transfer:
- dmas: DMA specifier, consisting of a phandle to DMA controller node,
memory peripheral interface and USART DMA channel ID, FIFO configuration.
Refer to dma.txt and atmel-dma.txt for details.
- dma-names: "rx" for RX channel, "tx" for TX channel.
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
capable USARTs.
- rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt
...
...
@@ -81,5 +88,8 @@ Example:
interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>;
clocks = <&usart0_clk>;
clock-names = "usart";
dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(3)>,
<&dma0 2 (AT91_DMA_CFG_PER_ID(4) | AT91_DMA_CFG_FIFOCFG_ASAP)>;
dma-names = "tx", "rx";
cs-gpios = <&pioB 3 0>;
};
Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml
0 → 100644
View file @
106dbe24
# SPDX-License-Identifier: GPL-2.0
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/allwinner,sun4i-a10-spi.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Allwinner A10 SPI Controller Device Tree Bindings
allOf
:
-
$ref
:
"
spi-controller.yaml"
maintainers
:
-
Chen-Yu Tsai <wens@csie.org>
-
Maxime Ripard <maxime.ripard@bootlin.com>
properties
:
"
#address-cells"
:
true
"
#size-cells"
:
true
compatible
:
const
:
allwinner,sun4i-a10-spi
reg
:
maxItems
:
1
interrupts
:
maxItems
:
1
clocks
:
items
:
-
description
:
Bus Clock
-
description
:
Module Clock
clock-names
:
items
:
-
const
:
ahb
-
const
:
mod
dmas
:
items
:
-
description
:
RX DMA Channel
-
description
:
TX DMA Channel
dma-names
:
items
:
-
const
:
rx
-
const
:
tx
num-cs
:
true
patternProperties
:
"
^.*@[0-9a-f]+"
:
properties
:
reg
:
items
:
minimum
:
0
maximum
:
4
spi-rx-bus-width
:
const
:
1
spi-tx-bus-width
:
const
:
1
required
:
-
compatible
-
reg
-
interrupts
-
clocks
-
clock-names
additionalProperties
:
false
examples
:
-
|
spi1: spi@1c06000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c06000 0x1000>;
interrupts = <11>;
clocks = <&ahb_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
#address-cells = <1>;
#size-cells = <0>;
};
...
Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
0 → 100644
View file @
106dbe24
# SPDX-License-Identifier: GPL-2.0
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/allwinner,sun6i-a31-spi.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Allwinner A31 SPI Controller Device Tree Bindings
allOf
:
-
$ref
:
"
spi-controller.yaml"
maintainers
:
-
Chen-Yu Tsai <wens@csie.org>
-
Maxime Ripard <maxime.ripard@bootlin.com>
properties
:
"
#address-cells"
:
true
"
#size-cells"
:
true
compatible
:
enum
:
-
allwinner,sun6i-a31-spi
-
allwinner,sun8i-h3-spi
reg
:
maxItems
:
1
interrupts
:
maxItems
:
1
clocks
:
items
:
-
description
:
Bus Clock
-
description
:
Module Clock
clock-names
:
items
:
-
const
:
ahb
-
const
:
mod
resets
:
maxItems
:
1
dmas
:
items
:
-
description
:
RX DMA Channel
-
description
:
TX DMA Channel
dma-names
:
items
:
-
const
:
rx
-
const
:
tx
num-cs
:
true
patternProperties
:
"
^.*@[0-9a-f]+"
:
properties
:
reg
:
items
:
minimum
:
0
maximum
:
4
spi-rx-bus-width
:
const
:
1
spi-tx-bus-width
:
const
:
1
required
:
-
compatible
-
reg
-
interrupts
-
clocks
-
clock-names
additionalProperties
:
false
examples
:
-
|
spi1: spi@1c69000 {
compatible = "allwinner,sun6i-a31-spi";
reg = <0x01c69000 0x1000>;
interrupts = <0 66 4>;
clocks = <&ahb1_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
resets = <&ahb1_rst 21>;
#address-cells = <1>;
#size-cells = <0>;
};
-
|
spi0: spi@1c68000 {
compatible = "allwinner,sun8i-h3-spi";
reg = <0x01c68000 0x1000>;
interrupts = <0 65 4>;
clocks = <&ccu 30>, <&ccu 82>;
clock-names = "ahb", "mod";
dmas = <&dma 23>, <&dma 23>;
dma-names = "rx", "tx";
resets = <&ccu 15>;
#address-cells = <1>;
#size-cells = <0>;
};
...
Documentation/devicetree/bindings/spi/spi-bus.txt
View file @
106dbe24
SPI (Serial Peripheral Interface) busses
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. The system's SPI
controller may be described for use in SPI master mode or in SPI slave mode,
but not for both at the same time.
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 on the SPI bus.
- #size-cells - should be zero.
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
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
assigning chip select numbers. Since SPI chip select configuration is
flexible and non-standardized, it is left out of this binding with the
assumption that board specific platform code will be used to manage
chip selects. Individual drivers can define additional properties to
support describing the chip select layout.
Optional properties (master mode only):
- cs-gpios - gpios chip select.
- num-cs - total number of chipselects.
If cs-gpios is used the number of chip selects will be increased automatically
with max(cs-gpios > hw cs).
So if for example the controller has 2 CS lines, and the cs-gpios
property looks like this:
cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>;
Then it should be configured so that num_chipselect = 4 with the
following mapping:
cs0 : &gpio1 0 0
cs1 : native
cs2 : &gpio1 1 0
cs3 : &gpio1 2 0
SPI slave nodes must be children of the SPI controller node.
In master mode, one or more slave nodes (up to the number of chip selects) can
be present. Required properties are:
- compatible - Name of SPI device following generic names recommended
practice.
- reg - Chip select address of device.
- spi-max-frequency - Maximum SPI clocking speed of device in Hz.
In slave mode, the (single) slave node is optional.
If present, it must be called "slave". Required properties are:
- compatible - Name of SPI device following generic names recommended
practice.
All slave nodes can contain the following optional properties:
- spi-cpol - Empty property indicating device requires inverse clock
polarity (CPOL) mode.
- spi-cpha - Empty property indicating device requires shifted clock
phase (CPHA) mode.
- spi-cs-high - Empty property indicating device requires chip select
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.
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
only 1 (SINGLE), 2 (DUAL) and 4 (QUAD).
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
via the SPI master node cs-gpios property.
SPI example for an MPC5200 SPI bus:
spi@f00 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
reg = <0xf00 0x20>;
interrupts = <2 13 0 2 14 0>;
interrupt-parent = <&mpc5200_pic>;
ethernet-switch@0 {
compatible = "micrel,ks8995m";
spi-max-frequency = <1000000>;
reg = <0>;
};
codec@1 {
compatible = "ti,tlv320aic26";
spi-max-frequency = <100000>;
reg = <1>;
};
};
This file has moved to spi-controller.yaml.
Documentation/devicetree/bindings/spi/spi-controller.yaml
0 → 100644
View file @
106dbe24
# SPDX-License-Identifier: GPL-2.0
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/spi-controller.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
SPI Controller Generic Binding
maintainers
:
-
Mark Brown <broonie@kernel.org>
description
:
|
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. The system SPI
controller may be described for use in SPI master mode or in SPI slave mode,
but not for both at the same time.
properties
:
$nodename
:
pattern
:
"
^spi(@.*|-[0-9a-f])*$"
"
#address-cells"
:
const
:
1
"
#size-cells"
:
const
:
0
cs-gpios
:
description
:
|
GPIOs used as chip selects.
If that property is used, the number of chip selects will be
increased automatically with max(cs-gpios, hardware chip selects).
So if, for example, the controller has 2 CS lines, and the
cs-gpios looks like this
cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>;
Then it should be configured so that num_chipselect = 4, with
the following mapping
cs0 : &gpio1 0 0
cs1 : native
cs2 : &gpio1 1 0
cs3 : &gpio1 2 0
num-cs
:
$ref
:
/schemas/types.yaml#/definitions/uint32
description
:
Total number of chip selects.
spi-slave
:
$ref
:
/schemas/types.yaml#/definitions/flag
description
:
The SPI controller acts as a slave, instead of a master.
patternProperties
:
"
^slave$"
:
type
:
object
properties
:
compatible
:
description
:
Compatible of the SPI device.
required
:
-
compatible
"
^.*@[0-9a-f]+$"
:
type
:
object
properties
:
compatible
:
description
:
Compatible of the SPI device.
reg
:
maxItems
:
1
minimum
:
0
maximum
:
256
description
:
Chip select used by the device.
spi-3wire
:
$ref
:
/schemas/types.yaml#/definitions/flag
description
:
The device requires 3-wire mode.
spi-cpha
:
$ref
:
/schemas/types.yaml#/definitions/flag
description
:
The device requires shifted clock phase (CPHA) mode.
spi-cpol
:
$ref
:
/schemas/types.yaml#/definitions/flag
description
:
The device requires inverse clock polarity (CPOL) mode.
spi-cs-high
:
$ref
:
/schemas/types.yaml#/definitions/flag
description
:
The device requires the chip select active high.
spi-lsb-first
:
$ref
:
/schemas/types.yaml#/definitions/flag
description
:
The device requires the LSB first mode.
spi-max-frequency
:
$ref
:
/schemas/types.yaml#/definitions/uint32
description
:
Maximum SPI clocking speed of the device in Hz.
spi-rx-bus-width
:
allOf
:
-
$ref
:
/schemas/types.yaml#/definitions/uint32
-
enum
:
[
1
,
2
,
4
]
-
default
:
1
description
:
Bus width to the SPI bus used for MISO.
spi-rx-delay-us
:
description
:
Delay, in microseconds, after a read transfer.
spi-tx-bus-width
:
allOf
:
-
$ref
:
/schemas/types.yaml#/definitions/uint32
-
enum
:
[
1
,
2
,
4
]
-
default
:
1
description
:
Bus width to the SPI bus used for MOSI.
spi-tx-delay-us
:
description
:
Delay, in microseconds, after a write transfer.
required
:
-
compatible
-
reg
examples
:
-
|
spi@f00 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
reg = <0xf00 0x20>;
interrupts = <2 13 0 2 14 0>;
interrupt-parent = <&mpc5200_pic>;
ethernet-switch@0 {
compatible = "micrel,ks8995m";
spi-max-frequency = <1000000>;
reg = <0>;
};
codec@1 {
compatible = "ti,tlv320aic26";
spi-max-frequency = <100000>;
reg = <1>;
};
};
Documentation/devicetree/bindings/spi/spi-gpio.txt
deleted
100644 → 0
View file @
2337ff45
SPI-GPIO devicetree bindings
This represents a group of 3-n GPIO lines used for bit-banged SPI on dedicated
GPIO lines.
Required properties:
- compatible: should be set to "spi-gpio"
- #address-cells: should be set to <0x1>
- ranges
- sck-gpios: GPIO spec for the SCK line to use
- miso-gpios: GPIO spec for the MISO line to use
- mosi-gpios: GPIO spec for the MOSI line to use
- cs-gpios: GPIOs to use for chipselect lines.
Not needed if num-chipselects = <0>.
- num-chipselects: Number of chipselect lines. Should be <0> if a single device
with no chip select is connected.
Deprecated bindings:
These legacy GPIO line bindings can alternatively be used to define the
GPIO lines used, they should not be used in new device trees.
- gpio-sck: GPIO spec for the SCK line to use
- gpio-miso: GPIO spec for the MISO line to use
- gpio-mosi: GPIO spec for the MOSI line to use
Example:
spi {
compatible = "spi-gpio";
#address-cells = <0x1>;
ranges;
sck-gpios = <&gpio 95 0>;
miso-gpios = <&gpio 98 0>;
mosi-gpios = <&gpio 97 0>;
cs-gpios = <&gpio 125 0>;
num-chipselects = <1>;
/* clients */
};
Documentation/devicetree/bindings/spi/spi-gpio.yaml
0 → 100644
View file @
106dbe24
# SPDX-License-Identifier: GPL-2.0
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/spi-gpio.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
SPI-GPIO devicetree bindings
maintainers
:
-
Rob Herring <robh@kernel.org>
description
:
This represents a group of 3-n GPIO lines used for bit-banged SPI on
dedicated GPIO lines.
allOf
:
-
$ref
:
"
/schemas/spi/spi-controller.yaml#"
properties
:
compatible
:
const
:
spi-gpio
sck-gpios
:
description
:
GPIO spec for the SCK line to use
maxItems
:
1
miso-gpios
:
description
:
GPIO spec for the MISO line to use
maxItems
:
1
mosi-gpios
:
description
:
GPIO spec for the MOSI line to use
maxItems
:
1
cs-gpios
:
description
:
GPIOs to use for chipselect lines.
Not needed if num-chipselects = <0>.
minItems
:
1
maxItems
:
1024
num-chipselects
:
description
:
Number of chipselect lines. Should be <0> if a single device
with no chip select is connected.
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
# Deprecated properties
gpio-sck
:
false
gpio-miso
:
false
gpio-mosi
:
false
required
:
-
compatible
-
num-chipselects
-
sck-gpios
examples
:
-
|
spi {
compatible = "spi-gpio";
#address-cells = <0x1>;
#size-cells = <0x0>;
sck-gpios = <&gpio 95 0>;
miso-gpios = <&gpio 98 0>;
mosi-gpios = <&gpio 97 0>;
cs-gpios = <&gpio 125 0>;
num-chipselects = <1>;
/* clients */
};
...
Documentation/devicetree/bindings/spi/spi-pl022.yaml
0 → 100644
View file @
106dbe24
# SPDX-License-Identifier: GPL-2.0
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/spi-pl022.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
ARM PL022 SPI controller
maintainers
:
-
Linus Walleij <linus.walleij@linaro.org>
allOf
:
-
$ref
:
"
spi-controller.yaml#"
# We need a select here so we don't match all nodes with 'arm,primecell'
select
:
properties
:
compatible
:
contains
:
const
:
arm,pl022
required
:
-
compatible
properties
:
compatible
:
items
:
-
const
:
arm,pl022
-
const
:
arm,primecell
reg
:
maxItems
:
1
interrupts
:
maxItems
:
1
clocks
:
maxItems
:
2
clock-names
:
items
:
-
enum
:
-
SSPCLK
-
sspclk
-
const
:
apb_pclk
pl022,autosuspend-delay
:
description
:
delay in ms following transfer completion before the
runtime power management system suspends the device. A setting of
0
indicates no delay and the device will be suspended immediately.
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
pl022,rt
:
description
:
indicates the controller should run the message pump with realtime
priority to minimise the transfer latency on the bus (boolean)
type
:
boolean
dmas
:
description
:
Two or more DMA channel specifiers following the convention outlined
in bindings/dma/dma.txt
minItems
:
2
maxItems
:
32
dma-names
:
description
:
There must be at least one channel named "tx" for transmit and named "rx"
for receive.
minItems
:
2
maxItems
:
32
additionalItems
:
true
items
:
-
const
:
rx
-
const
:
tx
patternProperties
:
"
^[a-zA-Z][a-zA-Z0-9,+
\\
-._]{0,63}@[0-9a-f]+$"
:
type
:
object
# SPI slave nodes must be children of the SPI master node and can
# contain the following properties.
properties
:
pl022,interface
:
description
:
SPI interface type
allOf
:
-
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
-
enum
:
-
0
# SPI
-
1
# Texas Instruments Synchronous Serial Frame Format
-
2
# Microwire (Half Duplex)
pl022,com-mode
:
description
:
Specifies the transfer mode
allOf
:
-
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
-
enum
:
-
0
# interrupt mode
-
1
# polling mode
-
2
# DMA mode
default
:
1
pl022,rx-level-trig
:
description
:
Rx FIFO watermark level
allOf
:
-
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
-
minimum
:
0
maximum
:
4
pl022,tx-level-trig
:
description
:
Tx FIFO watermark level
allOf
:
-
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
-
minimum
:
0
maximum
:
4
pl022,ctrl-len
:
description
:
Microwire interface - Control length
allOf
:
-
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
-
minimum
:
0x03
maximum
:
0x1f
pl022,wait-state
:
description
:
Microwire interface - Wait state
allOf
:
-
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
-
enum
:
[
0
,
1
]
pl022,duplex
:
description
:
Microwire interface - Full/Half duplex
allOf
:
-
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
-
enum
:
[
0
,
1
]
required
:
-
compatible
-
reg
-
interrupts
examples
:
-
|
spi@e0100000 {
compatible = "arm,pl022", "arm,primecell";
reg = <0xe0100000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 31 0x4>;
dmas = <&dma_controller 23 1>,
<&dma_controller 24 0>;
dma-names = "rx", "tx";
m25p80@1 {
compatible = "st,m25p80";
reg = <1>;
spi-max-frequency = <12000000>;
spi-cpol;
spi-cpha;
pl022,interface = <0>;
pl022,com-mode = <0x2>;
pl022,rx-level-trig = <0>;
pl022,tx-level-trig = <0>;
pl022,ctrl-len = <0x11>;
pl022,wait-state = <0>;
pl022,duplex = <0>;
};
};
...
Documentation/devicetree/bindings/spi/spi-stm32-qspi.txt
View file @
106dbe24
...
...
@@ -19,8 +19,11 @@ Required properties:
- reg: chip-Select number (QSPI controller may connect 2 flashes)
- spi-max-frequency: max frequency of spi bus
Optional propert
y
:
Optional propert
ies
:
- spi-rx-bus-width: see ./spi-bus.txt for the description
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt.
- dma-names: DMA request names should include "tx" and "rx" if present.
Example:
...
...
Documentation/devicetree/bindings/spi/spi-sun4i.txt
deleted
100644 → 0
View file @
2337ff45
Allwinner A10 SPI controller
Required properties:
- compatible: Should be "allwinner,sun4-a10-spi".
- reg: Should contain register location and length.
- interrupts: Should contain interrupt.
- clocks: phandle to the clocks feeding the SPI controller. Two are
needed:
- "ahb": the gated AHB parent clock
- "mod": the parent module clock
- clock-names: Must contain the clock names described just above
Example:
spi1: spi@1c06000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c06000 0x1000>;
interrupts = <11>;
clocks = <&ahb_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
#address-cells = <1>;
#size-cells = <0>;
};
Documentation/devicetree/bindings/spi/spi-sun6i.txt
deleted
100644 → 0
View file @
2337ff45
Allwinner A31/H3 SPI controller
Required properties:
- compatible: Should be "allwinner,sun6i-a31-spi" or "allwinner,sun8i-h3-spi".
- reg: Should contain register location and length.
- interrupts: Should contain interrupt.
- clocks: phandle to the clocks feeding the SPI controller. Two are
needed:
- "ahb": the gated AHB parent clock
- "mod": the parent module clock
- clock-names: Must contain the clock names described just above
- resets: phandle to the reset controller asserting this device in
reset
Optional properties:
- dmas: DMA specifiers for rx and tx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt
- dma-names: DMA request names should include "rx" and "tx" if present.
Example:
spi1: spi@1c69000 {
compatible = "allwinner,sun6i-a31-spi";
reg = <0x01c69000 0x1000>;
interrupts = <0 66 4>;
clocks = <&ahb1_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
resets = <&ahb1_rst 21>;
};
spi0: spi@1c68000 {
compatible = "allwinner,sun8i-h3-spi";
reg = <0x01c68000 0x1000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
clock-names = "ahb", "mod";
dmas = <&dma 23>, <&dma 23>;
dma-names = "rx", "tx";
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins>;
resets = <&ccu RST_BUS_SPI0>;
#address-cells = <1>;
#size-cells = <0>;
};
Documentation/devicetree/bindings/spi/spi-synquacer.txt
0 → 100644
View file @
106dbe24
* Socionext Synquacer HS-SPI bindings
Required Properties:
- compatible: should be "socionext,synquacer-spi"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: should contain the "spi_rx", "spi_tx" and "spi_fault" interrupts.
- clocks: core clock iHCLK. Optional rate clock iPCLK (default is iHCLK)
- clock-names: Shall be "iHCLK" and "iPCLK" respectively
Optional Properties:
- socionext,use-rtm: boolean, if required to use "retimed clock" for RX
- socionext,set-aces: boolean, if same active clock edges field to be set.
Example:
spi0: spi@ff110000 {
compatible = "socionext,synquacer-spi";
reg = <0xff110000 0x1000>;
interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_hsspi>;
clock-names = "iHCLK";
socionext,use-rtm;
socionext,set-aces;
};
Documentation/devicetree/bindings/spi/spi_pl022.txt
deleted
100644 → 0
View file @
2337ff45
ARM PL022 SPI controller
Required properties:
- compatible : "arm,pl022", "arm,primecell"
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt
- num-cs : total number of chipselects
Optional properties:
- cs-gpios : should specify GPIOs used for chipselects.
The gpios will be referred to as reg = <index> in the SPI child nodes.
If unspecified, a single SPI device without a chip select can be used.
- pl022,autosuspend-delay : delay in ms following transfer completion before
the runtime power management system suspends the
device. A setting of 0 indicates no delay and the
device will be suspended immediately
- pl022,rt : indicates the controller should run the message pump with realtime
priority to minimise the transfer latency on the bus (boolean)
- dmas : Two or more DMA channel specifiers following the convention outlined
in bindings/dma/dma.txt
- dma-names: Names for the dma channels, if present. There must be at
least one channel named "tx" for transmit and named "rx" for
receive.
SPI slave nodes must be children of the SPI master node and can
contain the following properties.
- pl022,interface : interface type:
0: SPI
1: Texas Instruments Synchronous Serial Frame Format
2: Microwire (Half Duplex)
- pl022,com-mode : specifies the transfer mode:
0: interrupt mode
1: polling mode (default mode if property not present)
2: DMA mode
- pl022,rx-level-trig : Rx FIFO watermark level
- pl022,tx-level-trig : Tx FIFO watermark level
- pl022,ctrl-len : Microwire interface: Control length
- pl022,wait-state : Microwire interface: Wait state
- pl022,duplex : Microwire interface: Full/Half duplex
Example:
spi@e0100000 {
compatible = "arm,pl022", "arm,primecell";
reg = <0xe0100000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 31 0x4>;
dmas = <&dma-controller 23 1>,
<&dma-controller 24 0>;
dma-names = "rx", "tx";
m25p80@1 {
compatible = "st,m25p80";
reg = <1>;
spi-max-frequency = <12000000>;
spi-cpol;
spi-cpha;
pl022,interface = <0>;
pl022,com-mode = <0x2>;
pl022,rx-level-trig = <0>;
pl022,tx-level-trig = <0>;
pl022,ctrl-len = <0x11>;
pl022,wait-state = <0>;
pl022,duplex = <0>;
};
};
MAINTAINERS
View file @
106dbe24
...
...
@@ -14630,6 +14630,14 @@ S: Maintained
F: drivers/net/ethernet/socionext/netsec.c
F: Documentation/devicetree/bindings/net/socionext-netsec.txt
SOCIONEXT (SNI) Synquacer SPI DRIVER
M: Masahisa Kojima <masahisa.kojima@linaro.org>
M: Jassi Brar <jaswinder.singh@linaro.org>
L: linux-spi@vger.kernel.org
S: Maintained
F: drivers/spi/spi-synquacer.c
F: Documentation/devicetree/bindings/spi/spi-synquacer.txt
SOLIDRUN CLEARFOG SUPPORT
M: Russell King <linux@armlinux.org.uk>
S: Maintained
...
...
drivers/spi/Kconfig
View file @
106dbe24
...
...
@@ -120,7 +120,7 @@ config SPI_AXI_SPI_ENGINE
config SPI_BCM2835
tristate "BCM2835 SPI controller"
depends on GPIOLIB
depends on ARCH_BCM2835 || COMPILE_TEST
depends on ARCH_BCM2835 ||
ARCH_BRCMSTB ||
COMPILE_TEST
help
This selects a driver for the Broadcom BCM2835 SPI master.
...
...
@@ -131,7 +131,7 @@ config SPI_BCM2835
config SPI_BCM2835AUX
tristate "BCM2835 SPI auxiliary controller"
depends on (
ARCH_BCM2835
&& GPIOLIB) || COMPILE_TEST
depends on (
(ARCH_BCM2835 || ARCH_BRCMSTB)
&& GPIOLIB) || COMPILE_TEST
help
This selects a driver for the Broadcom BCM2835 SPI aux master.
...
...
@@ -733,6 +733,16 @@ config SPI_SUN6I
help
This enables using the SPI controller on the Allwinner A31 SoCs.
config SPI_SYNQUACER
tristate "Socionext's SynQuacer HighSpeed SPI controller"
depends on ARCH_SYNQUACER || COMPILE_TEST
help
SPI driver for Socionext's High speed SPI controller which provides
various operating modes for interfacing to serial peripheral devices
that use the de-facto standard SPI protocol.
It also supports the new dual-bit and quad-bit SPI protocol.
config SPI_MXIC
tristate "Macronix MX25F0A SPI controller"
depends on SPI_MASTER
...
...
drivers/spi/Makefile
View file @
106dbe24
...
...
@@ -106,6 +106,7 @@ obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o
obj-$(CONFIG_SPI_ST_SSC4)
+=
spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I)
+=
spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I)
+=
spi-sun6i.o
obj-$(CONFIG_SPI_SYNQUACER)
+=
spi-synquacer.o
obj-$(CONFIG_SPI_TEGRA114)
+=
spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH)
+=
spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK)
+=
spi-tegra20-slink.o
...
...
drivers/spi/atmel-quadspi.c
View file @
106dbe24
...
...
@@ -151,6 +151,7 @@ struct atmel_qspi {
const
struct
atmel_qspi_caps
*
caps
;
u32
pending
;
u32
mr
;
u32
scr
;
struct
completion
cmd_completion
;
};
...
...
@@ -382,7 +383,7 @@ static int atmel_qspi_setup(struct spi_device *spi)
struct
spi_controller
*
ctrl
=
spi
->
master
;
struct
atmel_qspi
*
aq
=
spi_controller_get_devdata
(
ctrl
);
unsigned
long
src_rate
;
u32
sc
r
,
sc
br
;
u32
scbr
;
if
(
ctrl
->
busy
)
return
-
EBUSY
;
...
...
@@ -399,13 +400,13 @@ static int atmel_qspi_setup(struct spi_device *spi)
if
(
scbr
>
0
)
scbr
--
;
scr
=
QSPI_SCR_SCBR
(
scbr
);
writel_relaxed
(
scr
,
aq
->
regs
+
QSPI_SCR
);
aq
->
scr
=
QSPI_SCR_SCBR
(
scbr
);
writel_relaxed
(
aq
->
scr
,
aq
->
regs
+
QSPI_SCR
);
return
0
;
}
static
int
atmel_qspi_init
(
struct
atmel_qspi
*
aq
)
static
void
atmel_qspi_init
(
struct
atmel_qspi
*
aq
)
{
/* Reset the QSPI controller */
writel_relaxed
(
QSPI_CR_SWRST
,
aq
->
regs
+
QSPI_CR
);
...
...
@@ -416,8 +417,6 @@ static int atmel_qspi_init(struct atmel_qspi *aq)
/* Enable the QSPI controller */
writel_relaxed
(
QSPI_CR_QSPIEN
,
aq
->
regs
+
QSPI_CR
);
return
0
;
}
static
irqreturn_t
atmel_qspi_interrupt
(
int
irq
,
void
*
dev_id
)
...
...
@@ -536,9 +535,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
if
(
err
)
goto
disable_qspick
;
err
=
atmel_qspi_init
(
aq
);
if
(
err
)
goto
disable_qspick
;
atmel_qspi_init
(
aq
);
err
=
spi_register_controller
(
ctrl
);
if
(
err
)
...
...
@@ -587,7 +584,11 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
clk_prepare_enable
(
aq
->
pclk
);
clk_prepare_enable
(
aq
->
qspick
);
return
atmel_qspi_init
(
aq
);
atmel_qspi_init
(
aq
);
writel_relaxed
(
aq
->
scr
,
aq
->
regs
+
QSPI_SCR
);
return
0
;
}
static
SIMPLE_DEV_PM_OPS
(
atmel_qspi_pm_ops
,
atmel_qspi_suspend
,
...
...
drivers/spi/spi-at91-usart.c
View file @
106dbe24
...
...
@@ -8,9 +8,12 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-direction.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
...
...
@@ -59,6 +62,8 @@
#define US_INIT \
(US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
#define US_DMA_MIN_BYTES 16
#define US_DMA_TIMEOUT (msecs_to_jiffies(1000))
/* Register access macros */
#define at91_usart_spi_readl(port, reg) \
...
...
@@ -72,14 +77,19 @@
writeb_relaxed((value), (port)->regs + US_##reg)
struct
at91_usart_spi
{
struct
platform_device
*
mpdev
;
struct
spi_transfer
*
current_transfer
;
void
__iomem
*
regs
;
struct
device
*
dev
;
struct
clk
*
clk
;
struct
completion
xfer_completion
;
/*used in interrupt to protect data reading*/
spinlock_t
lock
;
phys_addr_t
phybase
;
int
irq
;
unsigned
int
current_tx_remaining_bytes
;
unsigned
int
current_rx_remaining_bytes
;
...
...
@@ -88,8 +98,182 @@ struct at91_usart_spi {
u32
status
;
bool
xfer_failed
;
bool
use_dma
;
};
static
void
dma_callback
(
void
*
data
)
{
struct
spi_controller
*
ctlr
=
data
;
struct
at91_usart_spi
*
aus
=
spi_master_get_devdata
(
ctlr
);
at91_usart_spi_writel
(
aus
,
IER
,
US_IR_RXRDY
);
aus
->
current_rx_remaining_bytes
=
0
;
complete
(
&
aus
->
xfer_completion
);
}
static
bool
at91_usart_spi_can_dma
(
struct
spi_controller
*
ctrl
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
struct
at91_usart_spi
*
aus
=
spi_master_get_devdata
(
ctrl
);
return
aus
->
use_dma
&&
xfer
->
len
>=
US_DMA_MIN_BYTES
;
}
static
int
at91_usart_spi_configure_dma
(
struct
spi_controller
*
ctlr
,
struct
at91_usart_spi
*
aus
)
{
struct
dma_slave_config
slave_config
;
struct
device
*
dev
=
&
aus
->
mpdev
->
dev
;
phys_addr_t
phybase
=
aus
->
phybase
;
dma_cap_mask_t
mask
;
int
err
=
0
;
dma_cap_zero
(
mask
);
dma_cap_set
(
DMA_SLAVE
,
mask
);
ctlr
->
dma_tx
=
dma_request_slave_channel_reason
(
dev
,
"tx"
);
if
(
IS_ERR_OR_NULL
(
ctlr
->
dma_tx
))
{
if
(
IS_ERR
(
ctlr
->
dma_tx
))
{
err
=
PTR_ERR
(
ctlr
->
dma_tx
);
goto
at91_usart_spi_error_clear
;
}
dev_dbg
(
dev
,
"DMA TX channel not available, SPI unable to use DMA
\n
"
);
err
=
-
EBUSY
;
goto
at91_usart_spi_error_clear
;
}
ctlr
->
dma_rx
=
dma_request_slave_channel_reason
(
dev
,
"rx"
);
if
(
IS_ERR_OR_NULL
(
ctlr
->
dma_rx
))
{
if
(
IS_ERR
(
ctlr
->
dma_rx
))
{
err
=
PTR_ERR
(
ctlr
->
dma_rx
);
goto
at91_usart_spi_error
;
}
dev_dbg
(
dev
,
"DMA RX channel not available, SPI unable to use DMA
\n
"
);
err
=
-
EBUSY
;
goto
at91_usart_spi_error
;
}
slave_config
.
dst_addr_width
=
DMA_SLAVE_BUSWIDTH_1_BYTE
;
slave_config
.
src_addr_width
=
DMA_SLAVE_BUSWIDTH_1_BYTE
;
slave_config
.
dst_addr
=
(
dma_addr_t
)
phybase
+
US_THR
;
slave_config
.
src_addr
=
(
dma_addr_t
)
phybase
+
US_RHR
;
slave_config
.
src_maxburst
=
1
;
slave_config
.
dst_maxburst
=
1
;
slave_config
.
device_fc
=
false
;
slave_config
.
direction
=
DMA_DEV_TO_MEM
;
if
(
dmaengine_slave_config
(
ctlr
->
dma_rx
,
&
slave_config
))
{
dev_err
(
&
ctlr
->
dev
,
"failed to configure rx dma channel
\n
"
);
err
=
-
EINVAL
;
goto
at91_usart_spi_error
;
}
slave_config
.
direction
=
DMA_MEM_TO_DEV
;
if
(
dmaengine_slave_config
(
ctlr
->
dma_tx
,
&
slave_config
))
{
dev_err
(
&
ctlr
->
dev
,
"failed to configure tx dma channel
\n
"
);
err
=
-
EINVAL
;
goto
at91_usart_spi_error
;
}
aus
->
use_dma
=
true
;
return
0
;
at91_usart_spi_error:
if
(
!
IS_ERR_OR_NULL
(
ctlr
->
dma_tx
))
dma_release_channel
(
ctlr
->
dma_tx
);
if
(
!
IS_ERR_OR_NULL
(
ctlr
->
dma_rx
))
dma_release_channel
(
ctlr
->
dma_rx
);
ctlr
->
dma_tx
=
NULL
;
ctlr
->
dma_rx
=
NULL
;
at91_usart_spi_error_clear:
return
err
;
}
static
void
at91_usart_spi_release_dma
(
struct
spi_controller
*
ctlr
)
{
if
(
ctlr
->
dma_rx
)
dma_release_channel
(
ctlr
->
dma_rx
);
if
(
ctlr
->
dma_tx
)
dma_release_channel
(
ctlr
->
dma_tx
);
}
static
void
at91_usart_spi_stop_dma
(
struct
spi_controller
*
ctlr
)
{
if
(
ctlr
->
dma_rx
)
dmaengine_terminate_all
(
ctlr
->
dma_rx
);
if
(
ctlr
->
dma_tx
)
dmaengine_terminate_all
(
ctlr
->
dma_tx
);
}
static
int
at91_usart_spi_dma_transfer
(
struct
spi_controller
*
ctlr
,
struct
spi_transfer
*
xfer
)
{
struct
at91_usart_spi
*
aus
=
spi_master_get_devdata
(
ctlr
);
struct
dma_chan
*
rxchan
=
ctlr
->
dma_rx
;
struct
dma_chan
*
txchan
=
ctlr
->
dma_tx
;
struct
dma_async_tx_descriptor
*
rxdesc
;
struct
dma_async_tx_descriptor
*
txdesc
;
dma_cookie_t
cookie
;
/* Disable RX interrupt */
at91_usart_spi_writel
(
aus
,
IDR
,
US_IR_RXRDY
);
rxdesc
=
dmaengine_prep_slave_sg
(
rxchan
,
xfer
->
rx_sg
.
sgl
,
xfer
->
rx_sg
.
nents
,
DMA_DEV_TO_MEM
,
DMA_PREP_INTERRUPT
|
DMA_CTRL_ACK
);
if
(
!
rxdesc
)
goto
at91_usart_spi_err_dma
;
txdesc
=
dmaengine_prep_slave_sg
(
txchan
,
xfer
->
tx_sg
.
sgl
,
xfer
->
tx_sg
.
nents
,
DMA_MEM_TO_DEV
,
DMA_PREP_INTERRUPT
|
DMA_CTRL_ACK
);
if
(
!
txdesc
)
goto
at91_usart_spi_err_dma
;
rxdesc
->
callback
=
dma_callback
;
rxdesc
->
callback_param
=
ctlr
;
cookie
=
rxdesc
->
tx_submit
(
rxdesc
);
if
(
dma_submit_error
(
cookie
))
goto
at91_usart_spi_err_dma
;
cookie
=
txdesc
->
tx_submit
(
txdesc
);
if
(
dma_submit_error
(
cookie
))
goto
at91_usart_spi_err_dma
;
rxchan
->
device
->
device_issue_pending
(
rxchan
);
txchan
->
device
->
device_issue_pending
(
txchan
);
return
0
;
at91_usart_spi_err_dma:
/* Enable RX interrupt if something fails and fallback to PIO */
at91_usart_spi_writel
(
aus
,
IER
,
US_IR_RXRDY
);
at91_usart_spi_stop_dma
(
ctlr
);
return
-
ENOMEM
;
}
static
unsigned
long
at91_usart_spi_dma_timeout
(
struct
at91_usart_spi
*
aus
)
{
return
wait_for_completion_timeout
(
&
aus
->
xfer_completion
,
US_DMA_TIMEOUT
);
}
static
inline
u32
at91_usart_spi_tx_ready
(
struct
at91_usart_spi
*
aus
)
{
return
aus
->
status
&
US_IR_TXRDY
;
...
...
@@ -216,6 +400,8 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
struct
spi_transfer
*
xfer
)
{
struct
at91_usart_spi
*
aus
=
spi_master_get_devdata
(
ctlr
);
unsigned
long
dma_timeout
=
0
;
int
ret
=
0
;
at91_usart_spi_set_xfer_speed
(
aus
,
xfer
);
aus
->
xfer_failed
=
false
;
...
...
@@ -225,8 +411,25 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
while
((
aus
->
current_tx_remaining_bytes
||
aus
->
current_rx_remaining_bytes
)
&&
!
aus
->
xfer_failed
)
{
at91_usart_spi_read_status
(
aus
);
at91_usart_spi_tx
(
aus
);
reinit_completion
(
&
aus
->
xfer_completion
);
if
(
at91_usart_spi_can_dma
(
ctlr
,
spi
,
xfer
)
&&
!
ret
)
{
ret
=
at91_usart_spi_dma_transfer
(
ctlr
,
xfer
);
if
(
ret
)
continue
;
dma_timeout
=
at91_usart_spi_dma_timeout
(
aus
);
if
(
WARN_ON
(
dma_timeout
==
0
))
{
dev_err
(
&
spi
->
dev
,
"DMA transfer timeout
\n
"
);
return
-
EIO
;
}
aus
->
current_tx_remaining_bytes
=
0
;
}
else
{
at91_usart_spi_read_status
(
aus
);
at91_usart_spi_tx
(
aus
);
}
cpu_relax
();
}
...
...
@@ -345,6 +548,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
controller
->
transfer_one
=
at91_usart_spi_transfer_one
;
controller
->
prepare_message
=
at91_usart_spi_prepare_message
;
controller
->
unprepare_message
=
at91_usart_spi_unprepare_message
;
controller
->
can_dma
=
at91_usart_spi_can_dma
;
controller
->
cleanup
=
at91_usart_spi_cleanup
;
controller
->
max_speed_hz
=
DIV_ROUND_UP
(
clk_get_rate
(
clk
),
US_MIN_CLK_DIV
);
...
...
@@ -376,7 +580,17 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
aus
->
spi_clk
=
clk_get_rate
(
clk
);
at91_usart_spi_init
(
aus
);
aus
->
phybase
=
regs
->
start
;
aus
->
mpdev
=
to_platform_device
(
pdev
->
dev
.
parent
);
ret
=
at91_usart_spi_configure_dma
(
controller
,
aus
);
if
(
ret
)
goto
at91_usart_fail_dma
;
spin_lock_init
(
&
aus
->
lock
);
init_completion
(
&
aus
->
xfer_completion
);
ret
=
devm_spi_register_master
(
&
pdev
->
dev
,
controller
);
if
(
ret
)
goto
at91_usart_fail_register_master
;
...
...
@@ -389,6 +603,8 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
return
0
;
at91_usart_fail_register_master:
at91_usart_spi_release_dma
(
controller
);
at91_usart_fail_dma:
clk_disable_unprepare
(
clk
);
at91_usart_spi_probe_fail:
spi_master_put
(
controller
);
...
...
@@ -453,6 +669,7 @@ static int at91_usart_spi_remove(struct platform_device *pdev)
struct
spi_controller
*
ctlr
=
platform_get_drvdata
(
pdev
);
struct
at91_usart_spi
*
aus
=
spi_master_get_devdata
(
ctlr
);
at91_usart_spi_release_dma
(
ctlr
);
clk_disable_unprepare
(
aus
->
clk
);
return
0
;
...
...
drivers/spi/spi-bcm2835.c
View file @
106dbe24
...
...
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
...
...
@@ -64,14 +65,18 @@
#define BCM2835_SPI_FIFO_SIZE 64
#define BCM2835_SPI_FIFO_SIZE_3_4 48
#define BCM2835_SPI_POLLING_LIMIT_US 30
#define BCM2835_SPI_POLLING_JIFFIES 2
#define BCM2835_SPI_DMA_MIN_LENGTH 96
#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
| SPI_NO_CS | SPI_3WIRE)
#define DRV_NAME "spi-bcm2835"
/* define polling limits */
unsigned
int
polling_limit_us
=
30
;
module_param
(
polling_limit_us
,
uint
,
0664
);
MODULE_PARM_DESC
(
polling_limit_us
,
"time in us to run a transfer in polling mode
\n
"
);
/**
* struct bcm2835_spi - BCM2835 SPI controller
* @regs: base address of register map
...
...
@@ -88,6 +93,15 @@
* length is not a multiple of 4 (to overcome hardware limitation)
* @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
* @dma_pending: whether a DMA transfer is in progress
* @debugfs_dir: the debugfs directory - neede to remove debugfs when
* unloading the module
* @count_transfer_polling: count of how often polling mode is used
* @count_transfer_irq: count of how often interrupt mode is used
* @count_transfer_irq_after_polling: count of how often we fall back to
* interrupt mode after starting in polling mode.
* These are counted as well in @count_transfer_polling and
* @count_transfer_irq
* @count_transfer_dma: count how often dma mode is used
*/
struct
bcm2835_spi
{
void
__iomem
*
regs
;
...
...
@@ -102,8 +116,55 @@ struct bcm2835_spi {
int
rx_prologue
;
unsigned
int
tx_spillover
;
unsigned
int
dma_pending
;
struct
dentry
*
debugfs_dir
;
u64
count_transfer_polling
;
u64
count_transfer_irq
;
u64
count_transfer_irq_after_polling
;
u64
count_transfer_dma
;
};
#if defined(CONFIG_DEBUG_FS)
static
void
bcm2835_debugfs_create
(
struct
bcm2835_spi
*
bs
,
const
char
*
dname
)
{
char
name
[
64
];
struct
dentry
*
dir
;
/* get full name */
snprintf
(
name
,
sizeof
(
name
),
"spi-bcm2835-%s"
,
dname
);
/* the base directory */
dir
=
debugfs_create_dir
(
name
,
NULL
);
bs
->
debugfs_dir
=
dir
;
/* the counters */
debugfs_create_u64
(
"count_transfer_polling"
,
0444
,
dir
,
&
bs
->
count_transfer_polling
);
debugfs_create_u64
(
"count_transfer_irq"
,
0444
,
dir
,
&
bs
->
count_transfer_irq
);
debugfs_create_u64
(
"count_transfer_irq_after_polling"
,
0444
,
dir
,
&
bs
->
count_transfer_irq_after_polling
);
debugfs_create_u64
(
"count_transfer_dma"
,
0444
,
dir
,
&
bs
->
count_transfer_dma
);
}
static
void
bcm2835_debugfs_remove
(
struct
bcm2835_spi
*
bs
)
{
debugfs_remove_recursive
(
bs
->
debugfs_dir
);
bs
->
debugfs_dir
=
NULL
;
}
#else
static
void
bcm2835_debugfs_create
(
struct
bcm2835_spi
*
bs
,
const
char
*
dname
)
{
}
static
void
bcm2835_debugfs_remove
(
struct
bcm2835_spi
*
bs
)
{
}
#endif
/* CONFIG_DEBUG_FS */
static
inline
u32
bcm2835_rd
(
struct
bcm2835_spi
*
bs
,
unsigned
reg
)
{
return
readl
(
bs
->
regs
+
reg
);
...
...
@@ -248,9 +309,9 @@ static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count)
}
}
static
void
bcm2835_spi_reset_hw
(
struct
spi_
master
*
maste
r
)
static
void
bcm2835_spi_reset_hw
(
struct
spi_
controller
*
ctl
r
)
{
struct
bcm2835_spi
*
bs
=
spi_
master_get_devdata
(
maste
r
);
struct
bcm2835_spi
*
bs
=
spi_
controller_get_devdata
(
ctl
r
);
u32
cs
=
bcm2835_rd
(
bs
,
BCM2835_SPI_CS
);
/* Disable SPI interrupts and transfer */
...
...
@@ -269,8 +330,8 @@ static void bcm2835_spi_reset_hw(struct spi_master *master)
static
irqreturn_t
bcm2835_spi_interrupt
(
int
irq
,
void
*
dev_id
)
{
struct
spi_
master
*
maste
r
=
dev_id
;
struct
bcm2835_spi
*
bs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctl
r
=
dev_id
;
struct
bcm2835_spi
*
bs
=
spi_
controller_get_devdata
(
ctl
r
);
u32
cs
=
bcm2835_rd
(
bs
,
BCM2835_SPI_CS
);
/*
...
...
@@ -292,20 +353,23 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
if
(
!
bs
->
rx_len
)
{
/* Transfer complete - reset SPI HW */
bcm2835_spi_reset_hw
(
maste
r
);
bcm2835_spi_reset_hw
(
ctl
r
);
/* wake up the framework */
complete
(
&
maste
r
->
xfer_completion
);
complete
(
&
ctl
r
->
xfer_completion
);
}
return
IRQ_HANDLED
;
}
static
int
bcm2835_spi_transfer_one_irq
(
struct
spi_
master
*
maste
r
,
static
int
bcm2835_spi_transfer_one_irq
(
struct
spi_
controller
*
ctl
r
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
tfr
,
u32
cs
,
bool
fifo_empty
)
{
struct
bcm2835_spi
*
bs
=
spi_master_get_devdata
(
master
);
struct
bcm2835_spi
*
bs
=
spi_controller_get_devdata
(
ctlr
);
/* update usage statistics */
bs
->
count_transfer_irq
++
;
/*
* Enable HW block, but with interrupts still disabled.
...
...
@@ -328,7 +392,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
/**
* bcm2835_spi_transfer_prologue() - transfer first few bytes without DMA
* @
master: SPI mast
er
* @
ctlr: SPI master controll
er
* @tfr: SPI transfer
* @bs: BCM2835 SPI controller
* @cs: CS register
...
...
@@ -372,7 +436,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
* be transmitted in 32-bit width to ensure that the following DMA transfer can
* pick up the residue in the RX FIFO in ungarbled form.
*/
static
void
bcm2835_spi_transfer_prologue
(
struct
spi_
master
*
maste
r
,
static
void
bcm2835_spi_transfer_prologue
(
struct
spi_
controller
*
ctl
r
,
struct
spi_transfer
*
tfr
,
struct
bcm2835_spi
*
bs
,
u32
cs
)
...
...
@@ -413,9 +477,9 @@ static void bcm2835_spi_transfer_prologue(struct spi_master *master,
bcm2835_wr_fifo_count
(
bs
,
bs
->
rx_prologue
);
bcm2835_wait_tx_fifo_empty
(
bs
);
bcm2835_rd_fifo_count
(
bs
,
bs
->
rx_prologue
);
bcm2835_spi_reset_hw
(
maste
r
);
bcm2835_spi_reset_hw
(
ctl
r
);
dma_sync_single_for_device
(
maste
r
->
dma_rx
->
device
->
dev
,
dma_sync_single_for_device
(
ctl
r
->
dma_rx
->
device
->
dev
,
sg_dma_address
(
&
tfr
->
rx_sg
.
sgl
[
0
]),
bs
->
rx_prologue
,
DMA_FROM_DEVICE
);
...
...
@@ -479,11 +543,11 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs)
static
void
bcm2835_spi_dma_done
(
void
*
data
)
{
struct
spi_
master
*
maste
r
=
data
;
struct
bcm2835_spi
*
bs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctl
r
=
data
;
struct
bcm2835_spi
*
bs
=
spi_
controller_get_devdata
(
ctl
r
);
/* reset fifo and HW */
bcm2835_spi_reset_hw
(
maste
r
);
bcm2835_spi_reset_hw
(
ctl
r
);
/* and terminate tx-dma as we do not have an irq for it
* because when the rx dma will terminate and this callback
...
...
@@ -491,15 +555,15 @@ static void bcm2835_spi_dma_done(void *data)
* situation otherwise...
*/
if
(
cmpxchg
(
&
bs
->
dma_pending
,
true
,
false
))
{
dmaengine_terminate_async
(
maste
r
->
dma_tx
);
dmaengine_terminate_async
(
ctl
r
->
dma_tx
);
bcm2835_spi_undo_prologue
(
bs
);
}
/* and mark as completed */
;
complete
(
&
maste
r
->
xfer_completion
);
complete
(
&
ctl
r
->
xfer_completion
);
}
static
int
bcm2835_spi_prepare_sg
(
struct
spi_
master
*
maste
r
,
static
int
bcm2835_spi_prepare_sg
(
struct
spi_
controller
*
ctl
r
,
struct
spi_transfer
*
tfr
,
bool
is_tx
)
{
...
...
@@ -514,14 +578,14 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
if
(
is_tx
)
{
dir
=
DMA_MEM_TO_DEV
;
chan
=
maste
r
->
dma_tx
;
chan
=
ctl
r
->
dma_tx
;
nents
=
tfr
->
tx_sg
.
nents
;
sgl
=
tfr
->
tx_sg
.
sgl
;
flags
=
0
/* no tx interrupt */
;
}
else
{
dir
=
DMA_DEV_TO_MEM
;
chan
=
maste
r
->
dma_rx
;
chan
=
ctl
r
->
dma_rx
;
nents
=
tfr
->
rx_sg
.
nents
;
sgl
=
tfr
->
rx_sg
.
sgl
;
flags
=
DMA_PREP_INTERRUPT
;
...
...
@@ -534,7 +598,7 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
/* set callback for rx */
if
(
!
is_tx
)
{
desc
->
callback
=
bcm2835_spi_dma_done
;
desc
->
callback_param
=
maste
r
;
desc
->
callback_param
=
ctl
r
;
}
/* submit it to DMA-engine */
...
...
@@ -543,27 +607,30 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
return
dma_submit_error
(
cookie
);
}
static
int
bcm2835_spi_transfer_one_dma
(
struct
spi_
master
*
maste
r
,
static
int
bcm2835_spi_transfer_one_dma
(
struct
spi_
controller
*
ctl
r
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
tfr
,
u32
cs
)
{
struct
bcm2835_spi
*
bs
=
spi_
master_get_devdata
(
maste
r
);
struct
bcm2835_spi
*
bs
=
spi_
controller_get_devdata
(
ctl
r
);
int
ret
;
/* update usage statistics */
bs
->
count_transfer_dma
++
;
/*
* Transfer first few bytes without DMA if length of first TX or RX
* sglist entry is not a multiple of 4 bytes (hardware limitation).
*/
bcm2835_spi_transfer_prologue
(
maste
r
,
tfr
,
bs
,
cs
);
bcm2835_spi_transfer_prologue
(
ctl
r
,
tfr
,
bs
,
cs
);
/* setup tx-DMA */
ret
=
bcm2835_spi_prepare_sg
(
maste
r
,
tfr
,
true
);
ret
=
bcm2835_spi_prepare_sg
(
ctl
r
,
tfr
,
true
);
if
(
ret
)
goto
err_reset_hw
;
/* start TX early */
dma_async_issue_pending
(
maste
r
->
dma_tx
);
dma_async_issue_pending
(
ctl
r
->
dma_tx
);
/* mark as dma pending */
bs
->
dma_pending
=
1
;
...
...
@@ -579,27 +646,27 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
* mapping of the rx buffers still takes place
* this saves 10us or more.
*/
ret
=
bcm2835_spi_prepare_sg
(
maste
r
,
tfr
,
false
);
ret
=
bcm2835_spi_prepare_sg
(
ctl
r
,
tfr
,
false
);
if
(
ret
)
{
/* need to reset on errors */
dmaengine_terminate_sync
(
maste
r
->
dma_tx
);
dmaengine_terminate_sync
(
ctl
r
->
dma_tx
);
bs
->
dma_pending
=
false
;
goto
err_reset_hw
;
}
/* start rx dma late */
dma_async_issue_pending
(
maste
r
->
dma_rx
);
dma_async_issue_pending
(
ctl
r
->
dma_rx
);
/* wait for wakeup in framework */
return
1
;
err_reset_hw:
bcm2835_spi_reset_hw
(
maste
r
);
bcm2835_spi_reset_hw
(
ctl
r
);
bcm2835_spi_undo_prologue
(
bs
);
return
ret
;
}
static
bool
bcm2835_spi_can_dma
(
struct
spi_
master
*
maste
r
,
static
bool
bcm2835_spi_can_dma
(
struct
spi_
controller
*
ctl
r
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
tfr
)
{
...
...
@@ -611,21 +678,21 @@ static bool bcm2835_spi_can_dma(struct spi_master *master,
return
true
;
}
static
void
bcm2835_dma_release
(
struct
spi_
master
*
maste
r
)
static
void
bcm2835_dma_release
(
struct
spi_
controller
*
ctl
r
)
{
if
(
maste
r
->
dma_tx
)
{
dmaengine_terminate_sync
(
maste
r
->
dma_tx
);
dma_release_channel
(
maste
r
->
dma_tx
);
maste
r
->
dma_tx
=
NULL
;
if
(
ctl
r
->
dma_tx
)
{
dmaengine_terminate_sync
(
ctl
r
->
dma_tx
);
dma_release_channel
(
ctl
r
->
dma_tx
);
ctl
r
->
dma_tx
=
NULL
;
}
if
(
maste
r
->
dma_rx
)
{
dmaengine_terminate_sync
(
maste
r
->
dma_rx
);
dma_release_channel
(
maste
r
->
dma_rx
);
maste
r
->
dma_rx
=
NULL
;
if
(
ctl
r
->
dma_rx
)
{
dmaengine_terminate_sync
(
ctl
r
->
dma_rx
);
dma_release_channel
(
ctl
r
->
dma_rx
);
ctl
r
->
dma_rx
=
NULL
;
}
}
static
void
bcm2835_dma_init
(
struct
spi_
master
*
maste
r
,
struct
device
*
dev
)
static
void
bcm2835_dma_init
(
struct
spi_
controller
*
ctl
r
,
struct
device
*
dev
)
{
struct
dma_slave_config
slave_config
;
const
__be32
*
addr
;
...
...
@@ -633,7 +700,7 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
int
ret
;
/* base address in dma-space */
addr
=
of_get_address
(
maste
r
->
dev
.
of_node
,
0
,
NULL
,
NULL
);
addr
=
of_get_address
(
ctl
r
->
dev
.
of_node
,
0
,
NULL
,
NULL
);
if
(
!
addr
)
{
dev_err
(
dev
,
"could not get DMA-register address - not using dma mode
\n
"
);
goto
err
;
...
...
@@ -641,38 +708,36 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
dma_reg_base
=
be32_to_cpup
(
addr
);
/* get tx/rx dma */
maste
r
->
dma_tx
=
dma_request_slave_channel
(
dev
,
"tx"
);
if
(
!
maste
r
->
dma_tx
)
{
ctl
r
->
dma_tx
=
dma_request_slave_channel
(
dev
,
"tx"
);
if
(
!
ctl
r
->
dma_tx
)
{
dev_err
(
dev
,
"no tx-dma configuration found - not using dma mode
\n
"
);
goto
err
;
}
maste
r
->
dma_rx
=
dma_request_slave_channel
(
dev
,
"rx"
);
if
(
!
maste
r
->
dma_rx
)
{
ctl
r
->
dma_rx
=
dma_request_slave_channel
(
dev
,
"rx"
);
if
(
!
ctl
r
->
dma_rx
)
{
dev_err
(
dev
,
"no rx-dma configuration found - not using dma mode
\n
"
);
goto
err_release
;
}
/* configure DMAs */
slave_config
.
direction
=
DMA_MEM_TO_DEV
;
slave_config
.
dst_addr
=
(
u32
)(
dma_reg_base
+
BCM2835_SPI_FIFO
);
slave_config
.
dst_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
ret
=
dmaengine_slave_config
(
maste
r
->
dma_tx
,
&
slave_config
);
ret
=
dmaengine_slave_config
(
ctl
r
->
dma_tx
,
&
slave_config
);
if
(
ret
)
goto
err_config
;
slave_config
.
direction
=
DMA_DEV_TO_MEM
;
slave_config
.
src_addr
=
(
u32
)(
dma_reg_base
+
BCM2835_SPI_FIFO
);
slave_config
.
src_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
ret
=
dmaengine_slave_config
(
maste
r
->
dma_rx
,
&
slave_config
);
ret
=
dmaengine_slave_config
(
ctl
r
->
dma_rx
,
&
slave_config
);
if
(
ret
)
goto
err_config
;
/* all went well, so set can_dma */
maste
r
->
can_dma
=
bcm2835_spi_can_dma
;
ctl
r
->
can_dma
=
bcm2835_spi_can_dma
;
/* need to do TX AND RX DMA, so we need dummy buffers */
master
->
flags
=
SPI_MASTER_MUST_RX
|
SPI_MAST
ER_MUST_TX
;
ctlr
->
flags
=
SPI_CONTROLLER_MUST_RX
|
SPI_CONTROLL
ER_MUST_TX
;
return
;
...
...
@@ -680,20 +745,22 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
dev_err
(
dev
,
"issue configuring dma: %d - not using DMA mode
\n
"
,
ret
);
err_release:
bcm2835_dma_release
(
maste
r
);
bcm2835_dma_release
(
ctl
r
);
err:
return
;
}
static
int
bcm2835_spi_transfer_one_poll
(
struct
spi_
master
*
maste
r
,
static
int
bcm2835_spi_transfer_one_poll
(
struct
spi_
controller
*
ctl
r
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
tfr
,
u32
cs
,
unsigned
long
long
xfer_time_us
)
u32
cs
)
{
struct
bcm2835_spi
*
bs
=
spi_
master_get_devdata
(
maste
r
);
struct
bcm2835_spi
*
bs
=
spi_
controller_get_devdata
(
ctl
r
);
unsigned
long
timeout
;
/* update usage statistics */
bs
->
count_transfer_polling
++
;
/* enable HW block without interrupts */
bcm2835_wr
(
bs
,
BCM2835_SPI_CS
,
cs
|
BCM2835_SPI_CS_TA
);
...
...
@@ -703,8 +770,8 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
*/
bcm2835_wr_fifo_blind
(
bs
,
BCM2835_SPI_FIFO_SIZE
);
/* set the timeout */
timeout
=
jiffies
+
BCM2835_SPI_POLLING_JIFFIES
;
/* set the timeout
to at least 2 jiffies
*/
timeout
=
jiffies
+
2
+
HZ
*
polling_limit_us
/
1000000
;
/* loop until finished the transfer */
while
(
bs
->
rx_len
)
{
...
...
@@ -723,25 +790,28 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
jiffies
-
timeout
,
bs
->
tx_len
,
bs
->
rx_len
);
/* fall back to interrupt mode */
return
bcm2835_spi_transfer_one_irq
(
master
,
spi
,
/* update usage statistics */
bs
->
count_transfer_irq_after_polling
++
;
return
bcm2835_spi_transfer_one_irq
(
ctlr
,
spi
,
tfr
,
cs
,
false
);
}
}
/* Transfer complete - reset SPI HW */
bcm2835_spi_reset_hw
(
maste
r
);
bcm2835_spi_reset_hw
(
ctl
r
);
/* and return without waiting for completion */
return
0
;
}
static
int
bcm2835_spi_transfer_one
(
struct
spi_
master
*
maste
r
,
static
int
bcm2835_spi_transfer_one
(
struct
spi_
controller
*
ctl
r
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
tfr
)
{
struct
bcm2835_spi
*
bs
=
spi_master_get_devdata
(
master
);
unsigned
long
spi_hz
,
clk_hz
,
cdiv
;
unsigned
long
spi_used_hz
;
unsigned
long
long
xfer_time_us
;
struct
bcm2835_spi
*
bs
=
spi_controller_get_devdata
(
ctlr
);
unsigned
long
spi_hz
,
clk_hz
,
cdiv
,
spi_used_hz
;
unsigned
long
hz_per_byte
,
byte_limit
;
u32
cs
=
bcm2835_rd
(
bs
,
BCM2835_SPI_CS
);
/* set clock */
...
...
@@ -782,42 +852,49 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
bs
->
tx_len
=
tfr
->
len
;
bs
->
rx_len
=
tfr
->
len
;
/* calculate the estimated time in us the transfer runs */
xfer_time_us
=
(
unsigned
long
long
)
tfr
->
len
*
9
/* clocks/byte - SPI-HW waits 1 clock after each byte */
*
1000000
;
do_div
(
xfer_time_us
,
spi_used_hz
);
/* Calculate the estimated time in us the transfer runs. Note that
* there is 1 idle clocks cycles after each byte getting transferred
* so we have 9 cycles/byte. This is used to find the number of Hz
* per byte per polling limit. E.g., we can transfer 1 byte in 30 us
* per 300,000 Hz of bus clock.
*/
hz_per_byte
=
polling_limit_us
?
(
9
*
1000000
)
/
polling_limit_us
:
0
;
byte_limit
=
hz_per_byte
?
spi_used_hz
/
hz_per_byte
:
1
;
/* for short requests run polling*/
if
(
xfer_time_us
<=
BCM2835_SPI_POLLING_LIMIT_US
)
return
bcm2835_spi_transfer_one_poll
(
master
,
spi
,
tfr
,
cs
,
xfer_time_us
);
/* run in polling mode for short transfers */
if
(
tfr
->
len
<
byte_limit
)
return
bcm2835_spi_transfer_one_poll
(
ctlr
,
spi
,
tfr
,
cs
);
/* run in dma mode if conditions are right */
if
(
master
->
can_dma
&&
bcm2835_spi_can_dma
(
master
,
spi
,
tfr
))
return
bcm2835_spi_transfer_one_dma
(
master
,
spi
,
tfr
,
cs
);
/* run in dma mode if conditions are right
* Note that unlike poll or interrupt mode DMA mode does not have
* this 1 idle clock cycle pattern but runs the spi clock without gaps
*/
if
(
ctlr
->
can_dma
&&
bcm2835_spi_can_dma
(
ctlr
,
spi
,
tfr
))
return
bcm2835_spi_transfer_one_dma
(
ctlr
,
spi
,
tfr
,
cs
);
/* run in interrupt-mode */
return
bcm2835_spi_transfer_one_irq
(
maste
r
,
spi
,
tfr
,
cs
,
true
);
return
bcm2835_spi_transfer_one_irq
(
ctl
r
,
spi
,
tfr
,
cs
,
true
);
}
static
int
bcm2835_spi_prepare_message
(
struct
spi_
master
*
maste
r
,
static
int
bcm2835_spi_prepare_message
(
struct
spi_
controller
*
ctl
r
,
struct
spi_message
*
msg
)
{
struct
spi_device
*
spi
=
msg
->
spi
;
struct
bcm2835_spi
*
bs
=
spi_
master_get_devdata
(
maste
r
);
struct
bcm2835_spi
*
bs
=
spi_
controller_get_devdata
(
ctl
r
);
u32
cs
=
bcm2835_rd
(
bs
,
BCM2835_SPI_CS
);
int
ret
;
/*
* DMA transfers are limited to 16 bit (0 to 65535 bytes) by the SPI HW
* due to DLEN. Split up transfers (32-bit FIFO aligned) if the limit is
* exceeded.
*/
ret
=
spi_split_transfers_maxsize
(
master
,
msg
,
65532
,
GFP_KERNEL
|
GFP_DMA
);
if
(
ret
)
return
ret
;
if
(
ctlr
->
can_dma
)
{
/*
* DMA transfers are limited to 16 bit (0 to 65535 bytes) by
* the SPI HW due to DLEN. Split up transfers (32-bit FIFO
* aligned) if the limit is exceeded.
*/
ret
=
spi_split_transfers_maxsize
(
ctlr
,
msg
,
65532
,
GFP_KERNEL
|
GFP_DMA
);
if
(
ret
)
return
ret
;
}
cs
&=
~
(
BCM2835_SPI_CS_CPOL
|
BCM2835_SPI_CS_CPHA
);
...
...
@@ -831,19 +908,19 @@ static int bcm2835_spi_prepare_message(struct spi_master *master,
return
0
;
}
static
void
bcm2835_spi_handle_err
(
struct
spi_
master
*
maste
r
,
static
void
bcm2835_spi_handle_err
(
struct
spi_
controller
*
ctl
r
,
struct
spi_message
*
msg
)
{
struct
bcm2835_spi
*
bs
=
spi_
master_get_devdata
(
maste
r
);
struct
bcm2835_spi
*
bs
=
spi_
controller_get_devdata
(
ctl
r
);
/* if an error occurred and we have an active dma, then terminate */
if
(
cmpxchg
(
&
bs
->
dma_pending
,
true
,
false
))
{
dmaengine_terminate_sync
(
maste
r
->
dma_tx
);
dmaengine_terminate_sync
(
maste
r
->
dma_rx
);
dmaengine_terminate_sync
(
ctl
r
->
dma_tx
);
dmaengine_terminate_sync
(
ctl
r
->
dma_rx
);
bcm2835_spi_undo_prologue
(
bs
);
}
/* and reset */
bcm2835_spi_reset_hw
(
maste
r
);
bcm2835_spi_reset_hw
(
ctl
r
);
}
static
int
chip_match_name
(
struct
gpio_chip
*
chip
,
void
*
data
)
...
...
@@ -900,85 +977,88 @@ static int bcm2835_spi_setup(struct spi_device *spi)
static
int
bcm2835_spi_probe
(
struct
platform_device
*
pdev
)
{
struct
spi_
master
*
maste
r
;
struct
spi_
controller
*
ctl
r
;
struct
bcm2835_spi
*
bs
;
struct
resource
*
res
;
int
err
;
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
*
bs
));
if
(
!
master
)
{
dev_err
(
&
pdev
->
dev
,
"spi_alloc_master() failed
\n
"
);
ctlr
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
*
bs
));
if
(
!
ctlr
)
return
-
ENOMEM
;
}
platform_set_drvdata
(
pdev
,
maste
r
);
platform_set_drvdata
(
pdev
,
ctl
r
);
maste
r
->
mode_bits
=
BCM2835_SPI_MODE_BITS
;
maste
r
->
bits_per_word_mask
=
SPI_BPW_MASK
(
8
);
maste
r
->
num_chipselect
=
3
;
maste
r
->
setup
=
bcm2835_spi_setup
;
maste
r
->
transfer_one
=
bcm2835_spi_transfer_one
;
maste
r
->
handle_err
=
bcm2835_spi_handle_err
;
maste
r
->
prepare_message
=
bcm2835_spi_prepare_message
;
maste
r
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
ctl
r
->
mode_bits
=
BCM2835_SPI_MODE_BITS
;
ctl
r
->
bits_per_word_mask
=
SPI_BPW_MASK
(
8
);
ctl
r
->
num_chipselect
=
3
;
ctl
r
->
setup
=
bcm2835_spi_setup
;
ctl
r
->
transfer_one
=
bcm2835_spi_transfer_one
;
ctl
r
->
handle_err
=
bcm2835_spi_handle_err
;
ctl
r
->
prepare_message
=
bcm2835_spi_prepare_message
;
ctl
r
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
bs
=
spi_
master_get_devdata
(
maste
r
);
bs
=
spi_
controller_get_devdata
(
ctl
r
);
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
bs
->
regs
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
if
(
IS_ERR
(
bs
->
regs
))
{
err
=
PTR_ERR
(
bs
->
regs
);
goto
out_
mast
er_put
;
goto
out_
controll
er_put
;
}
bs
->
clk
=
devm_clk_get
(
&
pdev
->
dev
,
NULL
);
if
(
IS_ERR
(
bs
->
clk
))
{
err
=
PTR_ERR
(
bs
->
clk
);
dev_err
(
&
pdev
->
dev
,
"could not get clk: %d
\n
"
,
err
);
goto
out_
mast
er_put
;
goto
out_
controll
er_put
;
}
bs
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
bs
->
irq
<=
0
)
{
dev_err
(
&
pdev
->
dev
,
"could not get IRQ: %d
\n
"
,
bs
->
irq
);
err
=
bs
->
irq
?
bs
->
irq
:
-
ENODEV
;
goto
out_
mast
er_put
;
goto
out_
controll
er_put
;
}
clk_prepare_enable
(
bs
->
clk
);
bcm2835_dma_init
(
maste
r
,
&
pdev
->
dev
);
bcm2835_dma_init
(
ctl
r
,
&
pdev
->
dev
);
/* initialise the hardware with the default polarities */
bcm2835_wr
(
bs
,
BCM2835_SPI_CS
,
BCM2835_SPI_CS_CLEAR_RX
|
BCM2835_SPI_CS_CLEAR_TX
);
err
=
devm_request_irq
(
&
pdev
->
dev
,
bs
->
irq
,
bcm2835_spi_interrupt
,
0
,
dev_name
(
&
pdev
->
dev
),
maste
r
);
dev_name
(
&
pdev
->
dev
),
ctl
r
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"could not request IRQ: %d
\n
"
,
err
);
goto
out_clk_disable
;
}
err
=
devm_spi_register_
master
(
&
pdev
->
dev
,
maste
r
);
err
=
devm_spi_register_
controller
(
&
pdev
->
dev
,
ctl
r
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"could not register SPI master: %d
\n
"
,
err
);
dev_err
(
&
pdev
->
dev
,
"could not register SPI controller: %d
\n
"
,
err
);
goto
out_clk_disable
;
}
bcm2835_debugfs_create
(
bs
,
dev_name
(
&
pdev
->
dev
));
return
0
;
out_clk_disable:
clk_disable_unprepare
(
bs
->
clk
);
out_
mast
er_put:
spi_
master_put
(
maste
r
);
out_
controll
er_put:
spi_
controller_put
(
ctl
r
);
return
err
;
}
static
int
bcm2835_spi_remove
(
struct
platform_device
*
pdev
)
{
struct
spi_master
*
master
=
platform_get_drvdata
(
pdev
);
struct
bcm2835_spi
*
bs
=
spi_master_get_devdata
(
master
);
struct
spi_controller
*
ctlr
=
platform_get_drvdata
(
pdev
);
struct
bcm2835_spi
*
bs
=
spi_controller_get_devdata
(
ctlr
);
bcm2835_debugfs_remove
(
bs
);
/* Clear FIFOs, and disable the HW block */
bcm2835_wr
(
bs
,
BCM2835_SPI_CS
,
...
...
@@ -986,7 +1066,7 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
clk_disable_unprepare
(
bs
->
clk
);
bcm2835_dma_release
(
maste
r
);
bcm2835_dma_release
(
ctl
r
);
return
0
;
}
...
...
drivers/spi/spi-bcm2835aux.c
View file @
106dbe24
...
...
@@ -496,10 +496,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
int
err
;
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
*
bs
));
if
(
!
master
)
{
dev_err
(
&
pdev
->
dev
,
"spi_alloc_master() failed
\n
"
);
if
(
!
master
)
return
-
ENOMEM
;
}
platform_set_drvdata
(
pdev
,
master
);
master
->
mode_bits
=
(
SPI_CPOL
|
SPI_CS_HIGH
|
SPI_NO_CS
);
...
...
drivers/spi/spi-meson-spifc.c
View file @
106dbe24
// SPDX-License-Identifier: GPL-2.0
-only
/
*
*
Driver for Amlogic Meson SPI flash controller (SPIFC)
*
*
Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
*
/
// SPDX-License-Identifier: GPL-2.0
+
/
/
//
Driver for Amlogic Meson SPI flash controller (SPIFC)
//
//
Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
/
/
#include <linux/clk.h>
#include <linux/delay.h>
...
...
drivers/spi/spi-mt65xx.c
View file @
106dbe24
...
...
@@ -123,8 +123,6 @@ static const struct mtk_spi_compatible mt8183_compat = {
* supplies it.
*/
static
const
struct
mtk_chip_config
mtk_default_chip_info
=
{
.
rx_mlsb
=
1
,
.
tx_mlsb
=
1
,
.
cs_pol
=
0
,
.
sample_sel
=
0
,
};
...
...
@@ -195,14 +193,13 @@ static int mtk_spi_prepare_message(struct spi_master *master,
reg_val
&=
~
SPI_CMD_CPOL
;
/* set the mlsbx and mlsbtx */
if
(
chip_config
->
tx_mlsb
)
reg_val
|=
SPI_CMD_TXMSBF
;
else
if
(
spi
->
mode
&
SPI_LSB_FIRST
)
{
reg_val
&=
~
SPI_CMD_TXMSBF
;
if
(
chip_config
->
rx_mlsb
)
reg_val
|=
SPI_CMD_RXMSBF
;
else
reg_val
&=
~
SPI_CMD_RXMSBF
;
}
else
{
reg_val
|=
SPI_CMD_TXMSBF
;
reg_val
|=
SPI_CMD_RXMSBF
;
}
/* set the tx/rx endian */
#ifdef __LITTLE_ENDIAN
...
...
@@ -599,7 +596,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
master
->
auto_runtime_pm
=
true
;
master
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_LSB_FIRST
;
master
->
set_cs
=
mtk_spi_set_cs
;
master
->
prepare_message
=
mtk_spi_prepare_message
;
...
...
drivers/spi/spi-pxa2xx.c
View file @
106dbe24
...
...
@@ -1437,6 +1437,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
{
PCI_VDEVICE
(
INTEL
,
0x34aa
),
LPSS_CNL_SSP
},
{
PCI_VDEVICE
(
INTEL
,
0x34ab
),
LPSS_CNL_SSP
},
{
PCI_VDEVICE
(
INTEL
,
0x34fb
),
LPSS_CNL_SSP
},
/* EHL */
{
PCI_VDEVICE
(
INTEL
,
0x4b2a
),
LPSS_BXT_SSP
},
{
PCI_VDEVICE
(
INTEL
,
0x4b2b
),
LPSS_BXT_SSP
},
{
PCI_VDEVICE
(
INTEL
,
0x4b37
),
LPSS_BXT_SSP
},
/* APL */
{
PCI_VDEVICE
(
INTEL
,
0x5ac2
),
LPSS_BXT_SSP
},
{
PCI_VDEVICE
(
INTEL
,
0x5ac4
),
LPSS_BXT_SSP
},
...
...
@@ -1704,6 +1708,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
goto
out_error_dma_irq_alloc
;
controller
->
max_speed_hz
=
clk_get_rate
(
ssp
->
clk
);
/*
* Set minimum speed for all other platforms than Intel Quark which is
* able do under 1 Hz transfers.
*/
if
(
!
pxa25x_ssp_comp
(
drv_data
))
controller
->
min_speed_hz
=
DIV_ROUND_UP
(
controller
->
max_speed_hz
,
4096
);
else
if
(
!
is_quark_x1000_ssp
(
drv_data
))
controller
->
min_speed_hz
=
DIV_ROUND_UP
(
controller
->
max_speed_hz
,
512
);
/* Load default SSP configuration */
pxa2xx_spi_write
(
drv_data
,
SSCR0
,
0
);
...
...
drivers/spi/spi-qup.c
View file @
106dbe24
...
...
@@ -873,10 +873,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
else
ret
=
spi_qup_do_pio
(
spi
,
xfer
,
timeout
);
if
(
ret
)
goto
exit
;
exit:
spi_qup_set_state
(
controller
,
QUP_STATE_RESET
);
spin_lock_irqsave
(
&
controller
->
lock
,
flags
);
if
(
!
ret
)
...
...
drivers/spi/spi-rockchip.c
View file @
106dbe24
...
...
@@ -417,7 +417,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
.
direction
=
DMA_MEM_TO_DEV
,
.
dst_addr
=
rs
->
dma_addr_tx
,
.
dst_addr_width
=
rs
->
n_bytes
,
.
dst_maxburst
=
rs
->
fifo_len
/
2
,
.
dst_maxburst
=
rs
->
fifo_len
/
4
,
};
dmaengine_slave_config
(
master
->
dma_tx
,
&
txconf
);
...
...
@@ -518,7 +518,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else
writel_relaxed
(
rs
->
fifo_len
/
2
-
1
,
rs
->
regs
+
ROCKCHIP_SPI_RXFTLR
);
writel_relaxed
(
rs
->
fifo_len
/
2
-
1
,
rs
->
regs
+
ROCKCHIP_SPI_DMATDLR
);
writel_relaxed
(
rs
->
fifo_len
/
2
,
rs
->
regs
+
ROCKCHIP_SPI_DMATDLR
);
writel_relaxed
(
0
,
rs
->
regs
+
ROCKCHIP_SPI_DMARDLR
);
writel_relaxed
(
dmacr
,
rs
->
regs
+
ROCKCHIP_SPI_DMACR
);
...
...
drivers/spi/spi-sh-msiof.c
View file @
106dbe24
...
...
@@ -229,7 +229,7 @@ static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p,
sh_msiof_write
(
p
,
CTR
,
data
);
return
readl_poll_timeout_atomic
(
p
->
mapbase
+
CTR
,
data
,
(
data
&
mask
)
==
set
,
1
0
,
10
00
);
(
data
&
mask
)
==
set
,
1
,
1
00
);
}
static
irqreturn_t
sh_msiof_spi_irq
(
int
irq
,
void
*
data
)
...
...
drivers/spi/spi-stm32-qspi.c
View file @
106dbe24
...
...
@@ -245,12 +245,8 @@ static int stm32_qspi_tx_dma(struct stm32_qspi *qspi,
writel_relaxed
(
cr
|
CR_DMAEN
,
qspi
->
io_base
+
QSPI_CR
);
t_out
=
sgt
.
nents
*
STM32_COMP_TIMEOUT_MS
;
if
(
!
wait_for_completion_interruptible_timeout
(
&
qspi
->
dma_completion
,
msecs_to_jiffies
(
t_out
)))
err
=
-
ETIMEDOUT
;
if
(
dma_async_is_tx_complete
(
dma_ch
,
cookie
,
NULL
,
NULL
)
!=
DMA_COMPLETE
)
if
(
!
wait_for_completion_timeout
(
&
qspi
->
dma_completion
,
msecs_to_jiffies
(
t_out
)))
err
=
-
ETIMEDOUT
;
if
(
err
)
...
...
@@ -304,7 +300,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi,
cr
=
readl_relaxed
(
qspi
->
io_base
+
QSPI_CR
);
writel_relaxed
(
cr
|
CR_TCIE
|
CR_TEIE
,
qspi
->
io_base
+
QSPI_CR
);
if
(
!
wait_for_completion_
interruptible_
timeout
(
&
qspi
->
data_completion
,
if
(
!
wait_for_completion_timeout
(
&
qspi
->
data_completion
,
msecs_to_jiffies
(
STM32_COMP_TIMEOUT_MS
)))
{
err
=
-
ETIMEDOUT
;
}
else
{
...
...
drivers/spi/spi-synquacer.c
0 → 100644
View file @
106dbe24
// SPDX-License-Identifier: GPL-2.0
//
// Synquacer HSSPI controller driver
//
// Copyright (c) 2015-2018 Socionext Inc.
// Copyright (c) 2018-2019 Linaro Ltd.
//
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
/* HSSPI register address definitions */
#define SYNQUACER_HSSPI_REG_MCTRL 0x00
#define SYNQUACER_HSSPI_REG_PCC0 0x04
#define SYNQUACER_HSSPI_REG_PCC(n) (SYNQUACER_HSSPI_REG_PCC0 + (n) * 4)
#define SYNQUACER_HSSPI_REG_TXF 0x14
#define SYNQUACER_HSSPI_REG_TXE 0x18
#define SYNQUACER_HSSPI_REG_TXC 0x1C
#define SYNQUACER_HSSPI_REG_RXF 0x20
#define SYNQUACER_HSSPI_REG_RXE 0x24
#define SYNQUACER_HSSPI_REG_RXC 0x28
#define SYNQUACER_HSSPI_REG_FAULTF 0x2C
#define SYNQUACER_HSSPI_REG_FAULTC 0x30
#define SYNQUACER_HSSPI_REG_DMCFG 0x34
#define SYNQUACER_HSSPI_REG_DMSTART 0x38
#define SYNQUACER_HSSPI_REG_DMBCC 0x3C
#define SYNQUACER_HSSPI_REG_DMSTATUS 0x40
#define SYNQUACER_HSSPI_REG_FIFOCFG 0x4C
#define SYNQUACER_HSSPI_REG_TX_FIFO 0x50
#define SYNQUACER_HSSPI_REG_RX_FIFO 0x90
#define SYNQUACER_HSSPI_REG_MID 0xFC
/* HSSPI register bit definitions */
#define SYNQUACER_HSSPI_MCTRL_MEN BIT(0)
#define SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN BIT(1)
#define SYNQUACER_HSSPI_MCTRL_CDSS BIT(3)
#define SYNQUACER_HSSPI_MCTRL_MES BIT(4)
#define SYNQUACER_HSSPI_MCTRL_SYNCON BIT(5)
#define SYNQUACER_HSSPI_PCC_CPHA BIT(0)
#define SYNQUACER_HSSPI_PCC_CPOL BIT(1)
#define SYNQUACER_HSSPI_PCC_ACES BIT(2)
#define SYNQUACER_HSSPI_PCC_RTM BIT(3)
#define SYNQUACER_HSSPI_PCC_SSPOL BIT(4)
#define SYNQUACER_HSSPI_PCC_SDIR BIT(7)
#define SYNQUACER_HSSPI_PCC_SENDIAN BIT(8)
#define SYNQUACER_HSSPI_PCC_SAFESYNC BIT(16)
#define SYNQUACER_HSSPI_PCC_SS2CD_SHIFT 5U
#define SYNQUACER_HSSPI_PCC_CDRS_MASK 0x7f
#define SYNQUACER_HSSPI_PCC_CDRS_SHIFT 9U
#define SYNQUACER_HSSPI_TXF_FIFO_FULL BIT(0)
#define SYNQUACER_HSSPI_TXF_FIFO_EMPTY BIT(1)
#define SYNQUACER_HSSPI_TXF_SLAVE_RELEASED BIT(6)
#define SYNQUACER_HSSPI_TXE_FIFO_FULL BIT(0)
#define SYNQUACER_HSSPI_TXE_FIFO_EMPTY BIT(1)
#define SYNQUACER_HSSPI_TXE_SLAVE_RELEASED BIT(6)
#define SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD BIT(5)
#define SYNQUACER_HSSPI_RXF_SLAVE_RELEASED BIT(6)
#define SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD BIT(5)
#define SYNQUACER_HSSPI_RXE_SLAVE_RELEASED BIT(6)
#define SYNQUACER_HSSPI_DMCFG_SSDC BIT(1)
#define SYNQUACER_HSSPI_DMCFG_MSTARTEN BIT(2)
#define SYNQUACER_HSSPI_DMSTART_START BIT(0)
#define SYNQUACER_HSSPI_DMSTOP_STOP BIT(8)
#define SYNQUACER_HSSPI_DMPSEL_CS_MASK 0x3
#define SYNQUACER_HSSPI_DMPSEL_CS_SHIFT 16U
#define SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT 24U
#define SYNQUACER_HSSPI_DMTRP_DATA_MASK 0x3
#define SYNQUACER_HSSPI_DMTRP_DATA_SHIFT 26U
#define SYNQUACER_HSSPI_DMTRP_DATA_TXRX 0
#define SYNQUACER_HSSPI_DMTRP_DATA_RX 1
#define SYNQUACER_HSSPI_DMTRP_DATA_TX 2
#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK 0x1f
#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT 8U
#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK 0x1f
#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT 16U
#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK 0xf
#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT 0U
#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_MASK 0xf
#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_SHIFT 4U
#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK 0x3
#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT 8U
#define SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH BIT(11)
#define SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH BIT(12)
#define SYNQUACER_HSSPI_FIFO_DEPTH 16U
#define SYNQUACER_HSSPI_FIFO_TX_THRESHOLD 4U
#define SYNQUACER_HSSPI_FIFO_RX_THRESHOLD \
(SYNQUACER_HSSPI_FIFO_DEPTH - SYNQUACER_HSSPI_FIFO_TX_THRESHOLD)
#define SYNQUACER_HSSPI_TRANSFER_MODE_TX BIT(1)
#define SYNQUACER_HSSPI_TRANSFER_MODE_RX BIT(2)
#define SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC 2000U
#define SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC 1000U
#define SYNQUACER_HSSPI_CLOCK_SRC_IHCLK 0
#define SYNQUACER_HSSPI_CLOCK_SRC_IPCLK 1
#define SYNQUACER_HSSPI_NUM_CHIP_SELECT 4U
#define SYNQUACER_HSSPI_IRQ_NAME_MAX 32U
struct
synquacer_spi
{
struct
device
*
dev
;
struct
completion
transfer_done
;
unsigned
int
cs
;
unsigned
int
bpw
;
unsigned
int
mode
;
unsigned
int
speed
;
bool
aces
,
rtm
;
void
*
rx_buf
;
const
void
*
tx_buf
;
struct
clk
*
clk
;
int
clk_src_type
;
void
__iomem
*
regs
;
u32
tx_words
,
rx_words
;
unsigned
int
bus_width
;
unsigned
int
transfer_mode
;
char
rx_irq_name
[
SYNQUACER_HSSPI_IRQ_NAME_MAX
];
char
tx_irq_name
[
SYNQUACER_HSSPI_IRQ_NAME_MAX
];
};
static
int
read_fifo
(
struct
synquacer_spi
*
sspi
)
{
u32
len
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTATUS
);
len
=
(
len
>>
SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT
)
&
SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK
;
len
=
min
(
len
,
sspi
->
rx_words
);
switch
(
sspi
->
bpw
)
{
case
8
:
{
u8
*
buf
=
sspi
->
rx_buf
;
ioread8_rep
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RX_FIFO
,
buf
,
len
);
sspi
->
rx_buf
=
buf
+
len
;
break
;
}
case
16
:
{
u16
*
buf
=
sspi
->
rx_buf
;
ioread16_rep
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RX_FIFO
,
buf
,
len
);
sspi
->
rx_buf
=
buf
+
len
;
break
;
}
case
24
:
/* fallthrough, should use 32-bits access */
case
32
:
{
u32
*
buf
=
sspi
->
rx_buf
;
ioread32_rep
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RX_FIFO
,
buf
,
len
);
sspi
->
rx_buf
=
buf
+
len
;
break
;
}
default:
return
-
EINVAL
;
}
sspi
->
rx_words
-=
len
;
return
0
;
}
static
int
write_fifo
(
struct
synquacer_spi
*
sspi
)
{
u32
len
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTATUS
);
len
=
(
len
>>
SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT
)
&
SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK
;
len
=
min
(
SYNQUACER_HSSPI_FIFO_DEPTH
-
len
,
sspi
->
tx_words
);
switch
(
sspi
->
bpw
)
{
case
8
:
{
const
u8
*
buf
=
sspi
->
tx_buf
;
iowrite8_rep
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TX_FIFO
,
buf
,
len
);
sspi
->
tx_buf
=
buf
+
len
;
break
;
}
case
16
:
{
const
u16
*
buf
=
sspi
->
tx_buf
;
iowrite16_rep
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TX_FIFO
,
buf
,
len
);
sspi
->
tx_buf
=
buf
+
len
;
break
;
}
case
24
:
/* fallthrough, should use 32-bits access */
case
32
:
{
const
u32
*
buf
=
sspi
->
tx_buf
;
iowrite32_rep
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TX_FIFO
,
buf
,
len
);
sspi
->
tx_buf
=
buf
+
len
;
break
;
}
default:
return
-
EINVAL
;
}
sspi
->
tx_words
-=
len
;
return
0
;
}
static
int
synquacer_spi_config
(
struct
spi_master
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
struct
synquacer_spi
*
sspi
=
spi_master_get_devdata
(
master
);
unsigned
int
speed
,
mode
,
bpw
,
cs
,
bus_width
,
transfer_mode
;
u32
rate
,
val
,
div
;
/* Full Duplex only on 1-bit wide bus */
if
(
xfer
->
rx_buf
&&
xfer
->
tx_buf
&&
(
xfer
->
rx_nbits
!=
1
||
xfer
->
tx_nbits
!=
1
))
{
dev_err
(
sspi
->
dev
,
"RX and TX bus widths must be 1-bit for Full-Duplex!
\n
"
);
return
-
EINVAL
;
}
if
(
xfer
->
tx_buf
)
{
bus_width
=
xfer
->
tx_nbits
;
transfer_mode
=
SYNQUACER_HSSPI_TRANSFER_MODE_TX
;
}
else
{
bus_width
=
xfer
->
rx_nbits
;
transfer_mode
=
SYNQUACER_HSSPI_TRANSFER_MODE_RX
;
}
mode
=
spi
->
mode
;
cs
=
spi
->
chip_select
;
speed
=
xfer
->
speed_hz
;
bpw
=
xfer
->
bits_per_word
;
/* return if nothing to change */
if
(
speed
==
sspi
->
speed
&&
bus_width
==
sspi
->
bus_width
&&
bpw
==
sspi
->
bpw
&&
mode
==
sspi
->
mode
&&
cs
==
sspi
->
cs
&&
transfer_mode
==
sspi
->
transfer_mode
)
{
return
0
;
}
sspi
->
transfer_mode
=
transfer_mode
;
rate
=
master
->
max_speed_hz
;
div
=
DIV_ROUND_UP
(
rate
,
speed
);
if
(
div
>
254
)
{
dev_err
(
sspi
->
dev
,
"Requested rate too low (%u)
\n
"
,
sspi
->
speed
);
return
-
EINVAL
;
}
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_PCC
(
cs
));
val
&=
~
SYNQUACER_HSSPI_PCC_SAFESYNC
;
if
(
bpw
==
8
&&
(
mode
&
(
SPI_TX_DUAL
|
SPI_RX_DUAL
))
&&
div
<
3
)
val
|=
SYNQUACER_HSSPI_PCC_SAFESYNC
;
if
(
bpw
==
8
&&
(
mode
&
(
SPI_TX_QUAD
|
SPI_RX_QUAD
))
&&
div
<
6
)
val
|=
SYNQUACER_HSSPI_PCC_SAFESYNC
;
if
(
bpw
==
16
&&
(
mode
&
(
SPI_TX_QUAD
|
SPI_RX_QUAD
))
&&
div
<
3
)
val
|=
SYNQUACER_HSSPI_PCC_SAFESYNC
;
if
(
mode
&
SPI_CPHA
)
val
|=
SYNQUACER_HSSPI_PCC_CPHA
;
else
val
&=
~
SYNQUACER_HSSPI_PCC_CPHA
;
if
(
mode
&
SPI_CPOL
)
val
|=
SYNQUACER_HSSPI_PCC_CPOL
;
else
val
&=
~
SYNQUACER_HSSPI_PCC_CPOL
;
if
(
mode
&
SPI_CS_HIGH
)
val
|=
SYNQUACER_HSSPI_PCC_SSPOL
;
else
val
&=
~
SYNQUACER_HSSPI_PCC_SSPOL
;
if
(
mode
&
SPI_LSB_FIRST
)
val
|=
SYNQUACER_HSSPI_PCC_SDIR
;
else
val
&=
~
SYNQUACER_HSSPI_PCC_SDIR
;
if
(
sspi
->
aces
)
val
|=
SYNQUACER_HSSPI_PCC_ACES
;
else
val
&=
~
SYNQUACER_HSSPI_PCC_ACES
;
if
(
sspi
->
rtm
)
val
|=
SYNQUACER_HSSPI_PCC_RTM
;
else
val
&=
~
SYNQUACER_HSSPI_PCC_RTM
;
val
|=
(
3
<<
SYNQUACER_HSSPI_PCC_SS2CD_SHIFT
);
val
|=
SYNQUACER_HSSPI_PCC_SENDIAN
;
val
&=
~
(
SYNQUACER_HSSPI_PCC_CDRS_MASK
<<
SYNQUACER_HSSPI_PCC_CDRS_SHIFT
);
val
|=
((
div
>>
1
)
<<
SYNQUACER_HSSPI_PCC_CDRS_SHIFT
);
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_PCC
(
cs
));
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_FIFOCFG
);
val
&=
~
(
SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK
<<
SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT
);
val
|=
((
bpw
/
8
-
1
)
<<
SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT
);
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_FIFOCFG
);
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
val
&=
~
(
SYNQUACER_HSSPI_DMTRP_DATA_MASK
<<
SYNQUACER_HSSPI_DMTRP_DATA_SHIFT
);
if
(
xfer
->
rx_buf
)
val
|=
(
SYNQUACER_HSSPI_DMTRP_DATA_RX
<<
SYNQUACER_HSSPI_DMTRP_DATA_SHIFT
);
else
val
|=
(
SYNQUACER_HSSPI_DMTRP_DATA_TX
<<
SYNQUACER_HSSPI_DMTRP_DATA_SHIFT
);
val
&=
~
(
3
<<
SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT
);
val
|=
((
bus_width
>>
1
)
<<
SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT
);
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
sspi
->
bpw
=
bpw
;
sspi
->
mode
=
mode
;
sspi
->
speed
=
speed
;
sspi
->
cs
=
spi
->
chip_select
;
sspi
->
bus_width
=
bus_width
;
return
0
;
}
static
int
synquacer_spi_transfer_one
(
struct
spi_master
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
struct
synquacer_spi
*
sspi
=
spi_master_get_devdata
(
master
);
int
ret
;
int
status
=
0
;
u32
words
;
u8
bpw
;
u32
val
;
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
val
&=
~
SYNQUACER_HSSPI_DMSTOP_STOP
;
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_FIFOCFG
);
val
|=
SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH
;
val
|=
SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH
;
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_FIFOCFG
);
/*
* See if we can transfer 4-bytes as 1 word
* to maximize the FIFO buffer efficiency.
*/
bpw
=
xfer
->
bits_per_word
;
if
(
bpw
==
8
&&
!
(
xfer
->
len
%
4
)
&&
!
(
spi
->
mode
&
SPI_LSB_FIRST
))
xfer
->
bits_per_word
=
32
;
ret
=
synquacer_spi_config
(
master
,
spi
,
xfer
);
/* restore */
xfer
->
bits_per_word
=
bpw
;
if
(
ret
)
return
ret
;
reinit_completion
(
&
sspi
->
transfer_done
);
sspi
->
tx_buf
=
xfer
->
tx_buf
;
sspi
->
rx_buf
=
xfer
->
rx_buf
;
switch
(
sspi
->
bpw
)
{
case
8
:
words
=
xfer
->
len
;
break
;
case
16
:
words
=
xfer
->
len
/
2
;
break
;
case
24
:
/* fallthrough, should use 32-bits access */
case
32
:
words
=
xfer
->
len
/
4
;
break
;
default:
dev_err
(
sspi
->
dev
,
"unsupported bpw: %d
\n
"
,
sspi
->
bpw
);
return
-
EINVAL
;
}
if
(
xfer
->
tx_buf
)
sspi
->
tx_words
=
words
;
else
sspi
->
tx_words
=
0
;
if
(
xfer
->
rx_buf
)
sspi
->
rx_words
=
words
;
else
sspi
->
rx_words
=
0
;
if
(
xfer
->
tx_buf
)
{
status
=
write_fifo
(
sspi
);
if
(
status
<
0
)
{
dev_err
(
sspi
->
dev
,
"failed write_fifo. status: 0x%x
\n
"
,
status
);
return
status
;
}
}
if
(
xfer
->
rx_buf
)
{
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_FIFOCFG
);
val
&=
~
(
SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK
<<
SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT
);
val
|=
((
sspi
->
rx_words
>
SYNQUACER_HSSPI_FIFO_DEPTH
?
SYNQUACER_HSSPI_FIFO_RX_THRESHOLD
:
sspi
->
rx_words
)
<<
SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT
);
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_FIFOCFG
);
}
writel
(
~
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TXC
);
writel
(
~
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RXC
);
/* Trigger */
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
val
|=
SYNQUACER_HSSPI_DMSTART_START
;
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
if
(
xfer
->
tx_buf
)
{
val
=
SYNQUACER_HSSPI_TXE_FIFO_EMPTY
;
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TXE
);
status
=
wait_for_completion_timeout
(
&
sspi
->
transfer_done
,
msecs_to_jiffies
(
SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC
));
writel
(
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TXE
);
}
if
(
xfer
->
rx_buf
)
{
u32
buf
[
SYNQUACER_HSSPI_FIFO_DEPTH
];
val
=
SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD
|
SYNQUACER_HSSPI_RXE_SLAVE_RELEASED
;
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RXE
);
status
=
wait_for_completion_timeout
(
&
sspi
->
transfer_done
,
msecs_to_jiffies
(
SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC
));
writel
(
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RXE
);
/* stop RX and clean RXFIFO */
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
val
|=
SYNQUACER_HSSPI_DMSTOP_STOP
;
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
sspi
->
rx_buf
=
buf
;
sspi
->
rx_words
=
SYNQUACER_HSSPI_FIFO_DEPTH
;
read_fifo
(
sspi
);
}
if
(
status
<
0
)
{
dev_err
(
sspi
->
dev
,
"failed to transfer. status: 0x%x
\n
"
,
status
);
return
status
;
}
return
0
;
}
static
void
synquacer_spi_set_cs
(
struct
spi_device
*
spi
,
bool
enable
)
{
struct
synquacer_spi
*
sspi
=
spi_master_get_devdata
(
spi
->
master
);
u32
val
;
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
val
&=
~
(
SYNQUACER_HSSPI_DMPSEL_CS_MASK
<<
SYNQUACER_HSSPI_DMPSEL_CS_SHIFT
);
val
|=
spi
->
chip_select
<<
SYNQUACER_HSSPI_DMPSEL_CS_SHIFT
;
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMSTART
);
}
static
int
synquacer_spi_wait_status_update
(
struct
synquacer_spi
*
sspi
,
bool
enable
)
{
u32
val
;
unsigned
long
timeout
=
jiffies
+
msecs_to_jiffies
(
SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC
);
/* wait MES(Module Enable Status) is updated */
do
{
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_MCTRL
)
&
SYNQUACER_HSSPI_MCTRL_MES
;
if
(
enable
&&
val
)
return
0
;
if
(
!
enable
&&
!
val
)
return
0
;
}
while
(
time_before
(
jiffies
,
timeout
));
dev_err
(
sspi
->
dev
,
"timeout occurs in updating Module Enable Status
\n
"
);
return
-
EBUSY
;
}
static
int
synquacer_spi_enable
(
struct
spi_master
*
master
)
{
u32
val
;
int
status
;
struct
synquacer_spi
*
sspi
=
spi_master_get_devdata
(
master
);
/* Disable module */
writel
(
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_MCTRL
);
status
=
synquacer_spi_wait_status_update
(
sspi
,
false
);
if
(
status
<
0
)
return
status
;
writel
(
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TXE
);
writel
(
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RXE
);
writel
(
~
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TXC
);
writel
(
~
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RXC
);
writel
(
~
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_FAULTC
);
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMCFG
);
val
&=
~
SYNQUACER_HSSPI_DMCFG_SSDC
;
val
&=
~
SYNQUACER_HSSPI_DMCFG_MSTARTEN
;
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_DMCFG
);
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_MCTRL
);
if
(
sspi
->
clk_src_type
==
SYNQUACER_HSSPI_CLOCK_SRC_IPCLK
)
val
|=
SYNQUACER_HSSPI_MCTRL_CDSS
;
else
val
&=
~
SYNQUACER_HSSPI_MCTRL_CDSS
;
val
&=
~
SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN
;
val
|=
SYNQUACER_HSSPI_MCTRL_MEN
;
val
|=
SYNQUACER_HSSPI_MCTRL_SYNCON
;
/* Enable module */
writel
(
val
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_MCTRL
);
status
=
synquacer_spi_wait_status_update
(
sspi
,
true
);
if
(
status
<
0
)
return
status
;
return
0
;
}
static
irqreturn_t
sq_spi_rx_handler
(
int
irq
,
void
*
priv
)
{
uint32_t
val
;
struct
synquacer_spi
*
sspi
=
priv
;
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RXF
);
if
((
val
&
SYNQUACER_HSSPI_RXF_SLAVE_RELEASED
)
||
(
val
&
SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD
))
{
read_fifo
(
sspi
);
if
(
sspi
->
rx_words
==
0
)
{
writel
(
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_RXE
);
complete
(
&
sspi
->
transfer_done
);
}
return
IRQ_HANDLED
;
}
return
IRQ_NONE
;
}
static
irqreturn_t
sq_spi_tx_handler
(
int
irq
,
void
*
priv
)
{
uint32_t
val
;
struct
synquacer_spi
*
sspi
=
priv
;
val
=
readl
(
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TXF
);
if
(
val
&
SYNQUACER_HSSPI_TXF_FIFO_EMPTY
)
{
if
(
sspi
->
tx_words
==
0
)
{
writel
(
0
,
sspi
->
regs
+
SYNQUACER_HSSPI_REG_TXE
);
complete
(
&
sspi
->
transfer_done
);
}
else
{
write_fifo
(
sspi
);
}
return
IRQ_HANDLED
;
}
return
IRQ_NONE
;
}
static
int
synquacer_spi_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
spi_master
*
master
;
struct
synquacer_spi
*
sspi
;
int
ret
;
int
rx_irq
,
tx_irq
;
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
*
sspi
));
if
(
!
master
)
return
-
ENOMEM
;
platform_set_drvdata
(
pdev
,
master
);
sspi
=
spi_master_get_devdata
(
master
);
sspi
->
dev
=
&
pdev
->
dev
;
init_completion
(
&
sspi
->
transfer_done
);
sspi
->
regs
=
devm_platform_ioremap_resource
(
pdev
,
0
);
if
(
IS_ERR
(
sspi
->
regs
))
{
ret
=
PTR_ERR
(
sspi
->
regs
);
goto
put_spi
;
}
sspi
->
clk_src_type
=
SYNQUACER_HSSPI_CLOCK_SRC_IHCLK
;
/* Default */
device_property_read_u32
(
&
pdev
->
dev
,
"socionext,ihclk-rate"
,
&
master
->
max_speed_hz
);
/* for ACPI */
if
(
dev_of_node
(
&
pdev
->
dev
))
{
if
(
device_property_match_string
(
&
pdev
->
dev
,
"clock-names"
,
"iHCLK"
)
>=
0
)
{
sspi
->
clk_src_type
=
SYNQUACER_HSSPI_CLOCK_SRC_IHCLK
;
sspi
->
clk
=
devm_clk_get
(
sspi
->
dev
,
"iHCLK"
);
}
else
if
(
device_property_match_string
(
&
pdev
->
dev
,
"clock-names"
,
"iPCLK"
)
>=
0
)
{
sspi
->
clk_src_type
=
SYNQUACER_HSSPI_CLOCK_SRC_IPCLK
;
sspi
->
clk
=
devm_clk_get
(
sspi
->
dev
,
"iPCLK"
);
}
else
{
dev_err
(
&
pdev
->
dev
,
"specified wrong clock source
\n
"
);
ret
=
-
EINVAL
;
goto
put_spi
;
}
if
(
IS_ERR
(
sspi
->
clk
))
{
if
(
!
(
PTR_ERR
(
sspi
->
clk
)
==
-
EPROBE_DEFER
))
dev_err
(
&
pdev
->
dev
,
"clock not found
\n
"
);
ret
=
PTR_ERR
(
sspi
->
clk
);
goto
put_spi
;
}
ret
=
clk_prepare_enable
(
sspi
->
clk
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to enable clock (%d)
\n
"
,
ret
);
goto
put_spi
;
}
master
->
max_speed_hz
=
clk_get_rate
(
sspi
->
clk
);
}
if
(
!
master
->
max_speed_hz
)
{
dev_err
(
&
pdev
->
dev
,
"missing clock source
\n
"
);
return
-
EINVAL
;
}
master
->
min_speed_hz
=
master
->
max_speed_hz
/
254
;
sspi
->
aces
=
device_property_read_bool
(
&
pdev
->
dev
,
"socionext,set-aces"
);
sspi
->
rtm
=
device_property_read_bool
(
&
pdev
->
dev
,
"socionext,use-rtm"
);
master
->
num_chipselect
=
SYNQUACER_HSSPI_NUM_CHIP_SELECT
;
rx_irq
=
platform_get_irq
(
pdev
,
0
);
if
(
rx_irq
<=
0
)
{
dev_err
(
&
pdev
->
dev
,
"get rx_irq failed (%d)
\n
"
,
rx_irq
);
ret
=
rx_irq
;
goto
put_spi
;
}
snprintf
(
sspi
->
rx_irq_name
,
SYNQUACER_HSSPI_IRQ_NAME_MAX
,
"%s-rx"
,
dev_name
(
&
pdev
->
dev
));
ret
=
devm_request_irq
(
&
pdev
->
dev
,
rx_irq
,
sq_spi_rx_handler
,
0
,
sspi
->
rx_irq_name
,
sspi
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"request rx_irq failed (%d)
\n
"
,
ret
);
goto
put_spi
;
}
tx_irq
=
platform_get_irq
(
pdev
,
1
);
if
(
tx_irq
<=
0
)
{
dev_err
(
&
pdev
->
dev
,
"get tx_irq failed (%d)
\n
"
,
tx_irq
);
ret
=
tx_irq
;
goto
put_spi
;
}
snprintf
(
sspi
->
tx_irq_name
,
SYNQUACER_HSSPI_IRQ_NAME_MAX
,
"%s-tx"
,
dev_name
(
&
pdev
->
dev
));
ret
=
devm_request_irq
(
&
pdev
->
dev
,
tx_irq
,
sq_spi_tx_handler
,
0
,
sspi
->
tx_irq_name
,
sspi
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"request tx_irq failed (%d)
\n
"
,
ret
);
goto
put_spi
;
}
master
->
dev
.
of_node
=
np
;
master
->
dev
.
fwnode
=
pdev
->
dev
.
fwnode
;
master
->
auto_runtime_pm
=
true
;
master
->
bus_num
=
pdev
->
id
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_TX_DUAL
|
SPI_RX_DUAL
|
SPI_TX_QUAD
|
SPI_RX_QUAD
;
master
->
bits_per_word_mask
=
SPI_BPW_MASK
(
32
)
|
SPI_BPW_MASK
(
24
)
|
SPI_BPW_MASK
(
16
)
|
SPI_BPW_MASK
(
8
);
master
->
set_cs
=
synquacer_spi_set_cs
;
master
->
transfer_one
=
synquacer_spi_transfer_one
;
ret
=
synquacer_spi_enable
(
master
);
if
(
ret
)
goto
fail_enable
;
pm_runtime_set_active
(
sspi
->
dev
);
pm_runtime_enable
(
sspi
->
dev
);
ret
=
devm_spi_register_master
(
sspi
->
dev
,
master
);
if
(
ret
)
goto
disable_pm
;
return
0
;
disable_pm:
pm_runtime_disable
(
sspi
->
dev
);
fail_enable:
clk_disable_unprepare
(
sspi
->
clk
);
put_spi:
spi_master_put
(
master
);
return
ret
;
}
static
int
synquacer_spi_remove
(
struct
platform_device
*
pdev
)
{
struct
spi_master
*
master
=
platform_get_drvdata
(
pdev
);
struct
synquacer_spi
*
sspi
=
spi_master_get_devdata
(
master
);
pm_runtime_disable
(
sspi
->
dev
);
clk_disable_unprepare
(
sspi
->
clk
);
return
0
;
}
static
int
__maybe_unused
synquacer_spi_suspend
(
struct
device
*
dev
)
{
struct
spi_master
*
master
=
dev_get_drvdata
(
dev
);
struct
synquacer_spi
*
sspi
=
spi_master_get_devdata
(
master
);
int
ret
;
ret
=
spi_master_suspend
(
master
);
if
(
ret
)
return
ret
;
if
(
!
pm_runtime_suspended
(
dev
))
clk_disable_unprepare
(
sspi
->
clk
);
return
ret
;
}
static
int
__maybe_unused
synquacer_spi_resume
(
struct
device
*
dev
)
{
struct
spi_master
*
master
=
dev_get_drvdata
(
dev
);
struct
synquacer_spi
*
sspi
=
spi_master_get_devdata
(
master
);
int
ret
;
if
(
!
pm_runtime_suspended
(
dev
))
{
/* Ensure reconfigure during next xfer */
sspi
->
speed
=
0
;
ret
=
clk_prepare_enable
(
sspi
->
clk
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"failed to enable clk (%d)
\n
"
,
ret
);
return
ret
;
}
ret
=
synquacer_spi_enable
(
master
);
if
(
ret
)
{
dev_err
(
dev
,
"failed to enable spi (%d)
\n
"
,
ret
);
return
ret
;
}
}
ret
=
spi_master_resume
(
master
);
if
(
ret
<
0
)
clk_disable_unprepare
(
sspi
->
clk
);
return
ret
;
}
static
SIMPLE_DEV_PM_OPS
(
synquacer_spi_pm_ops
,
synquacer_spi_suspend
,
synquacer_spi_resume
);
static
const
struct
of_device_id
synquacer_spi_of_match
[]
=
{
{.
compatible
=
"socionext,synquacer-spi"
},
{}
};
MODULE_DEVICE_TABLE
(
of
,
synquacer_spi_of_match
);
#ifdef CONFIG_ACPI
static
const
struct
acpi_device_id
synquacer_hsspi_acpi_ids
[]
=
{
{
"SCX0004"
},
{
/* sentinel */
}
};
MODULE_DEVICE_TABLE
(
acpi
,
synquacer_hsspi_acpi_ids
);
#endif
static
struct
platform_driver
synquacer_spi_driver
=
{
.
driver
=
{
.
name
=
"synquacer-spi"
,
.
pm
=
&
synquacer_spi_pm_ops
,
.
of_match_table
=
synquacer_spi_of_match
,
.
acpi_match_table
=
ACPI_PTR
(
synquacer_hsspi_acpi_ids
),
},
.
probe
=
synquacer_spi_probe
,
.
remove
=
synquacer_spi_remove
,
};
module_platform_driver
(
synquacer_spi_driver
);
MODULE_DESCRIPTION
(
"Socionext Synquacer HS-SPI controller driver"
);
MODULE_AUTHOR
(
"Masahisa Kojima <masahisa.kojima@linaro.org>"
);
MODULE_AUTHOR
(
"Jassi Brar <jaswinder.singh@linaro.org>"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/spi/spi-tegra114.c
View file @
106dbe24
...
...
@@ -84,8 +84,10 @@
(reg = (((val) & 0x1) << ((cs) * 8 + 5)) | \
((reg) & ~(1 << ((cs) * 8 + 5))))
#define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val) \
(reg = (((val) & 0xF) << ((cs) * 8)) | \
((reg) & ~(0xF << ((cs) * 8))))
(reg = (((val) & 0x1F) << ((cs) * 8)) | \
((reg) & ~(0x1F << ((cs) * 8))))
#define MAX_SETUP_HOLD_CYCLES 16
#define MAX_INACTIVE_CYCLES 32
#define SPI_TRANS_STATUS 0x010
#define SPI_BLK_CNT(val) (((val) >> 0) & 0xFFFF)
...
...
@@ -156,6 +158,11 @@ struct tegra_spi_soc_data {
bool
has_intr_mask_reg
;
};
struct
tegra_spi_client_data
{
int
tx_clk_tap_delay
;
int
rx_clk_tap_delay
;
};
struct
tegra_spi_data
{
struct
device
*
dev
;
struct
spi_master
*
master
;
...
...
@@ -182,6 +189,7 @@ struct tegra_spi_data {
unsigned
dma_buf_size
;
unsigned
max_buf_size
;
bool
is_curr_dma_xfer
;
bool
use_hw_based_cs
;
struct
completion
rx_dma_complete
;
struct
completion
tx_dma_complete
;
...
...
@@ -194,6 +202,10 @@ struct tegra_spi_data {
u32
command1_reg
;
u32
dma_control_reg
;
u32
def_command1_reg
;
u32
def_command2_reg
;
u32
spi_cs_timing1
;
u32
spi_cs_timing2
;
u8
last_used_cs
;
struct
completion
xfer_completion
;
struct
spi_transfer
*
curr_xfer
;
...
...
@@ -711,14 +723,55 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
dma_release_channel
(
dma_chan
);
}
static
void
tegra_spi_set_hw_cs_timing
(
struct
spi_device
*
spi
,
u8
setup_dly
,
u8
hold_dly
,
u8
inactive_dly
)
{
struct
tegra_spi_data
*
tspi
=
spi_master_get_devdata
(
spi
->
master
);
u32
setup_hold
;
u32
spi_cs_timing
;
u32
inactive_cycles
;
u8
cs_state
;
setup_dly
=
min_t
(
u8
,
setup_dly
,
MAX_SETUP_HOLD_CYCLES
);
hold_dly
=
min_t
(
u8
,
hold_dly
,
MAX_SETUP_HOLD_CYCLES
);
if
(
setup_dly
&&
hold_dly
)
{
setup_hold
=
SPI_SETUP_HOLD
(
setup_dly
-
1
,
hold_dly
-
1
);
spi_cs_timing
=
SPI_CS_SETUP_HOLD
(
tspi
->
spi_cs_timing1
,
spi
->
chip_select
,
setup_hold
);
if
(
tspi
->
spi_cs_timing1
!=
spi_cs_timing
)
{
tspi
->
spi_cs_timing1
=
spi_cs_timing
;
tegra_spi_writel
(
tspi
,
spi_cs_timing
,
SPI_CS_TIMING1
);
}
}
inactive_cycles
=
min_t
(
u8
,
inactive_dly
,
MAX_INACTIVE_CYCLES
);
if
(
inactive_cycles
)
inactive_cycles
--
;
cs_state
=
inactive_cycles
?
0
:
1
;
spi_cs_timing
=
tspi
->
spi_cs_timing2
;
SPI_SET_CS_ACTIVE_BETWEEN_PACKETS
(
spi_cs_timing
,
spi
->
chip_select
,
cs_state
);
SPI_SET_CYCLES_BETWEEN_PACKETS
(
spi_cs_timing
,
spi
->
chip_select
,
inactive_cycles
);
if
(
tspi
->
spi_cs_timing2
!=
spi_cs_timing
)
{
tspi
->
spi_cs_timing2
=
spi_cs_timing
;
tegra_spi_writel
(
tspi
,
spi_cs_timing
,
SPI_CS_TIMING2
);
}
}
static
u32
tegra_spi_setup_transfer_one
(
struct
spi_device
*
spi
,
struct
spi_transfer
*
t
,
bool
is_first_of_msg
)
struct
spi_transfer
*
t
,
bool
is_first_of_msg
,
bool
is_single_xfer
)
{
struct
tegra_spi_data
*
tspi
=
spi_master_get_devdata
(
spi
->
master
);
struct
tegra_spi_client_data
*
cdata
=
spi
->
controller_data
;
u32
speed
=
t
->
speed_hz
;
u8
bits_per_word
=
t
->
bits_per_word
;
u32
command1
;
u32
command1
,
command2
;
int
req_mode
;
u32
tx_tap
=
0
,
rx_tap
=
0
;
if
(
speed
!=
tspi
->
cur_speed
)
{
clk_set_rate
(
tspi
->
clk
,
speed
);
...
...
@@ -765,13 +818,34 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
}
else
tegra_spi_writel
(
tspi
,
command1
,
SPI_COMMAND1
);
command1
|=
SPI_CS_SW_HW
;
if
(
spi
->
mode
&
SPI_CS_HIGH
)
command1
|=
SPI_CS_SW_VAL
;
else
command1
&=
~
SPI_CS_SW_VAL
;
/* GPIO based chip select control */
if
(
spi
->
cs_gpiod
)
gpiod_set_value
(
spi
->
cs_gpiod
,
1
);
if
(
is_single_xfer
&&
!
(
t
->
cs_change
))
{
tspi
->
use_hw_based_cs
=
true
;
command1
&=
~
(
SPI_CS_SW_HW
|
SPI_CS_SW_VAL
);
}
else
{
tspi
->
use_hw_based_cs
=
false
;
command1
|=
SPI_CS_SW_HW
;
if
(
spi
->
mode
&
SPI_CS_HIGH
)
command1
|=
SPI_CS_SW_VAL
;
else
command1
&=
~
SPI_CS_SW_VAL
;
}
if
(
tspi
->
last_used_cs
!=
spi
->
chip_select
)
{
if
(
cdata
&&
cdata
->
tx_clk_tap_delay
)
tx_tap
=
cdata
->
tx_clk_tap_delay
;
if
(
cdata
&&
cdata
->
rx_clk_tap_delay
)
rx_tap
=
cdata
->
rx_clk_tap_delay
;
command2
=
SPI_TX_TAP_DELAY
(
tx_tap
)
|
SPI_RX_TAP_DELAY
(
rx_tap
);
if
(
command2
!=
tspi
->
def_command2_reg
)
tegra_spi_writel
(
tspi
,
command2
,
SPI_COMMAND2
);
tspi
->
last_used_cs
=
spi
->
chip_select
;
}
tegra_spi_writel
(
tspi
,
0
,
SPI_COMMAND2
);
}
else
{
command1
=
tspi
->
command1_reg
;
command1
&=
~
SPI_BIT_LENGTH
(
~
0
);
...
...
@@ -827,9 +901,42 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
return
ret
;
}
static
struct
tegra_spi_client_data
*
tegra_spi_parse_cdata_dt
(
struct
spi_device
*
spi
)
{
struct
tegra_spi_client_data
*
cdata
;
struct
device_node
*
slave_np
;
slave_np
=
spi
->
dev
.
of_node
;
if
(
!
slave_np
)
{
dev_dbg
(
&
spi
->
dev
,
"device node not found
\n
"
);
return
NULL
;
}
cdata
=
kzalloc
(
sizeof
(
*
cdata
),
GFP_KERNEL
);
if
(
!
cdata
)
return
NULL
;
of_property_read_u32
(
slave_np
,
"nvidia,tx-clk-tap-delay"
,
&
cdata
->
tx_clk_tap_delay
);
of_property_read_u32
(
slave_np
,
"nvidia,rx-clk-tap-delay"
,
&
cdata
->
rx_clk_tap_delay
);
return
cdata
;
}
static
void
tegra_spi_cleanup
(
struct
spi_device
*
spi
)
{
struct
tegra_spi_client_data
*
cdata
=
spi
->
controller_data
;
spi
->
controller_data
=
NULL
;
if
(
spi
->
dev
.
of_node
)
kfree
(
cdata
);
}
static
int
tegra_spi_setup
(
struct
spi_device
*
spi
)
{
struct
tegra_spi_data
*
tspi
=
spi_master_get_devdata
(
spi
->
master
);
struct
tegra_spi_client_data
*
cdata
=
spi
->
controller_data
;
u32
val
;
unsigned
long
flags
;
int
ret
;
...
...
@@ -840,9 +947,16 @@ static int tegra_spi_setup(struct spi_device *spi)
spi
->
mode
&
SPI_CPHA
?
""
:
"~"
,
spi
->
max_speed_hz
);
if
(
!
cdata
)
{
cdata
=
tegra_spi_parse_cdata_dt
(
spi
);
spi
->
controller_data
=
cdata
;
}
ret
=
pm_runtime_get_sync
(
tspi
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
tspi
->
dev
,
"pm runtime failed, e = %d
\n
"
,
ret
);
if
(
cdata
)
tegra_spi_cleanup
(
spi
);
return
ret
;
}
...
...
@@ -853,6 +967,10 @@ static int tegra_spi_setup(struct spi_device *spi)
}
spin_lock_irqsave
(
&
tspi
->
lock
,
flags
);
/* GPIO based chip select control */
if
(
spi
->
cs_gpiod
)
gpiod_set_value
(
spi
->
cs_gpiod
,
0
);
val
=
tspi
->
def_command1_reg
;
if
(
spi
->
mode
&
SPI_CS_HIGH
)
val
&=
~
SPI_CS_POL_INACTIVE
(
spi
->
chip_select
);
...
...
@@ -882,11 +1000,18 @@ static void tegra_spi_transfer_end(struct spi_device *spi)
struct
tegra_spi_data
*
tspi
=
spi_master_get_devdata
(
spi
->
master
);
int
cs_val
=
(
spi
->
mode
&
SPI_CS_HIGH
)
?
0
:
1
;
if
(
cs_val
)
tspi
->
command1_reg
|=
SPI_CS_SW_VAL
;
else
tspi
->
command1_reg
&=
~
SPI_CS_SW_VAL
;
tegra_spi_writel
(
tspi
,
tspi
->
command1_reg
,
SPI_COMMAND1
);
/* GPIO based chip select control */
if
(
spi
->
cs_gpiod
)
gpiod_set_value
(
spi
->
cs_gpiod
,
0
);
if
(
!
tspi
->
use_hw_based_cs
)
{
if
(
cs_val
)
tspi
->
command1_reg
|=
SPI_CS_SW_VAL
;
else
tspi
->
command1_reg
&=
~
SPI_CS_SW_VAL
;
tegra_spi_writel
(
tspi
,
tspi
->
command1_reg
,
SPI_COMMAND1
);
}
tegra_spi_writel
(
tspi
,
tspi
->
def_command1_reg
,
SPI_COMMAND1
);
}
...
...
@@ -913,16 +1038,19 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
struct
spi_device
*
spi
=
msg
->
spi
;
int
ret
;
bool
skip
=
false
;
int
single_xfer
;
msg
->
status
=
0
;
msg
->
actual_length
=
0
;
single_xfer
=
list_is_singular
(
&
msg
->
transfers
);
list_for_each_entry
(
xfer
,
&
msg
->
transfers
,
transfer_list
)
{
u32
cmd1
;
reinit_completion
(
&
tspi
->
xfer_completion
);
cmd1
=
tegra_spi_setup_transfer_one
(
spi
,
xfer
,
is_first_msg
);
cmd1
=
tegra_spi_setup_transfer_one
(
spi
,
xfer
,
is_first_msg
,
single_xfer
);
if
(
!
xfer
->
len
)
{
ret
=
0
;
...
...
@@ -955,6 +1083,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
reset_control_assert
(
tspi
->
rst
);
udelay
(
2
);
reset_control_deassert
(
tspi
->
rst
);
tspi
->
last_used_cs
=
master
->
num_chipselect
+
1
;
goto
complete_xfer
;
}
...
...
@@ -1188,11 +1317,14 @@ static int tegra_spi_probe(struct platform_device *pdev)
master
->
max_speed_hz
=
25000000
;
/* 25MHz */
/* the spi->mode bits understood by this driver: */
master
->
use_gpio_descriptors
=
true
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_CS_HIGH
|
SPI_LSB_FIRST
|
SPI_TX_DUAL
|
SPI_RX_DUAL
|
SPI_3WIRE
;
master
->
bits_per_word_mask
=
SPI_BPW_RANGE_MASK
(
4
,
32
);
master
->
setup
=
tegra_spi_setup
;
master
->
cleanup
=
tegra_spi_cleanup
;
master
->
transfer_one_message
=
tegra_spi_transfer_one_message
;
master
->
set_cs_timing
=
tegra_spi_set_hw_cs_timing
;
master
->
num_chipselect
=
MAX_CHIP_SELECT
;
master
->
auto_runtime_pm
=
true
;
bus_num
=
of_alias_get_id
(
pdev
->
dev
.
of_node
,
"spi"
);
...
...
@@ -1268,6 +1400,10 @@ static int tegra_spi_probe(struct platform_device *pdev)
reset_control_deassert
(
tspi
->
rst
);
tspi
->
def_command1_reg
=
SPI_M_S
;
tegra_spi_writel
(
tspi
,
tspi
->
def_command1_reg
,
SPI_COMMAND1
);
tspi
->
spi_cs_timing1
=
tegra_spi_readl
(
tspi
,
SPI_CS_TIMING1
);
tspi
->
spi_cs_timing2
=
tegra_spi_readl
(
tspi
,
SPI_CS_TIMING2
);
tspi
->
def_command2_reg
=
tegra_spi_readl
(
tspi
,
SPI_COMMAND2
);
tspi
->
last_used_cs
=
master
->
num_chipselect
+
1
;
pm_runtime_put
(
&
pdev
->
dev
);
ret
=
request_threaded_irq
(
tspi
->
irq
,
tegra_spi_isr
,
tegra_spi_isr_thread
,
IRQF_ONESHOT
,
...
...
@@ -1340,6 +1476,8 @@ static int tegra_spi_resume(struct device *dev)
return
ret
;
}
tegra_spi_writel
(
tspi
,
tspi
->
command1_reg
,
SPI_COMMAND1
);
tegra_spi_writel
(
tspi
,
tspi
->
def_command2_reg
,
SPI_COMMAND2
);
tspi
->
last_used_cs
=
master
->
num_chipselect
+
1
;
pm_runtime_put
(
dev
);
return
spi_master_resume
(
master
);
...
...
drivers/spi/spi.c
View file @
106dbe24
...
...
@@ -1090,6 +1090,60 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
return
0
;
}
static
void
_spi_transfer_delay_ns
(
u32
ns
)
{
if
(
!
ns
)
return
;
if
(
ns
<=
1000
)
{
ndelay
(
ns
);
}
else
{
u32
us
=
DIV_ROUND_UP
(
ns
,
1000
);
if
(
us
<=
10
)
udelay
(
us
);
else
usleep_range
(
us
,
us
+
DIV_ROUND_UP
(
us
,
10
));
}
}
static
void
_spi_transfer_cs_change_delay
(
struct
spi_message
*
msg
,
struct
spi_transfer
*
xfer
)
{
u32
delay
=
xfer
->
cs_change_delay
;
u32
unit
=
xfer
->
cs_change_delay_unit
;
u32
hz
;
/* return early on "fast" mode - for everything but USECS */
if
(
!
delay
&&
unit
!=
SPI_DELAY_UNIT_USECS
)
return
;
switch
(
unit
)
{
case
SPI_DELAY_UNIT_USECS
:
/* for compatibility use default of 10us */
if
(
!
delay
)
delay
=
10000
;
else
delay
*=
1000
;
break
;
case
SPI_DELAY_UNIT_NSECS
:
/* nothing to do here */
break
;
case
SPI_DELAY_UNIT_SCK
:
/* if there is no effective speed know, then approximate
* by underestimating with half the requested hz
*/
hz
=
xfer
->
effective_speed_hz
?:
xfer
->
speed_hz
/
2
;
delay
*=
DIV_ROUND_UP
(
1000000000
,
hz
);
break
;
default:
dev_err_once
(
&
msg
->
spi
->
dev
,
"Use of unsupported delay unit %i, using default of 10us
\n
"
,
xfer
->
cs_change_delay_unit
);
delay
=
10000
;
}
/* now sleep for the requested amount of time */
_spi_transfer_delay_ns
(
delay
);
}
/*
* spi_transfer_one_message - Default implementation of transfer_one_message()
*
...
...
@@ -1148,14 +1202,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
if
(
msg
->
status
!=
-
EINPROGRESS
)
goto
out
;
if
(
xfer
->
delay_usecs
)
{
u16
us
=
xfer
->
delay_usecs
;
if
(
us
<=
10
)
udelay
(
us
);
else
usleep_range
(
us
,
us
+
DIV_ROUND_UP
(
us
,
10
));
}
if
(
xfer
->
delay_usecs
)
_spi_transfer_delay_ns
(
xfer
->
delay_usecs
*
1000
);
if
(
xfer
->
cs_change
)
{
if
(
list_is_last
(
&
xfer
->
transfer_list
,
...
...
@@ -1163,7 +1211,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
keep_cs
=
true
;
}
else
{
spi_set_cs
(
msg
->
spi
,
false
);
udelay
(
10
);
_spi_transfer_cs_change_delay
(
msg
,
xfer
);
spi_set_cs
(
msg
->
spi
,
true
);
}
}
...
...
@@ -1804,9 +1852,18 @@ static void of_register_spi_devices(struct spi_controller *ctlr) { }
#endif
#ifdef CONFIG_ACPI
static
void
acpi_spi_parse_apple_properties
(
struct
spi_device
*
spi
)
struct
acpi_spi_lookup
{
struct
spi_controller
*
ctlr
;
u32
max_speed_hz
;
u32
mode
;
int
irq
;
u8
bits_per_word
;
u8
chip_select
;
};
static
void
acpi_spi_parse_apple_properties
(
struct
acpi_device
*
dev
,
struct
acpi_spi_lookup
*
lookup
)
{
struct
acpi_device
*
dev
=
ACPI_COMPANION
(
&
spi
->
dev
);
const
union
acpi_object
*
obj
;
if
(
!
x86_apple_machine
)
...
...
@@ -1814,35 +1871,46 @@ static void acpi_spi_parse_apple_properties(struct spi_device *spi)
if
(
!
acpi_dev_get_property
(
dev
,
"spiSclkPeriod"
,
ACPI_TYPE_BUFFER
,
&
obj
)
&&
obj
->
buffer
.
length
>=
4
)
spi
->
max_speed_hz
=
NSEC_PER_SEC
/
*
(
u32
*
)
obj
->
buffer
.
pointer
;
lookup
->
max_speed_hz
=
NSEC_PER_SEC
/
*
(
u32
*
)
obj
->
buffer
.
pointer
;
if
(
!
acpi_dev_get_property
(
dev
,
"spiWordSize"
,
ACPI_TYPE_BUFFER
,
&
obj
)
&&
obj
->
buffer
.
length
==
8
)
spi
->
bits_per_word
=
*
(
u64
*
)
obj
->
buffer
.
pointer
;
lookup
->
bits_per_word
=
*
(
u64
*
)
obj
->
buffer
.
pointer
;
if
(
!
acpi_dev_get_property
(
dev
,
"spiBitOrder"
,
ACPI_TYPE_BUFFER
,
&
obj
)
&&
obj
->
buffer
.
length
==
8
&&
!*
(
u64
*
)
obj
->
buffer
.
pointer
)
spi
->
mode
|=
SPI_LSB_FIRST
;
lookup
->
mode
|=
SPI_LSB_FIRST
;
if
(
!
acpi_dev_get_property
(
dev
,
"spiSPO"
,
ACPI_TYPE_BUFFER
,
&
obj
)
&&
obj
->
buffer
.
length
==
8
&&
*
(
u64
*
)
obj
->
buffer
.
pointer
)
spi
->
mode
|=
SPI_CPOL
;
lookup
->
mode
|=
SPI_CPOL
;
if
(
!
acpi_dev_get_property
(
dev
,
"spiSPH"
,
ACPI_TYPE_BUFFER
,
&
obj
)
&&
obj
->
buffer
.
length
==
8
&&
*
(
u64
*
)
obj
->
buffer
.
pointer
)
spi
->
mode
|=
SPI_CPHA
;
lookup
->
mode
|=
SPI_CPHA
;
}
static
int
acpi_spi_add_resource
(
struct
acpi_resource
*
ares
,
void
*
data
)
{
struct
spi_device
*
spi
=
data
;
struct
spi_controller
*
ctlr
=
spi
->
controlle
r
;
struct
acpi_spi_lookup
*
lookup
=
data
;
struct
spi_controller
*
ctlr
=
lookup
->
ctl
r
;
if
(
ares
->
type
==
ACPI_RESOURCE_TYPE_SERIAL_BUS
)
{
struct
acpi_resource_spi_serialbus
*
sb
;
acpi_handle
parent_handle
;
acpi_status
status
;
sb
=
&
ares
->
data
.
spi_serial_bus
;
if
(
sb
->
type
==
ACPI_RESOURCE_SERIAL_TYPE_SPI
)
{
status
=
acpi_get_handle
(
NULL
,
sb
->
resource_source
.
string_ptr
,
&
parent_handle
);
if
(
ACPI_FAILURE
(
status
)
||
ACPI_HANDLE
(
ctlr
->
dev
.
parent
)
!=
parent_handle
)
return
-
ENODEV
;
/*
* ACPI DeviceSelection numbering is handled by the
* host controller driver in Windows and can vary
...
...
@@ -1855,25 +1923,25 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
sb
->
device_selection
);
if
(
cs
<
0
)
return
cs
;
spi
->
chip_select
=
cs
;
lookup
->
chip_select
=
cs
;
}
else
{
spi
->
chip_select
=
sb
->
device_selection
;
lookup
->
chip_select
=
sb
->
device_selection
;
}
spi
->
max_speed_hz
=
sb
->
connection_speed
;
lookup
->
max_speed_hz
=
sb
->
connection_speed
;
if
(
sb
->
clock_phase
==
ACPI_SPI_SECOND_PHASE
)
spi
->
mode
|=
SPI_CPHA
;
lookup
->
mode
|=
SPI_CPHA
;
if
(
sb
->
clock_polarity
==
ACPI_SPI_START_HIGH
)
spi
->
mode
|=
SPI_CPOL
;
lookup
->
mode
|=
SPI_CPOL
;
if
(
sb
->
device_polarity
==
ACPI_SPI_ACTIVE_HIGH
)
spi
->
mode
|=
SPI_CS_HIGH
;
lookup
->
mode
|=
SPI_CS_HIGH
;
}
}
else
if
(
spi
->
irq
<
0
)
{
}
else
if
(
lookup
->
irq
<
0
)
{
struct
resource
r
;
if
(
acpi_dev_resource_interrupt
(
ares
,
0
,
&
r
))
spi
->
irq
=
r
.
start
;
lookup
->
irq
=
r
.
start
;
}
/* Always tell the ACPI core to skip this resource */
...
...
@@ -1883,7 +1951,9 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
static
acpi_status
acpi_register_spi_device
(
struct
spi_controller
*
ctlr
,
struct
acpi_device
*
adev
)
{
acpi_handle
parent_handle
=
NULL
;
struct
list_head
resource_list
;
struct
acpi_spi_lookup
lookup
=
{};
struct
spi_device
*
spi
;
int
ret
;
...
...
@@ -1891,28 +1961,42 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
acpi_device_enumerated
(
adev
))
return
AE_OK
;
spi
=
spi_alloc_device
(
ctlr
);
if
(
!
spi
)
{
dev_err
(
&
ctlr
->
dev
,
"failed to allocate SPI device for %s
\n
"
,
dev_name
(
&
adev
->
dev
));
return
AE_NO_MEMORY
;
}
ACPI_COMPANION_SET
(
&
spi
->
dev
,
adev
);
spi
->
irq
=
-
1
;
lookup
.
ctlr
=
ctlr
;
lookup
.
irq
=
-
1
;
INIT_LIST_HEAD
(
&
resource_list
);
ret
=
acpi_dev_get_resources
(
adev
,
&
resource_list
,
acpi_spi_add_resource
,
spi
);
acpi_spi_add_resource
,
&
lookup
);
acpi_dev_free_resource_list
(
&
resource_list
);
acpi_spi_parse_apple_properties
(
spi
);
if
(
ret
<
0
)
/* found SPI in _CRS but it points to another controller */
return
AE_OK
;
if
(
ret
<
0
||
!
spi
->
max_speed_hz
)
{
spi_dev_put
(
spi
);
if
(
!
lookup
.
max_speed_hz
&&
!
ACPI_FAILURE
(
acpi_get_parent
(
adev
->
handle
,
&
parent_handle
))
&&
ACPI_HANDLE
(
ctlr
->
dev
.
parent
)
==
parent_handle
)
{
/* Apple does not use _CRS but nested devices for SPI slaves */
acpi_spi_parse_apple_properties
(
adev
,
&
lookup
);
}
if
(
!
lookup
.
max_speed_hz
)
return
AE_OK
;
spi
=
spi_alloc_device
(
ctlr
);
if
(
!
spi
)
{
dev_err
(
&
ctlr
->
dev
,
"failed to allocate SPI device for %s
\n
"
,
dev_name
(
&
adev
->
dev
));
return
AE_NO_MEMORY
;
}
ACPI_COMPANION_SET
(
&
spi
->
dev
,
adev
);
spi
->
max_speed_hz
=
lookup
.
max_speed_hz
;
spi
->
mode
=
lookup
.
mode
;
spi
->
irq
=
lookup
.
irq
;
spi
->
bits_per_word
=
lookup
.
bits_per_word
;
spi
->
chip_select
=
lookup
.
chip_select
;
acpi_set_modalias
(
adev
,
acpi_device_hid
(
adev
),
spi
->
modalias
,
sizeof
(
spi
->
modalias
));
...
...
@@ -1944,6 +2028,8 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
return
acpi_register_spi_device
(
ctlr
,
adev
);
}
#define SPI_ACPI_ENUMERATE_MAX_DEPTH 32
static
void
acpi_register_spi_devices
(
struct
spi_controller
*
ctlr
)
{
acpi_status
status
;
...
...
@@ -1953,7 +2039,8 @@ static void acpi_register_spi_devices(struct spi_controller *ctlr)
if
(
!
handle
)
return
;
status
=
acpi_walk_namespace
(
ACPI_TYPE_DEVICE
,
handle
,
1
,
status
=
acpi_walk_namespace
(
ACPI_TYPE_DEVICE
,
ACPI_ROOT_OBJECT
,
SPI_ACPI_ENUMERATE_MAX_DEPTH
,
acpi_spi_add_device
,
NULL
,
ctlr
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
dev_warn
(
&
ctlr
->
dev
,
"failed to enumerate SPI slaves
\n
"
);
...
...
@@ -2286,11 +2373,6 @@ int spi_register_controller(struct spi_controller *ctlr)
if
(
status
)
return
status
;
/* even if it's just one always-selected device, there must
* be at least one chipselect
*/
if
(
ctlr
->
num_chipselect
==
0
)
return
-
EINVAL
;
if
(
ctlr
->
bus_num
>=
0
)
{
/* devices with a fixed bus num must check-in with the num */
mutex_lock
(
&
board_lock
);
...
...
@@ -2361,6 +2443,13 @@ int spi_register_controller(struct spi_controller *ctlr)
}
}
/*
* Even if it's just one always-selected device, there must
* be at least one chipselect.
*/
if
(
!
ctlr
->
num_chipselect
)
return
-
EINVAL
;
status
=
device_add
(
&
ctlr
->
dev
);
if
(
status
<
0
)
{
/* free bus id */
...
...
@@ -2470,7 +2559,6 @@ void spi_unregister_controller(struct spi_controller *ctlr)
{
struct
spi_controller
*
found
;
int
id
=
ctlr
->
bus_num
;
int
dummy
;
/* First make sure that this controller was ever added */
mutex_lock
(
&
board_lock
);
...
...
@@ -2484,7 +2572,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
list_del
(
&
ctlr
->
list
);
mutex_unlock
(
&
board_lock
);
d
ummy
=
d
evice_for_each_child
(
&
ctlr
->
dev
,
NULL
,
__unregister
);
device_for_each_child
(
&
ctlr
->
dev
,
NULL
,
__unregister
);
device_unregister
(
&
ctlr
->
dev
);
/* free bus id */
mutex_lock
(
&
board_lock
);
...
...
@@ -2633,12 +2721,9 @@ EXPORT_SYMBOL_GPL(spi_res_add);
*/
void
spi_res_release
(
struct
spi_controller
*
ctlr
,
struct
spi_message
*
message
)
{
struct
spi_res
*
res
;
while
(
!
list_empty
(
&
message
->
resources
))
{
res
=
list_last_entry
(
&
message
->
resources
,
struct
spi_res
,
entry
);
struct
spi_res
*
res
,
*
tmp
;
list_for_each_entry_safe_reverse
(
res
,
tmp
,
&
message
->
resources
,
entry
)
{
if
(
res
->
release
)
res
->
release
(
ctlr
,
message
,
res
->
data
);
...
...
@@ -2702,8 +2787,7 @@ struct spi_replaced_transfers *spi_replace_transfers(
/* allocate the structure using spi_res */
rxfer
=
spi_res_alloc
(
msg
->
spi
,
__spi_replace_transfers_release
,
insert
*
sizeof
(
struct
spi_transfer
)
+
sizeof
(
struct
spi_replaced_transfers
)
struct_size
(
rxfer
,
inserted_transfers
,
insert
)
+
extradatasize
,
gfp
);
if
(
!
rxfer
)
...
...
@@ -3083,6 +3167,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
*/
message
->
frame_length
=
0
;
list_for_each_entry
(
xfer
,
&
message
->
transfers
,
transfer_list
)
{
xfer
->
effective_speed_hz
=
0
;
message
->
frame_length
+=
xfer
->
len
;
if
(
!
xfer
->
bits_per_word
)
xfer
->
bits_per_word
=
spi
->
bits_per_word
;
...
...
@@ -3762,4 +3847,3 @@ static int __init spi_init(void)
* include needing to have boardinfo data structures be much more public.
*/
postcore_initcall
(
spi_init
);
drivers/spi/spidev.c
View file @
106dbe24
...
...
@@ -663,6 +663,8 @@ static const struct of_device_id spidev_dt_ids[] = {
{
.
compatible
=
"ge,achc"
},
{
.
compatible
=
"semtech,sx1301"
},
{
.
compatible
=
"lwn,bk4"
},
{
.
compatible
=
"dh,dhcom-board"
},
{
.
compatible
=
"menlo,m53cpld"
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
spidev_dt_ids
);
...
...
include/linux/platform_data/spi-mt65xx.h
View file @
106dbe24
...
...
@@ -11,8 +11,6 @@
/* Board specific platform_data */
struct
mtk_chip_config
{
u32
tx_mlsb
;
u32
rx_mlsb
;
u32
cs_pol
;
u32
sample_sel
;
};
...
...
include/linux/spi/spi.h
View file @
106dbe24
...
...
@@ -735,6 +735,9 @@ extern void spi_res_release(struct spi_controller *ctlr,
* @bits_per_word: select a bits_per_word other than the device default
* for this transfer. If 0 the default (from @spi_device) is used.
* @cs_change: affects chipselect after this transfer completes
* @cs_change_delay: delay between cs deassert and assert when
* @cs_change is set and @spi_transfer is not the last in @spi_message
* @cs_change_delay_unit: unit of cs_change_delay
* @delay_usecs: microseconds to delay after this transfer before
* (optionally) changing the chipselect status, then starting
* the next transfer or completing this @spi_message.
...
...
@@ -742,6 +745,9 @@ extern void spi_res_release(struct spi_controller *ctlr,
* (set by bits_per_word) transmission.
* @word_delay: clock cycles to inter word delay after each word size
* (set by bits_per_word) transmission.
* @effective_speed_hz: the effective SCK-speed that was used to
* transfer this transfer. Set to 0 if the spi bus driver does
* not support it.
* @transfer_list: transfers are sequenced through @spi_message.transfers
* @tx_sg: Scatterlist for transmit, currently not for client use
* @rx_sg: Scatterlist for receive, currently not for client use
...
...
@@ -824,9 +830,16 @@ struct spi_transfer {
u8
bits_per_word
;
u8
word_delay_usecs
;
u16
delay_usecs
;
u16
cs_change_delay
;
u8
cs_change_delay_unit
;
#define SPI_DELAY_UNIT_USECS 0
#define SPI_DELAY_UNIT_NSECS 1
#define SPI_DELAY_UNIT_SCK 2
u32
speed_hz
;
u16
word_delay
;
u32
effective_speed_hz
;
struct
list_head
transfer_list
;
};
...
...
@@ -967,6 +980,8 @@ static inline void spi_message_free(struct spi_message *m)
kfree
(
m
);
}
extern
void
spi_set_cs_timing
(
struct
spi_device
*
spi
,
u8
setup
,
u8
hold
,
u8
inactive_dly
);
extern
int
spi_setup
(
struct
spi_device
*
spi
);
extern
int
spi_async
(
struct
spi_device
*
spi
,
struct
spi_message
*
message
);
extern
int
spi_async_locked
(
struct
spi_device
*
spi
,
...
...
@@ -997,6 +1012,26 @@ spi_max_transfer_size(struct spi_device *spi)
return
min
(
tr_max
,
msg_max
);
}
/**
* spi_is_bpw_supported - Check if bits per word is supported
* @spi: SPI device
* @bpw: Bits per word
*
* This function checks to see if the SPI controller supports @bpw.
*
* Returns:
* True if @bpw is supported, false otherwise.
*/
static
inline
bool
spi_is_bpw_supported
(
struct
spi_device
*
spi
,
u32
bpw
)
{
u32
bpw_mask
=
spi
->
master
->
bits_per_word_mask
;
if
(
bpw
==
8
||
(
bpw
<=
32
&&
bpw_mask
&
SPI_BPW_MASK
(
bpw
)))
return
true
;
return
false
;
}
/*---------------------------------------------------------------------------*/
/* SPI transfer replacement methods which make use of spi_res */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment