forked from Minki/linux
spi: Updates for v5.17
This has mostly been a quiet release for the SPI subsystem, almost all cleanups and fixes to existing drivers. A couple of changes that stand out: - Cleanups and support for version specific features in the DesignWare controller. - Removal of support for Netlogic devices from the XLP driver, the platform had previously been removed by MIPS so the support couldn't be used. - Conversion of several DT bindings to YAML format. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmHcNHcACgkQJNaLcl1U h9Bm0Qf7B+2c0Mi8GGJ1TCL44IGTAs9DDOK1uvtaL6VOP5XA1CAm92na4+xghb05 xIxvHF/IyC4rAUjg+8btzgIBSmtBXNELO4JFCVXdKnaFPPjIjJfzE9eMdcK6HVdq 6ZNNVRCFv9E6Dy9cEPyU9dUNKSwJmE6ok8qHxo7f78WeftPWmBvMXa5knE5rj+d4 IiqaJg0L2jdGkTM5Qy0Mm+dI0dTUEkGCrjMhyJXbhry0H7L8z9f9utWI3QE8IXyG oyt2k7+MSrb6jeb9MRuD/9GC6VdaVv6MWTBEA0yTTsaGZhXwcpy9XJXy7xbbdF6P g7cd4E4Rlfz4Y9j8GSaDW4AuuUBB3A== =LgO4 -----END PGP SIGNATURE----- Merge tag 'spi-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi updates from Mark Brown: "This has mostly been a quiet release for the SPI subsystem, almost all cleanups and fixes to existing drivers. A couple of changes that stand out: - Cleanups and support for version specific features in the DesignWare controller. - Removal of support for Netlogic devices from the XLP driver, the platform had previously been removed by MIPS so the support couldn't be used. - Conversion of several DT bindings to YAML format" * tag 'spi-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (53 commits) spi: don't include ptp_clock_kernel.h in spi.h spi: spi-meson-spifc: Add missing pm_runtime_disable() in meson_spifc_probe spi: atmel: Fix typo spi: dt-bindings: mediatek,spi-mtk-nor: Fix example 'interrupts' property spi: qcom: geni: handle timeout for gpi mode spi: qcom: geni: set the error code for gpi transfer spi: spi-mux: Add reference to spi-peripheral-props.yaml schema spi: ar934x: fix transfer size spi: pxa2xx: Propagate firmware node spi: dw: Propagate firmware node spi: dln2: Propagate firmware node spi: ar934x: fix transfer and word delays spi: uniphier: Fix a bug that doesn't point to private data correctly spi: spi-mtk-nor: add new clock name 'axi' for spi nor spi: atmel,quadspi: Define sama7g5 QSPI spi: atmel,quadspi: Convert to json-schema spi: Fix incorrect cs_setup delay handling dt-bindings: mtd: spi-nor: Add a reference to spi-peripheral-props.yaml spi: dt-bindings: cdns,qspi-nor: Move peripheral-specific properties out spi: dt-bindings: add schema listing peripheral-specific properties ...
This commit is contained in:
commit
282aa44c21
@ -11,6 +11,7 @@ maintainers:
|
|||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "mtd.yaml#"
|
- $ref: "mtd.yaml#"
|
||||||
|
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
@ -88,7 +89,7 @@ patternProperties:
|
|||||||
"^otp(-[0-9]+)?$":
|
"^otp(-[0-9]+)?$":
|
||||||
type: object
|
type: object
|
||||||
|
|
||||||
additionalProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
|
99
Documentation/devicetree/bindings/spi/atmel,quadspi.yaml
Normal file
99
Documentation/devicetree/bindings/spi/atmel,quadspi.yaml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/spi/atmel,quadspi.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Atmel Quad Serial Peripheral Interface (QSPI)
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Tudor Ambarus <tudor.ambarus@microchip.com>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: spi-controller.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- atmel,sama5d2-qspi
|
||||||
|
- microchip,sam9x60-qspi
|
||||||
|
- microchip,sama7g5-qspi
|
||||||
|
- microchip,sama7g5-ospi
|
||||||
|
|
||||||
|
reg:
|
||||||
|
items:
|
||||||
|
- description: base registers
|
||||||
|
- description: mapped memory
|
||||||
|
|
||||||
|
reg-names:
|
||||||
|
items:
|
||||||
|
- const: qspi_base
|
||||||
|
- const: qspi_mmap
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
minItems: 1
|
||||||
|
items:
|
||||||
|
- description: peripheral clock
|
||||||
|
- description: system clock or generic clock, if available
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
minItems: 1
|
||||||
|
items:
|
||||||
|
- const: pclk
|
||||||
|
- enum: [ qspick, gclk ]
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
dmas:
|
||||||
|
items:
|
||||||
|
- description: tx DMA channel
|
||||||
|
- description: rx DMA channel
|
||||||
|
|
||||||
|
dma-names:
|
||||||
|
items:
|
||||||
|
- const: tx
|
||||||
|
- const: rx
|
||||||
|
|
||||||
|
'#address-cells':
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
'#size-cells':
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- reg-names
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- '#address-cells'
|
||||||
|
- '#size-cells'
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
#include <dt-bindings/clock/at91.h>
|
||||||
|
spi@f0020000 {
|
||||||
|
compatible = "atmel,sama5d2-qspi";
|
||||||
|
reg = <0xf0020000 0x100>, <0xd0000000 0x8000000>;
|
||||||
|
reg-names = "qspi_base", "qspi_mmap";
|
||||||
|
interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>;
|
||||||
|
clocks = <&pmc PMC_TYPE_PERIPHERAL 52>;
|
||||||
|
clock-names = "pclk";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pinctrl_spi0_default>;
|
||||||
|
|
||||||
|
flash@0 {
|
||||||
|
compatible = "jedec,spi-nor";
|
||||||
|
spi-max-frequency = <50000000>;
|
||||||
|
reg = <0>;
|
||||||
|
spi-rx-bus-width = <4>;
|
||||||
|
spi-tx-bus-width = <4>;
|
||||||
|
};
|
||||||
|
};
|
@ -1,37 +0,0 @@
|
|||||||
* Atmel Quad Serial Peripheral Interface (QSPI)
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: Should be one of the following:
|
|
||||||
- "atmel,sama5d2-qspi"
|
|
||||||
- "microchip,sam9x60-qspi"
|
|
||||||
- reg: Should contain the locations and lengths of the base registers
|
|
||||||
and the mapped memory.
|
|
||||||
- reg-names: Should contain the resource reg names:
|
|
||||||
- qspi_base: configuration register address space
|
|
||||||
- qspi_mmap: memory mapped address space
|
|
||||||
- interrupts: Should contain the interrupt for the device.
|
|
||||||
- clocks: Should reference the peripheral clock and the QSPI system
|
|
||||||
clock if available.
|
|
||||||
- clock-names: Should contain "pclk" for the peripheral clock and "qspick"
|
|
||||||
for the system clock when available.
|
|
||||||
- #address-cells: Should be <1>.
|
|
||||||
- #size-cells: Should be <0>.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
spi@f0020000 {
|
|
||||||
compatible = "atmel,sama5d2-qspi";
|
|
||||||
reg = <0xf0020000 0x100>, <0xd0000000 0x8000000>;
|
|
||||||
reg-names = "qspi_base", "qspi_mmap";
|
|
||||||
interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>;
|
|
||||||
clocks = <&pmc PMC_TYPE_PERIPHERAL 52>;
|
|
||||||
clock-names = "pclk";
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&pinctrl_spi0_default>;
|
|
||||||
|
|
||||||
m25p80@0 {
|
|
||||||
...
|
|
||||||
};
|
|
||||||
};
|
|
@ -0,0 +1,42 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/spi/cdns,qspi-nor-peripheral-props.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Peripheral-specific properties for the Cadence QSPI controller.
|
||||||
|
|
||||||
|
description:
|
||||||
|
See spi-peripheral-props.yaml for more info.
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Pratyush Yadav <p.yadav@ti.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
# cdns,qspi-nor.yaml
|
||||||
|
cdns,read-delay:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description:
|
||||||
|
Delay for read capture logic, in clock cycles.
|
||||||
|
|
||||||
|
cdns,tshsl-ns:
|
||||||
|
description:
|
||||||
|
Delay in nanoseconds for the length that the master mode chip select
|
||||||
|
outputs are de-asserted between transactions.
|
||||||
|
|
||||||
|
cdns,tsd2d-ns:
|
||||||
|
description:
|
||||||
|
Delay in nanoseconds between one chip select being de-activated
|
||||||
|
and the activation of another.
|
||||||
|
|
||||||
|
cdns,tchsh-ns:
|
||||||
|
description:
|
||||||
|
Delay in nanoseconds between last bit of current transaction and
|
||||||
|
deasserting the device chip select (qspi_n_ss_out).
|
||||||
|
|
||||||
|
cdns,tslch-ns:
|
||||||
|
description:
|
||||||
|
Delay in nanoseconds between setting qspi_n_ss_out low and
|
||||||
|
first bit transfer.
|
||||||
|
|
||||||
|
additionalProperties: true
|
@ -87,39 +87,6 @@ properties:
|
|||||||
items:
|
items:
|
||||||
enum: [ qspi, qspi-ocp ]
|
enum: [ qspi, qspi-ocp ]
|
||||||
|
|
||||||
# subnode's properties
|
|
||||||
patternProperties:
|
|
||||||
"@[0-9a-f]+$":
|
|
||||||
type: object
|
|
||||||
description:
|
|
||||||
Flash device uses the below defined properties in the subnode.
|
|
||||||
|
|
||||||
properties:
|
|
||||||
cdns,read-delay:
|
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
|
||||||
description:
|
|
||||||
Delay for read capture logic, in clock cycles.
|
|
||||||
|
|
||||||
cdns,tshsl-ns:
|
|
||||||
description:
|
|
||||||
Delay in nanoseconds for the length that the master mode chip select
|
|
||||||
outputs are de-asserted between transactions.
|
|
||||||
|
|
||||||
cdns,tsd2d-ns:
|
|
||||||
description:
|
|
||||||
Delay in nanoseconds between one chip select being de-activated
|
|
||||||
and the activation of another.
|
|
||||||
|
|
||||||
cdns,tchsh-ns:
|
|
||||||
description:
|
|
||||||
Delay in nanoseconds between last bit of current transaction and
|
|
||||||
deasserting the device chip select (qspi_n_ss_out).
|
|
||||||
|
|
||||||
cdns,tslch-ns:
|
|
||||||
description:
|
|
||||||
Delay in nanoseconds between setting qspi_n_ss_out low and
|
|
||||||
first bit transfer.
|
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
|
@ -43,14 +43,19 @@ properties:
|
|||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
clocks:
|
clocks:
|
||||||
|
minItems: 2
|
||||||
items:
|
items:
|
||||||
- description: clock used for spi bus
|
- description: clock used for spi bus
|
||||||
- description: clock used for controller
|
- description: clock used for controller
|
||||||
|
- description: clock used for nor dma bus. this depends on hardware
|
||||||
|
design, so this is optional.
|
||||||
|
|
||||||
clock-names:
|
clock-names:
|
||||||
|
minItems: 2
|
||||||
items:
|
items:
|
||||||
- const: spi
|
- const: spi
|
||||||
- const: sf
|
- const: sf
|
||||||
|
- const: axi
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
@ -72,7 +77,7 @@ examples:
|
|||||||
nor_flash: spi@1100d000 {
|
nor_flash: spi@1100d000 {
|
||||||
compatible = "mediatek,mt8173-nor";
|
compatible = "mediatek,mt8173-nor";
|
||||||
reg = <0 0x1100d000 0 0xe0>;
|
reg = <0 0x1100d000 0 0xe0>;
|
||||||
interrupts = <&spi_flash_irq>;
|
interrupts = <1>;
|
||||||
clocks = <&pericfg CLK_PERI_SPI>, <&topckgen CLK_TOP_SPINFI_IFR_SEL>;
|
clocks = <&pericfg CLK_PERI_SPI>, <&topckgen CLK_TOP_SPINFI_IFR_SEL>;
|
||||||
clock-names = "spi", "sf";
|
clock-names = "spi", "sf";
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
@ -84,4 +89,3 @@ examples:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ properties:
|
|||||||
- enum:
|
- enum:
|
||||||
- renesas,rspi-r7s72100 # RZ/A1H
|
- renesas,rspi-r7s72100 # RZ/A1H
|
||||||
- renesas,rspi-r7s9210 # RZ/A2
|
- renesas,rspi-r7s9210 # RZ/A2
|
||||||
- const: renesas,rspi-rz # RZ/A
|
- renesas,r9a07g044-rspi # RZ/G2{L,LC}
|
||||||
|
- const: renesas,rspi-rz # RZ/A and RZ/G2{L,LC}
|
||||||
|
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
@ -122,6 +123,7 @@ allOf:
|
|||||||
contains:
|
contains:
|
||||||
enum:
|
enum:
|
||||||
- renesas,qspi
|
- renesas,qspi
|
||||||
|
- renesas,r9a07g044-rspi
|
||||||
then:
|
then:
|
||||||
required:
|
required:
|
||||||
- resets
|
- resets
|
||||||
|
@ -94,73 +94,8 @@ patternProperties:
|
|||||||
"^.*@[0-9a-f]+$":
|
"^.*@[0-9a-f]+$":
|
||||||
type: object
|
type: object
|
||||||
|
|
||||||
properties:
|
allOf:
|
||||||
compatible:
|
- $ref: spi-peripheral-props.yaml
|
||||||
description:
|
|
||||||
Compatible of the SPI device.
|
|
||||||
|
|
||||||
reg:
|
|
||||||
minItems: 1
|
|
||||||
maxItems: 256
|
|
||||||
items:
|
|
||||||
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:
|
|
||||||
description:
|
|
||||||
Bus width to the SPI bus used for read transfers.
|
|
||||||
If 0 is provided, then no RX will be possible on this device.
|
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
|
||||||
enum: [0, 1, 2, 4, 8]
|
|
||||||
default: 1
|
|
||||||
|
|
||||||
spi-rx-delay-us:
|
|
||||||
description:
|
|
||||||
Delay, in microseconds, after a read transfer.
|
|
||||||
|
|
||||||
spi-tx-bus-width:
|
|
||||||
description:
|
|
||||||
Bus width to the SPI bus used for write transfers.
|
|
||||||
If 0 is provided, then no TX will be possible on this device.
|
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
|
||||||
enum: [0, 1, 2, 4, 8]
|
|
||||||
default: 1
|
|
||||||
|
|
||||||
spi-tx-delay-us:
|
|
||||||
description:
|
|
||||||
Delay, in microseconds, after a write transfer.
|
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
|
@ -14,10 +14,13 @@ allOf:
|
|||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
enum:
|
oneOf:
|
||||||
- fsl,imx7ulp-spi
|
- enum:
|
||||||
- fsl,imx8qxp-spi
|
- fsl,imx7ulp-spi
|
||||||
|
- fsl,imx8qxp-spi
|
||||||
|
- items:
|
||||||
|
- const: fsl,imx8ulp-spi
|
||||||
|
- const: fsl,imx7ulp-spi
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ description: |
|
|||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||||
|
- $ref: "/schemas/spi/spi-peripheral-props.yaml#"
|
||||||
|
|
||||||
maintainers:
|
maintainers:
|
||||||
- Chris Packham <chris.packham@alliedtelesis.co.nz>
|
- Chris Packham <chris.packham@alliedtelesis.co.nz>
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/spi/spi-peripheral-props.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Peripheral-specific properties for a SPI bus.
|
||||||
|
|
||||||
|
description:
|
||||||
|
Many SPI controllers need to add properties to peripheral devices. They could
|
||||||
|
be common properties like spi-max-frequency, spi-cpha, etc. or they could be
|
||||||
|
controller specific like delay in clock or data lines, etc. These properties
|
||||||
|
need to be defined in the peripheral node because they are per-peripheral and
|
||||||
|
there can be multiple peripherals attached to a controller. All those
|
||||||
|
properties are listed here. The controller specific properties should go in
|
||||||
|
their own separate schema that should be referenced from here.
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Pratyush Yadav <p.yadav@ti.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 256
|
||||||
|
items:
|
||||||
|
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:
|
||||||
|
description:
|
||||||
|
Bus width to the SPI bus used for read transfers.
|
||||||
|
If 0 is provided, then no RX will be possible on this device.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
enum: [0, 1, 2, 4, 8]
|
||||||
|
default: 1
|
||||||
|
|
||||||
|
spi-rx-delay-us:
|
||||||
|
description:
|
||||||
|
Delay, in microseconds, after a read transfer.
|
||||||
|
|
||||||
|
spi-tx-bus-width:
|
||||||
|
description:
|
||||||
|
Bus width to the SPI bus used for write transfers.
|
||||||
|
If 0 is provided, then no TX will be possible on this device.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
enum: [0, 1, 2, 4, 8]
|
||||||
|
default: 1
|
||||||
|
|
||||||
|
spi-tx-delay-us:
|
||||||
|
description:
|
||||||
|
Delay, in microseconds, after a write transfer.
|
||||||
|
|
||||||
|
# The controller specific properties go here.
|
||||||
|
allOf:
|
||||||
|
- $ref: cdns,qspi-nor-peripheral-props.yaml#
|
||||||
|
|
||||||
|
additionalProperties: true
|
@ -72,6 +72,9 @@ properties:
|
|||||||
- const: rx
|
- const: rx
|
||||||
- const: tx
|
- const: tx
|
||||||
|
|
||||||
|
resets:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
patternProperties:
|
patternProperties:
|
||||||
"^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$":
|
"^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$":
|
||||||
type: object
|
type: object
|
||||||
|
@ -101,8 +101,7 @@ device. All fields are optional.
|
|||||||
u8 rx_threshold;
|
u8 rx_threshold;
|
||||||
u8 dma_burst_size;
|
u8 dma_burst_size;
|
||||||
u32 timeout;
|
u32 timeout;
|
||||||
u8 enable_loopback;
|
int gpio_cs;
|
||||||
void (*cs_control)(u32 command);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are
|
The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are
|
||||||
@ -128,16 +127,6 @@ dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
|
|||||||
slave device. Please note that the PXA2xx SSP 1 does not support trailing byte
|
slave device. Please note that the PXA2xx SSP 1 does not support trailing byte
|
||||||
timeouts and must busy-wait any trailing bytes.
|
timeouts and must busy-wait any trailing bytes.
|
||||||
|
|
||||||
The "pxa2xx_spi_chip.enable_loopback" field is used to place the SSP porting
|
|
||||||
into internal loopback mode. In this mode the SSP controller internally
|
|
||||||
connects the SSPTX pin to the SSPRX pin. This is useful for initial setup
|
|
||||||
testing.
|
|
||||||
|
|
||||||
The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific
|
|
||||||
function for asserting/deasserting a slave device chip select. If the field is
|
|
||||||
NULL, the pxa2xx_spi master controller driver assumes that the SSP port is
|
|
||||||
configured to use GPIO or SSPFRM instead.
|
|
||||||
|
|
||||||
NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the
|
NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the
|
||||||
chipselect is dropped after each spi_transfer. Most devices need chip select
|
chipselect is dropped after each spi_transfer. Most devices need chip select
|
||||||
asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor)
|
asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor)
|
||||||
@ -152,30 +141,12 @@ field. Below is a sample configuration using the PXA255 NSSP.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
/* Chip Select control for the CS8415A SPI slave device */
|
|
||||||
static void cs8415a_cs_control(u32 command)
|
|
||||||
{
|
|
||||||
if (command & PXA2XX_CS_ASSERT)
|
|
||||||
GPCR(2) = GPIO_bit(2);
|
|
||||||
else
|
|
||||||
GPSR(2) = GPIO_bit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Chip Select control for the CS8405A SPI slave device */
|
|
||||||
static void cs8405a_cs_control(u32 command)
|
|
||||||
{
|
|
||||||
if (command & PXA2XX_CS_ASSERT)
|
|
||||||
GPCR(3) = GPIO_bit(3);
|
|
||||||
else
|
|
||||||
GPSR(3) = GPIO_bit(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct pxa2xx_spi_chip cs8415a_chip_info = {
|
static struct pxa2xx_spi_chip cs8415a_chip_info = {
|
||||||
.tx_threshold = 8, /* SSP hardward FIFO threshold */
|
.tx_threshold = 8, /* SSP hardward FIFO threshold */
|
||||||
.rx_threshold = 8, /* SSP hardward FIFO threshold */
|
.rx_threshold = 8, /* SSP hardward FIFO threshold */
|
||||||
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
||||||
.timeout = 235, /* See Intel documentation */
|
.timeout = 235, /* See Intel documentation */
|
||||||
.cs_control = cs8415a_cs_control, /* Use external chip select */
|
.gpio_cs = 2, /* Use external chip select */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pxa2xx_spi_chip cs8405a_chip_info = {
|
static struct pxa2xx_spi_chip cs8405a_chip_info = {
|
||||||
@ -183,7 +154,7 @@ field. Below is a sample configuration using the PXA255 NSSP.
|
|||||||
.rx_threshold = 8, /* SSP hardward FIFO threshold */
|
.rx_threshold = 8, /* SSP hardward FIFO threshold */
|
||||||
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
||||||
.timeout = 235, /* See Intel documentation */
|
.timeout = 235, /* See Intel documentation */
|
||||||
.cs_control = cs8405a_cs_control, /* Use external chip select */
|
.gpio_cs = 3, /* Use external chip select */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct spi_board_info streetracer_spi_board_info[] __initdata = {
|
static struct spi_board_info streetracer_spi_board_info[] __initdata = {
|
||||||
|
@ -29,21 +29,49 @@ of the driver stack) that are not accessible to userspace.
|
|||||||
|
|
||||||
DEVICE CREATION, DRIVER BINDING
|
DEVICE CREATION, DRIVER BINDING
|
||||||
===============================
|
===============================
|
||||||
The simplest way to arrange to use this driver is to just list it in the
|
|
||||||
spi_board_info for a device as the driver it should use: the "modalias"
|
|
||||||
entry is "spidev", matching the name of the driver exposing this API.
|
|
||||||
Set up the other device characteristics (bits per word, SPI clocking,
|
|
||||||
chipselect polarity, etc) as usual, so you won't always need to override
|
|
||||||
them later.
|
|
||||||
|
|
||||||
(Sysfs also supports userspace driven binding/unbinding of drivers to
|
The spidev driver contains lists of SPI devices that are supported for
|
||||||
devices. That mechanism might be supported here in the future.)
|
the different hardware topology representations.
|
||||||
|
|
||||||
When you do that, the sysfs node for the SPI device will include a child
|
The following are the SPI device tables supported by the spidev driver:
|
||||||
device node with a "dev" attribute that will be understood by udev or mdev.
|
|
||||||
(Larger systems will have "udev". Smaller ones may configure "mdev" into
|
- struct spi_device_id spidev_spi_ids[]: list of devices that can be
|
||||||
busybox; it's less featureful, but often enough.) For a SPI device with
|
bound when these are defined using a struct spi_board_info with a
|
||||||
chipselect C on bus B, you should see:
|
.modalias field matching one of the entries in the table.
|
||||||
|
|
||||||
|
- struct of_device_id spidev_dt_ids[]: list of devices that can be
|
||||||
|
bound when these are defined using a Device Tree node that has a
|
||||||
|
compatible string matching one of the entries in the table.
|
||||||
|
|
||||||
|
- struct acpi_device_id spidev_acpi_ids[]: list of devices that can
|
||||||
|
be bound when these are defined using a ACPI device object with a
|
||||||
|
_HID matching one of the entries in the table.
|
||||||
|
|
||||||
|
You are encouraged to add an entry for your SPI device name to relevant
|
||||||
|
tables, if these don't already have an entry for the device. To do that,
|
||||||
|
post a patch for spidev to the linux-spi@vger.kernel.org mailing list.
|
||||||
|
|
||||||
|
It used to be supported to define an SPI device using the "spidev" name.
|
||||||
|
For example, as .modalias = "spidev" or compatible = "spidev". But this
|
||||||
|
is no longer supported by the Linux kernel and instead a real SPI device
|
||||||
|
name as listed in one of the tables must be used.
|
||||||
|
|
||||||
|
Not having a real SPI device name will lead to an error being printed and
|
||||||
|
the spidev driver failing to probe.
|
||||||
|
|
||||||
|
Sysfs also supports userspace driven binding/unbinding of drivers to
|
||||||
|
devices that do not bind automatically using one of the tables above.
|
||||||
|
To make the spidev driver bind to such a device, use the following:
|
||||||
|
|
||||||
|
echo spidev > /sys/bus/spi/devices/spiB.C/driver_override
|
||||||
|
echo spiB.C > /sys/bus/spi/drivers/spidev/bind
|
||||||
|
|
||||||
|
When the spidev driver is bound to a SPI device, the sysfs node for the
|
||||||
|
device will include a child device node with a "dev" attribute that will
|
||||||
|
be understood by udev or mdev (udev replacement from BusyBox; it's less
|
||||||
|
featureful, but often enough).
|
||||||
|
|
||||||
|
For a SPI device with chipselect C on bus B, you should see:
|
||||||
|
|
||||||
/dev/spidevB.C ...
|
/dev/spidevB.C ...
|
||||||
character special device, major number 153 with
|
character special device, major number 153 with
|
||||||
|
@ -211,16 +211,17 @@ static struct ads7846_platform_data ads_info = {
|
|||||||
// .y_plate_ohms = 500, /* GUESS! */
|
// .y_plate_ohms = 500, /* GUESS! */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ads7846_cs(u32 command)
|
static struct gpiod_lookup_table ads7846_cs_gpios = {
|
||||||
{
|
.dev_id = "ads7846",
|
||||||
static const unsigned TS_nCS = 1 << 11;
|
.table = {
|
||||||
lubbock_set_misc_wr(TS_nCS, (command == PXA2XX_CS_ASSERT) ? 0 : TS_nCS);
|
GPIO_LOOKUP("lubbock", 11, "cs", GPIO_ACTIVE_LOW),
|
||||||
}
|
{}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static struct pxa2xx_spi_chip ads_hw = {
|
static struct pxa2xx_spi_chip ads_hw = {
|
||||||
.tx_threshold = 1,
|
.tx_threshold = 1,
|
||||||
.rx_threshold = 2,
|
.rx_threshold = 2,
|
||||||
.cs_control = ads7846_cs,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct spi_board_info spi_board_info[] __initdata = { {
|
static struct spi_board_info spi_board_info[] __initdata = { {
|
||||||
@ -512,6 +513,8 @@ static void __init lubbock_init(void)
|
|||||||
lubbock_flash_data[flashboot].name = "boot-rom";
|
lubbock_flash_data[flashboot].name = "boot-rom";
|
||||||
(void) platform_add_devices(devices, ARRAY_SIZE(devices));
|
(void) platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||||
|
|
||||||
|
gpiod_add_lookup_table(&ads7846_cs_gpios);
|
||||||
|
|
||||||
pxa2xx_set_spi_info(1, &pxa_ssp_master_info);
|
pxa2xx_set_spi_info(1, &pxa_ssp_master_info);
|
||||||
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
|
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ static struct pxa2xx_spi_controller pxa_ssp_master_2_info = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* An upcoming kernel change will scrap SFRM usage so these
|
/* An upcoming kernel change will scrap SFRM usage so these
|
||||||
* drivers have been moved to use gpio's via cs_control */
|
* drivers have been moved to use GPIOs */
|
||||||
static struct pxa2xx_spi_chip staccel_chip_info = {
|
static struct pxa2xx_spi_chip staccel_chip_info = {
|
||||||
.tx_threshold = 8,
|
.tx_threshold = 8,
|
||||||
.rx_threshold = 8,
|
.rx_threshold = 8,
|
||||||
|
@ -974,14 +974,13 @@ config SPI_XILINX
|
|||||||
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
|
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
|
||||||
|
|
||||||
config SPI_XLP
|
config SPI_XLP
|
||||||
tristate "Netlogic XLP SPI controller driver"
|
tristate "Cavium ThunderX2 SPI controller driver"
|
||||||
depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST
|
depends on ARCH_THUNDER2 || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Enable support for the SPI controller on the Netlogic XLP SoCs.
|
Enable support for the SPI controller on the Cavium ThunderX2.
|
||||||
Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX
|
(Originally on Netlogic XLP SoCs.)
|
||||||
and XLP5XX.
|
|
||||||
|
|
||||||
If you have a Netlogic XLP platform say Y here.
|
If you have a Cavium ThunderX2 platform say Y here.
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config SPI_XTENSA_XTFPGA
|
config SPI_XTENSA_XTFPGA
|
||||||
|
@ -82,7 +82,7 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
|
|||||||
struct spi_device *spi = m->spi;
|
struct spi_device *spi = m->spi;
|
||||||
unsigned long trx_done, trx_cur;
|
unsigned long trx_done, trx_cur;
|
||||||
int stat = 0;
|
int stat = 0;
|
||||||
u8 term = 0;
|
u8 bpw, term = 0;
|
||||||
int div, i;
|
int div, i;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
const u8 *tx_buf;
|
const u8 *tx_buf;
|
||||||
@ -90,6 +90,11 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
|
|||||||
|
|
||||||
m->actual_length = 0;
|
m->actual_length = 0;
|
||||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
|
if (t->bits_per_word >= 8 && t->bits_per_word < 32)
|
||||||
|
bpw = t->bits_per_word >> 3;
|
||||||
|
else
|
||||||
|
bpw = 4;
|
||||||
|
|
||||||
if (t->speed_hz)
|
if (t->speed_hz)
|
||||||
div = ar934x_spi_clk_div(sp, t->speed_hz);
|
div = ar934x_spi_clk_div(sp, t->speed_hz);
|
||||||
else
|
else
|
||||||
@ -105,10 +110,10 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
|
|||||||
iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL);
|
iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL);
|
||||||
iowrite32(0, sp->base + AR934X_SPI_DATAOUT);
|
iowrite32(0, sp->base + AR934X_SPI_DATAOUT);
|
||||||
|
|
||||||
for (trx_done = 0; trx_done < t->len; trx_done += 4) {
|
for (trx_done = 0; trx_done < t->len; trx_done += bpw) {
|
||||||
trx_cur = t->len - trx_done;
|
trx_cur = t->len - trx_done;
|
||||||
if (trx_cur > 4)
|
if (trx_cur > bpw)
|
||||||
trx_cur = 4;
|
trx_cur = bpw;
|
||||||
else if (list_is_last(&t->transfer_list, &m->transfers))
|
else if (list_is_last(&t->transfer_list, &m->transfers))
|
||||||
term = 1;
|
term = 1;
|
||||||
|
|
||||||
@ -137,8 +142,10 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
|
|||||||
reg >>= 8;
|
reg >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spi_delay_exec(&t->word_delay, t);
|
||||||
}
|
}
|
||||||
m->actual_length += t->len;
|
m->actual_length += t->len;
|
||||||
|
spi_transfer_delay_exec(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_done:
|
msg_done:
|
||||||
@ -191,7 +198,8 @@ static int ar934x_spi_probe(struct platform_device *pdev)
|
|||||||
ctlr->mode_bits = SPI_LSB_FIRST;
|
ctlr->mode_bits = SPI_LSB_FIRST;
|
||||||
ctlr->setup = ar934x_spi_setup;
|
ctlr->setup = ar934x_spi_setup;
|
||||||
ctlr->transfer_one_message = ar934x_spi_transfer_one_message;
|
ctlr->transfer_one_message = ar934x_spi_transfer_one_message;
|
||||||
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
|
ctlr->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
|
||||||
|
SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
|
||||||
ctlr->dev.of_node = pdev->dev.of_node;
|
ctlr->dev.of_node = pdev->dev.of_node;
|
||||||
ctlr->num_chipselect = 3;
|
ctlr->num_chipselect = 3;
|
||||||
|
|
||||||
|
@ -433,26 +433,25 @@ static bool atmel_spi_can_dma(struct spi_master *master,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int atmel_spi_dma_slave_config(struct atmel_spi *as,
|
static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
|
||||||
struct dma_slave_config *slave_config,
|
|
||||||
u8 bits_per_word)
|
|
||||||
{
|
{
|
||||||
struct spi_master *master = platform_get_drvdata(as->pdev);
|
struct spi_master *master = platform_get_drvdata(as->pdev);
|
||||||
|
struct dma_slave_config slave_config;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (bits_per_word > 8) {
|
if (bits_per_word > 8) {
|
||||||
slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||||
slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||||
} else {
|
} else {
|
||||||
slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||||
slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
slave_config->dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
|
slave_config.dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
|
||||||
slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR;
|
slave_config.src_addr = (dma_addr_t)as->phybase + SPI_RDR;
|
||||||
slave_config->src_maxburst = 1;
|
slave_config.src_maxburst = 1;
|
||||||
slave_config->dst_maxburst = 1;
|
slave_config.dst_maxburst = 1;
|
||||||
slave_config->device_fc = false;
|
slave_config.device_fc = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This driver uses fixed peripheral select mode (PS bit set to '0' in
|
* This driver uses fixed peripheral select mode (PS bit set to '0' in
|
||||||
@ -464,12 +463,11 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
|
|||||||
* However, the first data has to be written into the lowest 16 bits and
|
* However, the first data has to be written into the lowest 16 bits and
|
||||||
* the second data into the highest 16 bits of the Transmit
|
* the second data into the highest 16 bits of the Transmit
|
||||||
* Data Register. For 8bit data (the most frequent case), it would
|
* Data Register. For 8bit data (the most frequent case), it would
|
||||||
* require to rework tx_buf so each data would actualy fit 16 bits.
|
* require to rework tx_buf so each data would actually fit 16 bits.
|
||||||
* So we'd rather write only one data at the time. Hence the transmit
|
* So we'd rather write only one data at the time. Hence the transmit
|
||||||
* path works the same whether FIFOs are available (and enabled) or not.
|
* path works the same whether FIFOs are available (and enabled) or not.
|
||||||
*/
|
*/
|
||||||
slave_config->direction = DMA_MEM_TO_DEV;
|
if (dmaengine_slave_config(master->dma_tx, &slave_config)) {
|
||||||
if (dmaengine_slave_config(master->dma_tx, slave_config)) {
|
|
||||||
dev_err(&as->pdev->dev,
|
dev_err(&as->pdev->dev,
|
||||||
"failed to configure tx dma channel\n");
|
"failed to configure tx dma channel\n");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
@ -483,8 +481,7 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
|
|||||||
* So the receive path works the same whether FIFOs are available (and
|
* So the receive path works the same whether FIFOs are available (and
|
||||||
* enabled) or not.
|
* enabled) or not.
|
||||||
*/
|
*/
|
||||||
slave_config->direction = DMA_DEV_TO_MEM;
|
if (dmaengine_slave_config(master->dma_rx, &slave_config)) {
|
||||||
if (dmaengine_slave_config(master->dma_rx, slave_config)) {
|
|
||||||
dev_err(&as->pdev->dev,
|
dev_err(&as->pdev->dev,
|
||||||
"failed to configure rx dma channel\n");
|
"failed to configure rx dma channel\n");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
@ -496,7 +493,6 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
|
|||||||
static int atmel_spi_configure_dma(struct spi_master *master,
|
static int atmel_spi_configure_dma(struct spi_master *master,
|
||||||
struct atmel_spi *as)
|
struct atmel_spi *as)
|
||||||
{
|
{
|
||||||
struct dma_slave_config slave_config;
|
|
||||||
struct device *dev = &as->pdev->dev;
|
struct device *dev = &as->pdev->dev;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -518,7 +514,7 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = atmel_spi_dma_slave_config(as, &slave_config, 8);
|
err = atmel_spi_dma_slave_config(as, 8);
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -700,7 +696,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
|||||||
struct dma_chan *txchan = master->dma_tx;
|
struct dma_chan *txchan = master->dma_tx;
|
||||||
struct dma_async_tx_descriptor *rxdesc;
|
struct dma_async_tx_descriptor *rxdesc;
|
||||||
struct dma_async_tx_descriptor *txdesc;
|
struct dma_async_tx_descriptor *txdesc;
|
||||||
struct dma_slave_config slave_config;
|
|
||||||
dma_cookie_t cookie;
|
dma_cookie_t cookie;
|
||||||
|
|
||||||
dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n");
|
dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n");
|
||||||
@ -712,8 +707,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
|||||||
|
|
||||||
*plen = xfer->len;
|
*plen = xfer->len;
|
||||||
|
|
||||||
if (atmel_spi_dma_slave_config(as, &slave_config,
|
if (atmel_spi_dma_slave_config(as, xfer->bits_per_word))
|
||||||
xfer->bits_per_word))
|
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
|
|
||||||
/* Send both scatterlists */
|
/* Send both scatterlists */
|
||||||
|
@ -287,6 +287,18 @@ static inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi)
|
|||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 bcm_qspi_calc_spbr(u32 clk_speed_hz,
|
||||||
|
const struct bcm_qspi_parms *xp)
|
||||||
|
{
|
||||||
|
u32 spbr = 0;
|
||||||
|
|
||||||
|
/* SPBR = System Clock/(2 * SCK Baud Rate) */
|
||||||
|
if (xp->speed_hz)
|
||||||
|
spbr = clk_speed_hz / (xp->speed_hz * 2);
|
||||||
|
|
||||||
|
return spbr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read qspi controller register*/
|
/* Read qspi controller register*/
|
||||||
static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type,
|
static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type,
|
||||||
unsigned int offset)
|
unsigned int offset)
|
||||||
@ -586,12 +598,24 @@ static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs)
|
|||||||
qspi->curr_cs = cs;
|
qspi->curr_cs = cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool bcmspi_parms_did_change(const struct bcm_qspi_parms * const cur,
|
||||||
|
const struct bcm_qspi_parms * const prev)
|
||||||
|
{
|
||||||
|
return (cur->speed_hz != prev->speed_hz) ||
|
||||||
|
(cur->mode != prev->mode) ||
|
||||||
|
(cur->bits_per_word != prev->bits_per_word);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* MSPI helpers */
|
/* MSPI helpers */
|
||||||
static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
||||||
const struct bcm_qspi_parms *xp)
|
const struct bcm_qspi_parms *xp)
|
||||||
{
|
{
|
||||||
u32 spcr, spbr = 0;
|
u32 spcr, spbr = 0;
|
||||||
|
|
||||||
|
if (!bcmspi_parms_did_change(xp, &qspi->last_parms))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!qspi->mspi_maj_rev)
|
if (!qspi->mspi_maj_rev)
|
||||||
/* legacy controller */
|
/* legacy controller */
|
||||||
spcr = MSPI_MASTER_BIT;
|
spcr = MSPI_MASTER_BIT;
|
||||||
@ -621,9 +645,17 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
|||||||
spcr |= MSPI_SPCR3_HALFDUPLEX | MSPI_SPCR3_HDOUTTYPE;
|
spcr |= MSPI_SPCR3_HALFDUPLEX | MSPI_SPCR3_HDOUTTYPE;
|
||||||
|
|
||||||
if (bcm_qspi_has_sysclk_108(qspi)) {
|
if (bcm_qspi_has_sysclk_108(qspi)) {
|
||||||
/* SYSCLK_108 */
|
/* check requested baud rate before moving to 108Mhz */
|
||||||
spcr |= MSPI_SPCR3_SYSCLKSEL_108;
|
spbr = bcm_qspi_calc_spbr(MSPI_BASE_FREQ * 4, xp);
|
||||||
qspi->base_clk = MSPI_BASE_FREQ * 4;
|
if (spbr > QSPI_SPBR_MAX) {
|
||||||
|
/* use SYSCLK_27Mhz for slower baud rates */
|
||||||
|
spcr &= ~MSPI_SPCR3_SYSCLKSEL_MASK;
|
||||||
|
qspi->base_clk = MSPI_BASE_FREQ;
|
||||||
|
} else {
|
||||||
|
/* SYSCLK_108Mhz */
|
||||||
|
spcr |= MSPI_SPCR3_SYSCLKSEL_108;
|
||||||
|
qspi->base_clk = MSPI_BASE_FREQ * 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xp->bits_per_word > 16) {
|
if (xp->bits_per_word > 16) {
|
||||||
@ -649,9 +681,9 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
|||||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
|
bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xp->speed_hz)
|
/* SCK Baud Rate = System Clock/(2 * SPBR) */
|
||||||
spbr = qspi->base_clk / (2 * xp->speed_hz);
|
qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
|
||||||
|
spbr = bcm_qspi_calc_spbr(qspi->base_clk, xp);
|
||||||
spbr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
|
spbr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
|
||||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spbr);
|
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spbr);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/property.h>
|
||||||
#include <linux/mfd/dln2.h>
|
#include <linux/mfd/dln2.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
@ -688,6 +689,8 @@ static int dln2_spi_probe(struct platform_device *pdev)
|
|||||||
if (!master)
|
if (!master)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
device_set_node(&master->dev, dev_fwnode(dev));
|
||||||
|
|
||||||
platform_set_drvdata(pdev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
dln2 = spi_master_get_devdata(master);
|
dln2 = spi_master_get_devdata(master);
|
||||||
@ -699,7 +702,6 @@ static int dln2_spi_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dln2->master = master;
|
dln2->master = master;
|
||||||
dln2->master->dev.of_node = dev->of_node;
|
|
||||||
dln2->pdev = pdev;
|
dln2->pdev = pdev;
|
||||||
dln2->port = pdata->port;
|
dln2->port = pdata->port;
|
||||||
/* cs/mode can never be 0xff, so the first transfer will set them */
|
/* cs/mode can never be 0xff, so the first transfer will set them */
|
||||||
|
@ -123,7 +123,7 @@ static ssize_t dw_spi_bt1_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
|||||||
len = min_t(size_t, len, dwsbt1->map_len - offs);
|
len = min_t(size_t, len, dwsbt1->map_len - offs);
|
||||||
|
|
||||||
/* Collect the controller configuration required by the operation */
|
/* Collect the controller configuration required by the operation */
|
||||||
cfg.tmode = SPI_TMOD_EPROMREAD;
|
cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;
|
||||||
cfg.dfs = 8;
|
cfg.dfs = 8;
|
||||||
cfg.ndf = 4;
|
cfg.ndf = 4;
|
||||||
cfg.freq = mem->spi->max_speed_hz;
|
cfg.freq = mem->spi->max_speed_hz;
|
||||||
@ -131,13 +131,13 @@ static ssize_t dw_spi_bt1_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
|||||||
/* Make sure the corresponding CS is de-asserted on transmission */
|
/* Make sure the corresponding CS is de-asserted on transmission */
|
||||||
dw_spi_set_cs(mem->spi, false);
|
dw_spi_set_cs(mem->spi, false);
|
||||||
|
|
||||||
spi_enable_chip(dws, 0);
|
dw_spi_enable_chip(dws, 0);
|
||||||
|
|
||||||
dw_spi_update_config(dws, mem->spi, &cfg);
|
dw_spi_update_config(dws, mem->spi, &cfg);
|
||||||
|
|
||||||
spi_umask_intr(dws, SPI_INT_RXFI);
|
dw_spi_umask_intr(dws, DW_SPI_INT_RXFI);
|
||||||
|
|
||||||
spi_enable_chip(dws, 1);
|
dw_spi_enable_chip(dws, 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable the transparent mode of the System Boot Controller.
|
* Enable the transparent mode of the System Boot Controller.
|
||||||
@ -339,3 +339,4 @@ module_platform_driver(dw_spi_bt1_driver);
|
|||||||
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
|
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
|
||||||
MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver");
|
MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_IMPORT_NS(SPI_DW_CORE);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* Copyright (c) 2009, Intel Corporation.
|
* Copyright (c) 2009, Intel Corporation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@ -24,7 +25,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Slave spi_device related */
|
/* Slave spi_device related */
|
||||||
struct chip_data {
|
struct dw_spi_chip_data {
|
||||||
u32 cr0;
|
u32 cr0;
|
||||||
u32 rx_sample_dly; /* RX sample delay */
|
u32 rx_sample_dly; /* RX sample delay */
|
||||||
};
|
};
|
||||||
@ -106,10 +107,10 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
|
|||||||
else
|
else
|
||||||
dw_writel(dws, DW_SPI_SER, 0);
|
dw_writel(dws, DW_SPI_SER, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_set_cs);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_set_cs, SPI_DW_CORE);
|
||||||
|
|
||||||
/* Return the max entries we can fill into tx fifo */
|
/* Return the max entries we can fill into tx fifo */
|
||||||
static inline u32 tx_max(struct dw_spi *dws)
|
static inline u32 dw_spi_tx_max(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
u32 tx_room, rxtx_gap;
|
u32 tx_room, rxtx_gap;
|
||||||
|
|
||||||
@ -129,14 +130,14 @@ static inline u32 tx_max(struct dw_spi *dws)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return the max entries we should read out of rx fifo */
|
/* Return the max entries we should read out of rx fifo */
|
||||||
static inline u32 rx_max(struct dw_spi *dws)
|
static inline u32 dw_spi_rx_max(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
return min_t(u32, dws->rx_len, dw_readl(dws, DW_SPI_RXFLR));
|
return min_t(u32, dws->rx_len, dw_readl(dws, DW_SPI_RXFLR));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dw_writer(struct dw_spi *dws)
|
static void dw_writer(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
u32 max = tx_max(dws);
|
u32 max = dw_spi_tx_max(dws);
|
||||||
u32 txw = 0;
|
u32 txw = 0;
|
||||||
|
|
||||||
while (max--) {
|
while (max--) {
|
||||||
@ -157,7 +158,7 @@ static void dw_writer(struct dw_spi *dws)
|
|||||||
|
|
||||||
static void dw_reader(struct dw_spi *dws)
|
static void dw_reader(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
u32 max = rx_max(dws);
|
u32 max = dw_spi_rx_max(dws);
|
||||||
u32 rxw;
|
u32 rxw;
|
||||||
|
|
||||||
while (max--) {
|
while (max--) {
|
||||||
@ -186,31 +187,31 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw)
|
|||||||
else
|
else
|
||||||
irq_status = dw_readl(dws, DW_SPI_ISR);
|
irq_status = dw_readl(dws, DW_SPI_ISR);
|
||||||
|
|
||||||
if (irq_status & SPI_INT_RXOI) {
|
if (irq_status & DW_SPI_INT_RXOI) {
|
||||||
dev_err(&dws->master->dev, "RX FIFO overflow detected\n");
|
dev_err(&dws->master->dev, "RX FIFO overflow detected\n");
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (irq_status & SPI_INT_RXUI) {
|
if (irq_status & DW_SPI_INT_RXUI) {
|
||||||
dev_err(&dws->master->dev, "RX FIFO underflow detected\n");
|
dev_err(&dws->master->dev, "RX FIFO underflow detected\n");
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (irq_status & SPI_INT_TXOI) {
|
if (irq_status & DW_SPI_INT_TXOI) {
|
||||||
dev_err(&dws->master->dev, "TX FIFO overflow detected\n");
|
dev_err(&dws->master->dev, "TX FIFO overflow detected\n");
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generically handle the erroneous situation */
|
/* Generically handle the erroneous situation */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
spi_reset_chip(dws);
|
dw_spi_reset_chip(dws);
|
||||||
if (dws->master->cur_msg)
|
if (dws->master->cur_msg)
|
||||||
dws->master->cur_msg->status = ret;
|
dws->master->cur_msg->status = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_check_status);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE);
|
||||||
|
|
||||||
static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
|
static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
@ -230,7 +231,7 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
|
|||||||
*/
|
*/
|
||||||
dw_reader(dws);
|
dw_reader(dws);
|
||||||
if (!dws->rx_len) {
|
if (!dws->rx_len) {
|
||||||
spi_mask_intr(dws, 0xff);
|
dw_spi_mask_intr(dws, 0xff);
|
||||||
spi_finalize_current_transfer(dws->master);
|
spi_finalize_current_transfer(dws->master);
|
||||||
} else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
|
} else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
|
||||||
dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
|
dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
|
||||||
@ -241,10 +242,10 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
|
|||||||
* disabled after the data transmission is finished so not to
|
* disabled after the data transmission is finished so not to
|
||||||
* have the TXE IRQ flood at the final stage of the transfer.
|
* have the TXE IRQ flood at the final stage of the transfer.
|
||||||
*/
|
*/
|
||||||
if (irq_status & SPI_INT_TXEI) {
|
if (irq_status & DW_SPI_INT_TXEI) {
|
||||||
dw_writer(dws);
|
dw_writer(dws);
|
||||||
if (!dws->tx_len)
|
if (!dws->tx_len)
|
||||||
spi_mask_intr(dws, SPI_INT_TXEI);
|
dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
@ -254,13 +255,13 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
|
|||||||
{
|
{
|
||||||
struct spi_controller *master = dev_id;
|
struct spi_controller *master = dev_id;
|
||||||
struct dw_spi *dws = spi_controller_get_devdata(master);
|
struct dw_spi *dws = spi_controller_get_devdata(master);
|
||||||
u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f;
|
u16 irq_status = dw_readl(dws, DW_SPI_ISR) & DW_SPI_INT_MASK;
|
||||||
|
|
||||||
if (!irq_status)
|
if (!irq_status)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
if (!master->cur_msg) {
|
if (!master->cur_msg) {
|
||||||
spi_mask_intr(dws, 0xff);
|
dw_spi_mask_intr(dws, 0xff);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,37 +272,43 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
|
|||||||
{
|
{
|
||||||
u32 cr0 = 0;
|
u32 cr0 = 0;
|
||||||
|
|
||||||
if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) {
|
if (dw_spi_ip_is(dws, PSSI)) {
|
||||||
/* CTRLR0[ 5: 4] Frame Format */
|
/* CTRLR0[ 5: 4] Frame Format */
|
||||||
cr0 |= SSI_MOTO_SPI << SPI_FRF_OFFSET;
|
cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_FRF_MASK, DW_SPI_CTRLR0_FRF_MOTO_SPI);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SPI mode (SCPOL|SCPH)
|
* SPI mode (SCPOL|SCPH)
|
||||||
* CTRLR0[ 6] Serial Clock Phase
|
* CTRLR0[ 6] Serial Clock Phase
|
||||||
* CTRLR0[ 7] Serial Clock Polarity
|
* CTRLR0[ 7] Serial Clock Polarity
|
||||||
*/
|
*/
|
||||||
cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET;
|
if (spi->mode & SPI_CPOL)
|
||||||
cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET;
|
cr0 |= DW_PSSI_CTRLR0_SCPOL;
|
||||||
|
if (spi->mode & SPI_CPHA)
|
||||||
|
cr0 |= DW_PSSI_CTRLR0_SCPHA;
|
||||||
|
|
||||||
/* CTRLR0[11] Shift Register Loop */
|
/* CTRLR0[11] Shift Register Loop */
|
||||||
cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET;
|
if (spi->mode & SPI_LOOP)
|
||||||
|
cr0 |= DW_PSSI_CTRLR0_SRL;
|
||||||
} else {
|
} else {
|
||||||
/* CTRLR0[ 7: 6] Frame Format */
|
/* CTRLR0[ 7: 6] Frame Format */
|
||||||
cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
|
cr0 |= FIELD_PREP(DW_HSSI_CTRLR0_FRF_MASK, DW_SPI_CTRLR0_FRF_MOTO_SPI);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SPI mode (SCPOL|SCPH)
|
* SPI mode (SCPOL|SCPH)
|
||||||
* CTRLR0[ 8] Serial Clock Phase
|
* CTRLR0[ 8] Serial Clock Phase
|
||||||
* CTRLR0[ 9] Serial Clock Polarity
|
* CTRLR0[ 9] Serial Clock Polarity
|
||||||
*/
|
*/
|
||||||
cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
|
if (spi->mode & SPI_CPOL)
|
||||||
cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
|
cr0 |= DW_HSSI_CTRLR0_SCPOL;
|
||||||
|
if (spi->mode & SPI_CPHA)
|
||||||
|
cr0 |= DW_HSSI_CTRLR0_SCPHA;
|
||||||
|
|
||||||
/* CTRLR0[13] Shift Register Loop */
|
/* CTRLR0[13] Shift Register Loop */
|
||||||
cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET;
|
if (spi->mode & SPI_LOOP)
|
||||||
|
cr0 |= DW_HSSI_CTRLR0_SRL;
|
||||||
|
|
||||||
if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
|
if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
|
||||||
cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST;
|
cr0 |= DW_HSSI_CTRLR0_KEEMBAY_MST;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cr0;
|
return cr0;
|
||||||
@ -310,7 +317,7 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
|
|||||||
void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
|
void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
|
||||||
struct dw_spi_cfg *cfg)
|
struct dw_spi_cfg *cfg)
|
||||||
{
|
{
|
||||||
struct chip_data *chip = spi_get_ctldata(spi);
|
struct dw_spi_chip_data *chip = spi_get_ctldata(spi);
|
||||||
u32 cr0 = chip->cr0;
|
u32 cr0 = chip->cr0;
|
||||||
u32 speed_hz;
|
u32 speed_hz;
|
||||||
u16 clk_div;
|
u16 clk_div;
|
||||||
@ -318,16 +325,17 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
|
|||||||
/* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */
|
/* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */
|
||||||
cr0 |= (cfg->dfs - 1) << dws->dfs_offset;
|
cr0 |= (cfg->dfs - 1) << dws->dfs_offset;
|
||||||
|
|
||||||
if (!(dws->caps & DW_SPI_CAP_DWC_SSI))
|
if (dw_spi_ip_is(dws, PSSI))
|
||||||
/* CTRLR0[ 9:8] Transfer Mode */
|
/* CTRLR0[ 9:8] Transfer Mode */
|
||||||
cr0 |= cfg->tmode << SPI_TMOD_OFFSET;
|
cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_TMOD_MASK, cfg->tmode);
|
||||||
else
|
else
|
||||||
/* CTRLR0[11:10] Transfer Mode */
|
/* CTRLR0[11:10] Transfer Mode */
|
||||||
cr0 |= cfg->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
|
cr0 |= FIELD_PREP(DW_HSSI_CTRLR0_TMOD_MASK, cfg->tmode);
|
||||||
|
|
||||||
dw_writel(dws, DW_SPI_CTRLR0, cr0);
|
dw_writel(dws, DW_SPI_CTRLR0, cr0);
|
||||||
|
|
||||||
if (cfg->tmode == SPI_TMOD_EPROMREAD || cfg->tmode == SPI_TMOD_RO)
|
if (cfg->tmode == DW_SPI_CTRLR0_TMOD_EPROMREAD ||
|
||||||
|
cfg->tmode == DW_SPI_CTRLR0_TMOD_RO)
|
||||||
dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
|
dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
|
||||||
|
|
||||||
/* Note DW APB SSI clock divider doesn't support odd numbers */
|
/* Note DW APB SSI clock divider doesn't support odd numbers */
|
||||||
@ -335,7 +343,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
|
|||||||
speed_hz = dws->max_freq / clk_div;
|
speed_hz = dws->max_freq / clk_div;
|
||||||
|
|
||||||
if (dws->current_freq != speed_hz) {
|
if (dws->current_freq != speed_hz) {
|
||||||
spi_set_clk(dws, clk_div);
|
dw_spi_set_clk(dws, clk_div);
|
||||||
dws->current_freq = speed_hz;
|
dws->current_freq = speed_hz;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +353,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
|
|||||||
dws->cur_rx_sample_dly = chip->rx_sample_dly;
|
dws->cur_rx_sample_dly = chip->rx_sample_dly;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_update_config);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_update_config, SPI_DW_CORE);
|
||||||
|
|
||||||
static void dw_spi_irq_setup(struct dw_spi *dws)
|
static void dw_spi_irq_setup(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
@ -363,9 +371,9 @@ static void dw_spi_irq_setup(struct dw_spi *dws)
|
|||||||
|
|
||||||
dws->transfer_handler = dw_spi_transfer_handler;
|
dws->transfer_handler = dw_spi_transfer_handler;
|
||||||
|
|
||||||
imask = SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI |
|
imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI |
|
||||||
SPI_INT_RXFI;
|
DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI;
|
||||||
spi_umask_intr(dws, imask);
|
dw_spi_umask_intr(dws, imask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -405,11 +413,12 @@ static int dw_spi_poll_transfer(struct dw_spi *dws,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int dw_spi_transfer_one(struct spi_controller *master,
|
static int dw_spi_transfer_one(struct spi_controller *master,
|
||||||
struct spi_device *spi, struct spi_transfer *transfer)
|
struct spi_device *spi,
|
||||||
|
struct spi_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = spi_controller_get_devdata(master);
|
struct dw_spi *dws = spi_controller_get_devdata(master);
|
||||||
struct dw_spi_cfg cfg = {
|
struct dw_spi_cfg cfg = {
|
||||||
.tmode = SPI_TMOD_TR,
|
.tmode = DW_SPI_CTRLR0_TMOD_TR,
|
||||||
.dfs = transfer->bits_per_word,
|
.dfs = transfer->bits_per_word,
|
||||||
.freq = transfer->speed_hz,
|
.freq = transfer->speed_hz,
|
||||||
};
|
};
|
||||||
@ -425,7 +434,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
|
|||||||
/* Ensure the data above is visible for all CPUs */
|
/* Ensure the data above is visible for all CPUs */
|
||||||
smp_mb();
|
smp_mb();
|
||||||
|
|
||||||
spi_enable_chip(dws, 0);
|
dw_spi_enable_chip(dws, 0);
|
||||||
|
|
||||||
dw_spi_update_config(dws, spi, &cfg);
|
dw_spi_update_config(dws, spi, &cfg);
|
||||||
|
|
||||||
@ -436,7 +445,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
|
|||||||
dws->dma_mapped = master->cur_msg_mapped;
|
dws->dma_mapped = master->cur_msg_mapped;
|
||||||
|
|
||||||
/* For poll mode just disable all interrupts */
|
/* For poll mode just disable all interrupts */
|
||||||
spi_mask_intr(dws, 0xff);
|
dw_spi_mask_intr(dws, 0xff);
|
||||||
|
|
||||||
if (dws->dma_mapped) {
|
if (dws->dma_mapped) {
|
||||||
ret = dws->dma_ops->dma_setup(dws, transfer);
|
ret = dws->dma_ops->dma_setup(dws, transfer);
|
||||||
@ -444,7 +453,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_enable_chip(dws, 1);
|
dw_spi_enable_chip(dws, 1);
|
||||||
|
|
||||||
if (dws->dma_mapped)
|
if (dws->dma_mapped)
|
||||||
return dws->dma_ops->dma_transfer(dws, transfer);
|
return dws->dma_ops->dma_transfer(dws, transfer);
|
||||||
@ -457,20 +466,20 @@ static int dw_spi_transfer_one(struct spi_controller *master,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void dw_spi_handle_err(struct spi_controller *master,
|
static void dw_spi_handle_err(struct spi_controller *master,
|
||||||
struct spi_message *msg)
|
struct spi_message *msg)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = spi_controller_get_devdata(master);
|
struct dw_spi *dws = spi_controller_get_devdata(master);
|
||||||
|
|
||||||
if (dws->dma_mapped)
|
if (dws->dma_mapped)
|
||||||
dws->dma_ops->dma_stop(dws);
|
dws->dma_ops->dma_stop(dws);
|
||||||
|
|
||||||
spi_reset_chip(dws);
|
dw_spi_reset_chip(dws);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
|
static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
|
||||||
{
|
{
|
||||||
if (op->data.dir == SPI_MEM_DATA_IN)
|
if (op->data.dir == SPI_MEM_DATA_IN)
|
||||||
op->data.nbytes = clamp_val(op->data.nbytes, 0, SPI_NDF_MASK + 1);
|
op->data.nbytes = clamp_val(op->data.nbytes, 0, DW_SPI_NDF_MASK + 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -498,7 +507,7 @@ static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op)
|
|||||||
if (op->data.dir == SPI_MEM_DATA_OUT)
|
if (op->data.dir == SPI_MEM_DATA_OUT)
|
||||||
len += op->data.nbytes;
|
len += op->data.nbytes;
|
||||||
|
|
||||||
if (len <= SPI_BUF_SIZE) {
|
if (len <= DW_SPI_BUF_SIZE) {
|
||||||
out = dws->buf;
|
out = dws->buf;
|
||||||
} else {
|
} else {
|
||||||
out = kzalloc(len, GFP_KERNEL);
|
out = kzalloc(len, GFP_KERNEL);
|
||||||
@ -512,9 +521,9 @@ static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op)
|
|||||||
* single buffer in order to speed the data transmission up.
|
* single buffer in order to speed the data transmission up.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < op->cmd.nbytes; ++i)
|
for (i = 0; i < op->cmd.nbytes; ++i)
|
||||||
out[i] = SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1);
|
out[i] = DW_SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1);
|
||||||
for (j = 0; j < op->addr.nbytes; ++i, ++j)
|
for (j = 0; j < op->addr.nbytes; ++i, ++j)
|
||||||
out[i] = SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1);
|
out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1);
|
||||||
for (j = 0; j < op->dummy.nbytes; ++i, ++j)
|
for (j = 0; j < op->dummy.nbytes; ++i, ++j)
|
||||||
out[i] = 0x0;
|
out[i] = 0x0;
|
||||||
|
|
||||||
@ -587,7 +596,7 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
|
|||||||
entries = readl_relaxed(dws->regs + DW_SPI_RXFLR);
|
entries = readl_relaxed(dws->regs + DW_SPI_RXFLR);
|
||||||
if (!entries) {
|
if (!entries) {
|
||||||
sts = readl_relaxed(dws->regs + DW_SPI_RISR);
|
sts = readl_relaxed(dws->regs + DW_SPI_RISR);
|
||||||
if (sts & SPI_INT_RXOI) {
|
if (sts & DW_SPI_INT_RXOI) {
|
||||||
dev_err(&dws->master->dev, "FIFO overflow on Rx\n");
|
dev_err(&dws->master->dev, "FIFO overflow on Rx\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
@ -603,12 +612,12 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
|
|||||||
|
|
||||||
static inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
|
static inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
return dw_readl(dws, DW_SPI_SR) & SR_BUSY;
|
return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
|
static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
int retry = SPI_WAIT_RETRIES;
|
int retry = DW_SPI_WAIT_RETRIES;
|
||||||
struct spi_delay delay;
|
struct spi_delay delay;
|
||||||
unsigned long ns, us;
|
unsigned long ns, us;
|
||||||
u32 nents;
|
u32 nents;
|
||||||
@ -638,9 +647,9 @@ static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
|
|||||||
|
|
||||||
static void dw_spi_stop_mem_op(struct dw_spi *dws, struct spi_device *spi)
|
static void dw_spi_stop_mem_op(struct dw_spi *dws, struct spi_device *spi)
|
||||||
{
|
{
|
||||||
spi_enable_chip(dws, 0);
|
dw_spi_enable_chip(dws, 0);
|
||||||
dw_spi_set_cs(spi, true);
|
dw_spi_set_cs(spi, true);
|
||||||
spi_enable_chip(dws, 1);
|
dw_spi_enable_chip(dws, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -673,19 +682,19 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
|||||||
cfg.dfs = 8;
|
cfg.dfs = 8;
|
||||||
cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq);
|
cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq);
|
||||||
if (op->data.dir == SPI_MEM_DATA_IN) {
|
if (op->data.dir == SPI_MEM_DATA_IN) {
|
||||||
cfg.tmode = SPI_TMOD_EPROMREAD;
|
cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;
|
||||||
cfg.ndf = op->data.nbytes;
|
cfg.ndf = op->data.nbytes;
|
||||||
} else {
|
} else {
|
||||||
cfg.tmode = SPI_TMOD_TO;
|
cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_enable_chip(dws, 0);
|
dw_spi_enable_chip(dws, 0);
|
||||||
|
|
||||||
dw_spi_update_config(dws, mem->spi, &cfg);
|
dw_spi_update_config(dws, mem->spi, &cfg);
|
||||||
|
|
||||||
spi_mask_intr(dws, 0xff);
|
dw_spi_mask_intr(dws, 0xff);
|
||||||
|
|
||||||
spi_enable_chip(dws, 1);
|
dw_spi_enable_chip(dws, 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DW APB SSI controller has very nasty peculiarities. First originally
|
* DW APB SSI controller has very nasty peculiarities. First originally
|
||||||
@ -768,7 +777,7 @@ static void dw_spi_init_mem_ops(struct dw_spi *dws)
|
|||||||
static int dw_spi_setup(struct spi_device *spi)
|
static int dw_spi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
|
struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
|
||||||
struct chip_data *chip;
|
struct dw_spi_chip_data *chip;
|
||||||
|
|
||||||
/* Only alloc on first setup */
|
/* Only alloc on first setup */
|
||||||
chip = spi_get_ctldata(spi);
|
chip = spi_get_ctldata(spi);
|
||||||
@ -776,7 +785,7 @@ static int dw_spi_setup(struct spi_device *spi)
|
|||||||
struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
|
struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
|
||||||
u32 rx_sample_dly_ns;
|
u32 rx_sample_dly_ns;
|
||||||
|
|
||||||
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
|
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||||
if (!chip)
|
if (!chip)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
spi_set_ctldata(spi, chip);
|
spi_set_ctldata(spi, chip);
|
||||||
@ -803,16 +812,30 @@ static int dw_spi_setup(struct spi_device *spi)
|
|||||||
|
|
||||||
static void dw_spi_cleanup(struct spi_device *spi)
|
static void dw_spi_cleanup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct chip_data *chip = spi_get_ctldata(spi);
|
struct dw_spi_chip_data *chip = spi_get_ctldata(spi);
|
||||||
|
|
||||||
kfree(chip);
|
kfree(chip);
|
||||||
spi_set_ctldata(spi, NULL);
|
spi_set_ctldata(spi, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restart the controller, disable all interrupts, clean rx fifo */
|
/* Restart the controller, disable all interrupts, clean rx fifo */
|
||||||
static void spi_hw_init(struct device *dev, struct dw_spi *dws)
|
static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
spi_reset_chip(dws);
|
dw_spi_reset_chip(dws);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve the Synopsys component version if it hasn't been specified
|
||||||
|
* by the platform. CoreKit version ID is encoded as a 3-chars ASCII
|
||||||
|
* code enclosed with '*' (typical for the most of Synopsys IP-cores).
|
||||||
|
*/
|
||||||
|
if (!dws->ver) {
|
||||||
|
dws->ver = dw_readl(dws, DW_SPI_VERSION);
|
||||||
|
|
||||||
|
dev_dbg(dev, "Synopsys DWC%sSSI v%c.%c%c\n",
|
||||||
|
dw_spi_ip_is(dws, PSSI) ? " APB " : " ",
|
||||||
|
DW_SPI_GET_BYTE(dws->ver, 3), DW_SPI_GET_BYTE(dws->ver, 2),
|
||||||
|
DW_SPI_GET_BYTE(dws->ver, 1));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to detect the FIFO depth if not set by interface driver,
|
* Try to detect the FIFO depth if not set by interface driver,
|
||||||
@ -837,18 +860,18 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
|
|||||||
* writability. Note DWC SSI controller also has the extended DFS, but
|
* writability. Note DWC SSI controller also has the extended DFS, but
|
||||||
* with zero offset.
|
* with zero offset.
|
||||||
*/
|
*/
|
||||||
if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) {
|
if (dw_spi_ip_is(dws, PSSI)) {
|
||||||
u32 cr0, tmp = dw_readl(dws, DW_SPI_CTRLR0);
|
u32 cr0, tmp = dw_readl(dws, DW_SPI_CTRLR0);
|
||||||
|
|
||||||
spi_enable_chip(dws, 0);
|
dw_spi_enable_chip(dws, 0);
|
||||||
dw_writel(dws, DW_SPI_CTRLR0, 0xffffffff);
|
dw_writel(dws, DW_SPI_CTRLR0, 0xffffffff);
|
||||||
cr0 = dw_readl(dws, DW_SPI_CTRLR0);
|
cr0 = dw_readl(dws, DW_SPI_CTRLR0);
|
||||||
dw_writel(dws, DW_SPI_CTRLR0, tmp);
|
dw_writel(dws, DW_SPI_CTRLR0, tmp);
|
||||||
spi_enable_chip(dws, 1);
|
dw_spi_enable_chip(dws, 1);
|
||||||
|
|
||||||
if (!(cr0 & SPI_DFS_MASK)) {
|
if (!(cr0 & DW_PSSI_CTRLR0_DFS_MASK)) {
|
||||||
dws->caps |= DW_SPI_CAP_DFS32;
|
dws->caps |= DW_SPI_CAP_DFS32;
|
||||||
dws->dfs_offset = SPI_DFS32_OFFSET;
|
dws->dfs_offset = __bf_shf(DW_PSSI_CTRLR0_DFS32_MASK);
|
||||||
dev_dbg(dev, "Detected 32-bits max data frame size\n");
|
dev_dbg(dev, "Detected 32-bits max data frame size\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -872,13 +895,15 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
|||||||
if (!master)
|
if (!master)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
device_set_node(&master->dev, dev_fwnode(dev));
|
||||||
|
|
||||||
dws->master = master;
|
dws->master = master;
|
||||||
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
|
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
|
||||||
|
|
||||||
spi_controller_set_devdata(master, dws);
|
spi_controller_set_devdata(master, dws);
|
||||||
|
|
||||||
/* Basic HW init */
|
/* Basic HW init */
|
||||||
spi_hw_init(dev, dws);
|
dw_spi_hw_init(dev, dws);
|
||||||
|
|
||||||
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
|
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
|
||||||
master);
|
master);
|
||||||
@ -908,8 +933,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
|||||||
if (dws->mem_ops.exec_op)
|
if (dws->mem_ops.exec_op)
|
||||||
master->mem_ops = &dws->mem_ops;
|
master->mem_ops = &dws->mem_ops;
|
||||||
master->max_speed_hz = dws->max_freq;
|
master->max_speed_hz = dws->max_freq;
|
||||||
master->dev.of_node = dev->of_node;
|
|
||||||
master->dev.fwnode = dev->fwnode;
|
|
||||||
master->flags = SPI_MASTER_GPIO_SS;
|
master->flags = SPI_MASTER_GPIO_SS;
|
||||||
master->auto_runtime_pm = true;
|
master->auto_runtime_pm = true;
|
||||||
|
|
||||||
@ -939,13 +962,13 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
|||||||
err_dma_exit:
|
err_dma_exit:
|
||||||
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
||||||
dws->dma_ops->dma_exit(dws);
|
dws->dma_ops->dma_exit(dws);
|
||||||
spi_enable_chip(dws, 0);
|
dw_spi_enable_chip(dws, 0);
|
||||||
free_irq(dws->irq, master);
|
free_irq(dws->irq, master);
|
||||||
err_free_master:
|
err_free_master:
|
||||||
spi_controller_put(master);
|
spi_controller_put(master);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_add_host);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, SPI_DW_CORE);
|
||||||
|
|
||||||
void dw_spi_remove_host(struct dw_spi *dws)
|
void dw_spi_remove_host(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
@ -956,11 +979,11 @@ void dw_spi_remove_host(struct dw_spi *dws)
|
|||||||
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
||||||
dws->dma_ops->dma_exit(dws);
|
dws->dma_ops->dma_exit(dws);
|
||||||
|
|
||||||
spi_shutdown_chip(dws);
|
dw_spi_shutdown_chip(dws);
|
||||||
|
|
||||||
free_irq(dws->irq, dws->master);
|
free_irq(dws->irq, dws->master);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_remove_host);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, SPI_DW_CORE);
|
||||||
|
|
||||||
int dw_spi_suspend_host(struct dw_spi *dws)
|
int dw_spi_suspend_host(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
@ -970,17 +993,17 @@ int dw_spi_suspend_host(struct dw_spi *dws)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
spi_shutdown_chip(dws);
|
dw_spi_shutdown_chip(dws);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_host, SPI_DW_CORE);
|
||||||
|
|
||||||
int dw_spi_resume_host(struct dw_spi *dws)
|
int dw_spi_resume_host(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
spi_hw_init(&dws->master->dev, dws);
|
dw_spi_hw_init(&dws->master->dev, dws);
|
||||||
return spi_controller_resume(dws->master);
|
return spi_controller_resume(dws->master);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_resume_host);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, SPI_DW_CORE);
|
||||||
|
|
||||||
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
|
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
|
||||||
MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
|
MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <linux/dmaengine.h>
|
#include <linux/dmaengine.h>
|
||||||
#include <linux/irqreturn.h>
|
#include <linux/irqreturn.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/platform_data/dma-dw.h>
|
#include <linux/platform_data/dma-dw.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
@ -17,10 +18,10 @@
|
|||||||
|
|
||||||
#include "spi-dw.h"
|
#include "spi-dw.h"
|
||||||
|
|
||||||
#define RX_BUSY 0
|
#define DW_SPI_RX_BUSY 0
|
||||||
#define RX_BURST_LEVEL 16
|
#define DW_SPI_RX_BURST_LEVEL 16
|
||||||
#define TX_BUSY 1
|
#define DW_SPI_TX_BUSY 1
|
||||||
#define TX_BURST_LEVEL 16
|
#define DW_SPI_TX_BURST_LEVEL 16
|
||||||
|
|
||||||
static bool dw_spi_dma_chan_filter(struct dma_chan *chan, void *param)
|
static bool dw_spi_dma_chan_filter(struct dma_chan *chan, void *param)
|
||||||
{
|
{
|
||||||
@ -45,7 +46,7 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
|
|||||||
if (!ret && caps.max_burst)
|
if (!ret && caps.max_burst)
|
||||||
max_burst = caps.max_burst;
|
max_burst = caps.max_burst;
|
||||||
else
|
else
|
||||||
max_burst = RX_BURST_LEVEL;
|
max_burst = DW_SPI_RX_BURST_LEVEL;
|
||||||
|
|
||||||
dws->rxburst = min(max_burst, def_burst);
|
dws->rxburst = min(max_burst, def_burst);
|
||||||
dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
|
dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
|
||||||
@ -54,7 +55,7 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
|
|||||||
if (!ret && caps.max_burst)
|
if (!ret && caps.max_burst)
|
||||||
max_burst = caps.max_burst;
|
max_burst = caps.max_burst;
|
||||||
else
|
else
|
||||||
max_burst = TX_BURST_LEVEL;
|
max_burst = DW_SPI_TX_BURST_LEVEL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Having a Rx DMA channel serviced with higher priority than a Tx DMA
|
* Having a Rx DMA channel serviced with higher priority than a Tx DMA
|
||||||
@ -226,13 +227,13 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
|
|||||||
|
|
||||||
static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
|
static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
return !(dw_readl(dws, DW_SPI_SR) & SR_TF_EMPT);
|
return !(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_TF_EMPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
|
static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
|
||||||
struct spi_transfer *xfer)
|
struct spi_transfer *xfer)
|
||||||
{
|
{
|
||||||
int retry = SPI_WAIT_RETRIES;
|
int retry = DW_SPI_WAIT_RETRIES;
|
||||||
struct spi_delay delay;
|
struct spi_delay delay;
|
||||||
u32 nents;
|
u32 nents;
|
||||||
|
|
||||||
@ -259,8 +260,8 @@ static void dw_spi_dma_tx_done(void *arg)
|
|||||||
{
|
{
|
||||||
struct dw_spi *dws = arg;
|
struct dw_spi *dws = arg;
|
||||||
|
|
||||||
clear_bit(TX_BUSY, &dws->dma_chan_busy);
|
clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
|
||||||
if (test_bit(RX_BUSY, &dws->dma_chan_busy))
|
if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
complete(&dws->dma_completion);
|
complete(&dws->dma_completion);
|
||||||
@ -304,19 +305,19 @@ static int dw_spi_dma_submit_tx(struct dw_spi *dws, struct scatterlist *sgl,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_bit(TX_BUSY, &dws->dma_chan_busy);
|
set_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool dw_spi_dma_rx_busy(struct dw_spi *dws)
|
static inline bool dw_spi_dma_rx_busy(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
return !!(dw_readl(dws, DW_SPI_SR) & SR_RF_NOT_EMPT);
|
return !!(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_RF_NOT_EMPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_spi_dma_wait_rx_done(struct dw_spi *dws)
|
static int dw_spi_dma_wait_rx_done(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
int retry = SPI_WAIT_RETRIES;
|
int retry = DW_SPI_WAIT_RETRIES;
|
||||||
struct spi_delay delay;
|
struct spi_delay delay;
|
||||||
unsigned long ns, us;
|
unsigned long ns, us;
|
||||||
u32 nents;
|
u32 nents;
|
||||||
@ -360,8 +361,8 @@ static void dw_spi_dma_rx_done(void *arg)
|
|||||||
{
|
{
|
||||||
struct dw_spi *dws = arg;
|
struct dw_spi *dws = arg;
|
||||||
|
|
||||||
clear_bit(RX_BUSY, &dws->dma_chan_busy);
|
clear_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
|
||||||
if (test_bit(TX_BUSY, &dws->dma_chan_busy))
|
if (test_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
complete(&dws->dma_completion);
|
complete(&dws->dma_completion);
|
||||||
@ -405,7 +406,7 @@ static int dw_spi_dma_submit_rx(struct dw_spi *dws, struct scatterlist *sgl,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_bit(RX_BUSY, &dws->dma_chan_busy);
|
set_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -430,16 +431,16 @@ static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set the DMA handshaking interface */
|
/* Set the DMA handshaking interface */
|
||||||
dma_ctrl = SPI_DMA_TDMAE;
|
dma_ctrl = DW_SPI_DMACR_TDMAE;
|
||||||
if (xfer->rx_buf)
|
if (xfer->rx_buf)
|
||||||
dma_ctrl |= SPI_DMA_RDMAE;
|
dma_ctrl |= DW_SPI_DMACR_RDMAE;
|
||||||
dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
|
dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
|
||||||
|
|
||||||
/* Set the interrupt mask */
|
/* Set the interrupt mask */
|
||||||
imr = SPI_INT_TXOI;
|
imr = DW_SPI_INT_TXOI;
|
||||||
if (xfer->rx_buf)
|
if (xfer->rx_buf)
|
||||||
imr |= SPI_INT_RXUI | SPI_INT_RXOI;
|
imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI;
|
||||||
spi_umask_intr(dws, imr);
|
dw_spi_umask_intr(dws, imr);
|
||||||
|
|
||||||
reinit_completion(&dws->dma_completion);
|
reinit_completion(&dws->dma_completion);
|
||||||
|
|
||||||
@ -615,13 +616,13 @@ static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
|
|||||||
|
|
||||||
static void dw_spi_dma_stop(struct dw_spi *dws)
|
static void dw_spi_dma_stop(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
if (test_bit(TX_BUSY, &dws->dma_chan_busy)) {
|
if (test_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy)) {
|
||||||
dmaengine_terminate_sync(dws->txchan);
|
dmaengine_terminate_sync(dws->txchan);
|
||||||
clear_bit(TX_BUSY, &dws->dma_chan_busy);
|
clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
|
||||||
}
|
}
|
||||||
if (test_bit(RX_BUSY, &dws->dma_chan_busy)) {
|
if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) {
|
||||||
dmaengine_terminate_sync(dws->rxchan);
|
dmaengine_terminate_sync(dws->rxchan);
|
||||||
clear_bit(RX_BUSY, &dws->dma_chan_busy);
|
clear_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,7 +639,7 @@ void dw_spi_dma_setup_mfld(struct dw_spi *dws)
|
|||||||
{
|
{
|
||||||
dws->dma_ops = &dw_spi_dma_mfld_ops;
|
dws->dma_ops = &dw_spi_dma_mfld_ops;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_dma_setup_mfld);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_mfld, SPI_DW_CORE);
|
||||||
|
|
||||||
static const struct dw_spi_dma_ops dw_spi_dma_generic_ops = {
|
static const struct dw_spi_dma_ops dw_spi_dma_generic_ops = {
|
||||||
.dma_init = dw_spi_dma_init_generic,
|
.dma_init = dw_spi_dma_init_generic,
|
||||||
@ -653,4 +654,4 @@ void dw_spi_dma_setup_generic(struct dw_spi *dws)
|
|||||||
{
|
{
|
||||||
dws->dma_ops = &dw_spi_dma_generic_ops;
|
dws->dma_ops = &dw_spi_dma_generic_ops;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_spi_dma_setup_generic);
|
EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_generic, SPI_DW_CORE);
|
||||||
|
@ -196,18 +196,18 @@ static int dw_spi_alpine_init(struct platform_device *pdev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_spi_dw_apb_init(struct platform_device *pdev,
|
static int dw_spi_pssi_init(struct platform_device *pdev,
|
||||||
struct dw_spi_mmio *dwsmmio)
|
struct dw_spi_mmio *dwsmmio)
|
||||||
{
|
{
|
||||||
dw_spi_dma_setup_generic(&dwsmmio->dws);
|
dw_spi_dma_setup_generic(&dwsmmio->dws);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_spi_dwc_ssi_init(struct platform_device *pdev,
|
static int dw_spi_hssi_init(struct platform_device *pdev,
|
||||||
struct dw_spi_mmio *dwsmmio)
|
struct dw_spi_mmio *dwsmmio)
|
||||||
{
|
{
|
||||||
dwsmmio->dws.caps = DW_SPI_CAP_DWC_SSI;
|
dwsmmio->dws.ip = DW_HSSI_ID;
|
||||||
|
|
||||||
dw_spi_dma_setup_generic(&dwsmmio->dws);
|
dw_spi_dma_setup_generic(&dwsmmio->dws);
|
||||||
|
|
||||||
@ -217,7 +217,8 @@ static int dw_spi_dwc_ssi_init(struct platform_device *pdev,
|
|||||||
static int dw_spi_keembay_init(struct platform_device *pdev,
|
static int dw_spi_keembay_init(struct platform_device *pdev,
|
||||||
struct dw_spi_mmio *dwsmmio)
|
struct dw_spi_mmio *dwsmmio)
|
||||||
{
|
{
|
||||||
dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST | DW_SPI_CAP_DWC_SSI;
|
dwsmmio->dws.ip = DW_HSSI_ID;
|
||||||
|
dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -342,12 +343,12 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id dw_spi_mmio_of_match[] = {
|
static const struct of_device_id dw_spi_mmio_of_match[] = {
|
||||||
{ .compatible = "snps,dw-apb-ssi", .data = dw_spi_dw_apb_init},
|
{ .compatible = "snps,dw-apb-ssi", .data = dw_spi_pssi_init},
|
||||||
{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
|
{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
|
||||||
{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
|
{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
|
||||||
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
|
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
|
||||||
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init},
|
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
|
||||||
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
|
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
|
||||||
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
|
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
|
||||||
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
|
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
|
||||||
{ .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
|
{ .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
|
||||||
@ -357,7 +358,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
|||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static const struct acpi_device_id dw_spi_mmio_acpi_match[] = {
|
static const struct acpi_device_id dw_spi_mmio_acpi_match[] = {
|
||||||
{"HISI0173", (kernel_ulong_t)dw_spi_dw_apb_init},
|
{"HISI0173", (kernel_ulong_t)dw_spi_pssi_init},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
|
MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
|
||||||
@ -377,3 +378,4 @@ module_platform_driver(dw_spi_mmio_driver);
|
|||||||
MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
|
MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
|
||||||
MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
|
MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_IMPORT_NS(SPI_DW_CORE);
|
||||||
|
@ -24,14 +24,14 @@
|
|||||||
#define CLK_SPI_CDIV_MASK 0x00000e00
|
#define CLK_SPI_CDIV_MASK 0x00000e00
|
||||||
#define CLK_SPI_DISABLE_OFFSET 8
|
#define CLK_SPI_DISABLE_OFFSET 8
|
||||||
|
|
||||||
struct spi_pci_desc {
|
struct dw_spi_pci_desc {
|
||||||
int (*setup)(struct dw_spi *);
|
int (*setup)(struct dw_spi *);
|
||||||
u16 num_cs;
|
u16 num_cs;
|
||||||
u16 bus_num;
|
u16 bus_num;
|
||||||
u32 max_freq;
|
u32 max_freq;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int spi_mid_init(struct dw_spi *dws)
|
static int dw_spi_pci_mid_init(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
void __iomem *clk_reg;
|
void __iomem *clk_reg;
|
||||||
u32 clk_cdiv;
|
u32 clk_cdiv;
|
||||||
@ -53,36 +53,36 @@ static int spi_mid_init(struct dw_spi *dws)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spi_generic_init(struct dw_spi *dws)
|
static int dw_spi_pci_generic_init(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
dw_spi_dma_setup_generic(dws);
|
dw_spi_dma_setup_generic(dws);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct spi_pci_desc spi_pci_mid_desc_1 = {
|
static struct dw_spi_pci_desc dw_spi_pci_mid_desc_1 = {
|
||||||
.setup = spi_mid_init,
|
.setup = dw_spi_pci_mid_init,
|
||||||
.num_cs = 5,
|
.num_cs = 5,
|
||||||
.bus_num = 0,
|
.bus_num = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct spi_pci_desc spi_pci_mid_desc_2 = {
|
static struct dw_spi_pci_desc dw_spi_pci_mid_desc_2 = {
|
||||||
.setup = spi_mid_init,
|
.setup = dw_spi_pci_mid_init,
|
||||||
.num_cs = 2,
|
.num_cs = 2,
|
||||||
.bus_num = 1,
|
.bus_num = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct spi_pci_desc spi_pci_ehl_desc = {
|
static struct dw_spi_pci_desc dw_spi_pci_ehl_desc = {
|
||||||
.setup = spi_generic_init,
|
.setup = dw_spi_pci_generic_init,
|
||||||
.num_cs = 2,
|
.num_cs = 2,
|
||||||
.bus_num = -1,
|
.bus_num = -1,
|
||||||
.max_freq = 100000000,
|
.max_freq = 100000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
static int dw_spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
|
struct dw_spi_pci_desc *desc = (struct dw_spi_pci_desc *)ent->driver_data;
|
||||||
struct dw_spi *dws;
|
struct dw_spi *dws;
|
||||||
struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data;
|
|
||||||
int pci_bar = 0;
|
int pci_bar = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ err_free_irq_vectors:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spi_pci_remove(struct pci_dev *pdev)
|
static void dw_spi_pci_remove(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = pci_get_drvdata(pdev);
|
struct dw_spi *dws = pci_get_drvdata(pdev);
|
||||||
|
|
||||||
@ -162,14 +162,14 @@ static void spi_pci_remove(struct pci_dev *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
static int spi_suspend(struct device *dev)
|
static int dw_spi_pci_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = dev_get_drvdata(dev);
|
struct dw_spi *dws = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return dw_spi_suspend_host(dws);
|
return dw_spi_suspend_host(dws);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spi_resume(struct device *dev)
|
static int dw_spi_pci_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = dev_get_drvdata(dev);
|
struct dw_spi *dws = dev_get_drvdata(dev);
|
||||||
|
|
||||||
@ -177,39 +177,39 @@ static int spi_resume(struct device *dev)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume);
|
static SIMPLE_DEV_PM_OPS(dw_spi_pci_pm_ops, dw_spi_pci_suspend, dw_spi_pci_resume);
|
||||||
|
|
||||||
static const struct pci_device_id pci_ids[] = {
|
static const struct pci_device_id dw_spi_pci_ids[] = {
|
||||||
/* Intel MID platform SPI controller 0 */
|
/* Intel MID platform SPI controller 0 */
|
||||||
/*
|
/*
|
||||||
* The access to the device 8086:0801 is disabled by HW, since it's
|
* The access to the device 8086:0801 is disabled by HW, since it's
|
||||||
* exclusively used by SCU to communicate with MSIC.
|
* exclusively used by SCU to communicate with MSIC.
|
||||||
*/
|
*/
|
||||||
/* Intel MID platform SPI controller 1 */
|
/* Intel MID platform SPI controller 1 */
|
||||||
{ PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1},
|
{ PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&dw_spi_pci_mid_desc_1},
|
||||||
/* Intel MID platform SPI controller 2 */
|
/* Intel MID platform SPI controller 2 */
|
||||||
{ PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2},
|
{ PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&dw_spi_pci_mid_desc_2},
|
||||||
/* Intel Elkhart Lake PSE SPI controllers */
|
/* Intel Elkhart Lake PSE SPI controllers */
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&spi_pci_ehl_desc},
|
{ PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&dw_spi_pci_ehl_desc},
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&spi_pci_ehl_desc},
|
{ PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&dw_spi_pci_ehl_desc},
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&spi_pci_ehl_desc},
|
{ PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&dw_spi_pci_ehl_desc},
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&spi_pci_ehl_desc},
|
{ PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&dw_spi_pci_ehl_desc},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
MODULE_DEVICE_TABLE(pci, dw_spi_pci_ids);
|
||||||
|
|
||||||
static struct pci_driver dw_spi_driver = {
|
static struct pci_driver dw_spi_pci_driver = {
|
||||||
.name = DRIVER_NAME,
|
.name = DRIVER_NAME,
|
||||||
.id_table = pci_ids,
|
.id_table = dw_spi_pci_ids,
|
||||||
.probe = spi_pci_probe,
|
.probe = dw_spi_pci_probe,
|
||||||
.remove = spi_pci_remove,
|
.remove = dw_spi_pci_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.pm = &dw_spi_pm_ops,
|
.pm = &dw_spi_pci_pm_ops,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
module_pci_driver(dw_spi_pci_driver);
|
||||||
module_pci_driver(dw_spi_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
|
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
|
||||||
MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
|
MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_IMPORT_NS(SPI_DW_CORE);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
#ifndef DW_SPI_HEADER_H
|
#ifndef __SPI_DW_H__
|
||||||
#define DW_SPI_HEADER_H
|
#define __SPI_DW_H__
|
||||||
|
|
||||||
#include <linux/bits.h>
|
#include <linux/bits.h>
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
@ -11,7 +11,30 @@
|
|||||||
#include <linux/spi/spi-mem.h>
|
#include <linux/spi/spi-mem.h>
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
|
|
||||||
/* Register offsets */
|
/* Synopsys DW SSI IP-core virtual IDs */
|
||||||
|
#define DW_PSSI_ID 0
|
||||||
|
#define DW_HSSI_ID 1
|
||||||
|
|
||||||
|
/* Synopsys DW SSI component versions (FourCC sequence) */
|
||||||
|
#define DW_HSSI_102A 0x3130322a
|
||||||
|
|
||||||
|
/* DW SSI IP-core ID and version check helpers */
|
||||||
|
#define dw_spi_ip_is(_dws, _ip) \
|
||||||
|
((_dws)->ip == DW_ ## _ip ## _ID)
|
||||||
|
|
||||||
|
#define __dw_spi_ver_cmp(_dws, _ip, _ver, _op) \
|
||||||
|
(dw_spi_ip_is(_dws, _ip) && (_dws)->ver _op DW_ ## _ip ## _ver)
|
||||||
|
|
||||||
|
#define dw_spi_ver_is(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, ==)
|
||||||
|
|
||||||
|
#define dw_spi_ver_is_ge(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, >=)
|
||||||
|
|
||||||
|
/* DW SPI controller capabilities */
|
||||||
|
#define DW_SPI_CAP_CS_OVERRIDE BIT(0)
|
||||||
|
#define DW_SPI_CAP_KEEMBAY_MST BIT(1)
|
||||||
|
#define DW_SPI_CAP_DFS32 BIT(2)
|
||||||
|
|
||||||
|
/* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */
|
||||||
#define DW_SPI_CTRLR0 0x00
|
#define DW_SPI_CTRLR0 0x00
|
||||||
#define DW_SPI_CTRLR1 0x04
|
#define DW_SPI_CTRLR1 0x04
|
||||||
#define DW_SPI_SSIENR 0x08
|
#define DW_SPI_SSIENR 0x08
|
||||||
@ -40,92 +63,79 @@
|
|||||||
#define DW_SPI_RX_SAMPLE_DLY 0xf0
|
#define DW_SPI_RX_SAMPLE_DLY 0xf0
|
||||||
#define DW_SPI_CS_OVERRIDE 0xf4
|
#define DW_SPI_CS_OVERRIDE 0xf4
|
||||||
|
|
||||||
/* Bit fields in CTRLR0 */
|
/* Bit fields in CTRLR0 (DWC APB SSI) */
|
||||||
#define SPI_DFS_OFFSET 0
|
#define DW_PSSI_CTRLR0_DFS_MASK GENMASK(3, 0)
|
||||||
#define SPI_DFS_MASK GENMASK(3, 0)
|
#define DW_PSSI_CTRLR0_DFS32_MASK GENMASK(20, 16)
|
||||||
#define SPI_DFS32_OFFSET 16
|
|
||||||
|
|
||||||
#define SPI_FRF_OFFSET 4
|
#define DW_PSSI_CTRLR0_FRF_MASK GENMASK(5, 4)
|
||||||
#define SPI_FRF_SPI 0x0
|
#define DW_SPI_CTRLR0_FRF_MOTO_SPI 0x0
|
||||||
#define SPI_FRF_SSP 0x1
|
#define DW_SPI_CTRLR0_FRF_TI_SSP 0x1
|
||||||
#define SPI_FRF_MICROWIRE 0x2
|
#define DW_SPI_CTRLR0_FRF_NS_MICROWIRE 0x2
|
||||||
#define SPI_FRF_RESV 0x3
|
#define DW_SPI_CTRLR0_FRF_RESV 0x3
|
||||||
|
|
||||||
#define SPI_MODE_OFFSET 6
|
#define DW_PSSI_CTRLR0_MODE_MASK GENMASK(7, 6)
|
||||||
#define SPI_SCPH_OFFSET 6
|
#define DW_PSSI_CTRLR0_SCPHA BIT(6)
|
||||||
#define SPI_SCOL_OFFSET 7
|
#define DW_PSSI_CTRLR0_SCPOL BIT(7)
|
||||||
|
|
||||||
#define SPI_TMOD_OFFSET 8
|
#define DW_PSSI_CTRLR0_TMOD_MASK GENMASK(9, 8)
|
||||||
#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET)
|
#define DW_SPI_CTRLR0_TMOD_TR 0x0 /* xmit & recv */
|
||||||
#define SPI_TMOD_TR 0x0 /* xmit & recv */
|
#define DW_SPI_CTRLR0_TMOD_TO 0x1 /* xmit only */
|
||||||
#define SPI_TMOD_TO 0x1 /* xmit only */
|
#define DW_SPI_CTRLR0_TMOD_RO 0x2 /* recv only */
|
||||||
#define SPI_TMOD_RO 0x2 /* recv only */
|
#define DW_SPI_CTRLR0_TMOD_EPROMREAD 0x3 /* eeprom read mode */
|
||||||
#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
|
|
||||||
|
|
||||||
#define SPI_SLVOE_OFFSET 10
|
#define DW_PSSI_CTRLR0_SLV_OE BIT(10)
|
||||||
#define SPI_SRL_OFFSET 11
|
#define DW_PSSI_CTRLR0_SRL BIT(11)
|
||||||
#define SPI_CFS_OFFSET 12
|
#define DW_PSSI_CTRLR0_CFS BIT(12)
|
||||||
|
|
||||||
/* Bit fields in CTRLR0 based on DWC_ssi_databook.pdf v1.01a */
|
/* Bit fields in CTRLR0 (DWC SSI with AHB interface) */
|
||||||
#define DWC_SSI_CTRLR0_SRL_OFFSET 13
|
#define DW_HSSI_CTRLR0_DFS_MASK GENMASK(4, 0)
|
||||||
#define DWC_SSI_CTRLR0_TMOD_OFFSET 10
|
#define DW_HSSI_CTRLR0_FRF_MASK GENMASK(7, 6)
|
||||||
#define DWC_SSI_CTRLR0_TMOD_MASK GENMASK(11, 10)
|
#define DW_HSSI_CTRLR0_SCPHA BIT(8)
|
||||||
#define DWC_SSI_CTRLR0_SCPOL_OFFSET 9
|
#define DW_HSSI_CTRLR0_SCPOL BIT(9)
|
||||||
#define DWC_SSI_CTRLR0_SCPH_OFFSET 8
|
#define DW_HSSI_CTRLR0_TMOD_MASK GENMASK(11, 10)
|
||||||
#define DWC_SSI_CTRLR0_FRF_OFFSET 6
|
#define DW_HSSI_CTRLR0_SRL BIT(13)
|
||||||
#define DWC_SSI_CTRLR0_DFS_OFFSET 0
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For Keem Bay, CTRLR0[31] is used to select controller mode.
|
* For Keem Bay, CTRLR0[31] is used to select controller mode.
|
||||||
* 0: SSI is slave
|
* 0: SSI is slave
|
||||||
* 1: SSI is master
|
* 1: SSI is master
|
||||||
*/
|
*/
|
||||||
#define DWC_SSI_CTRLR0_KEEMBAY_MST BIT(31)
|
#define DW_HSSI_CTRLR0_KEEMBAY_MST BIT(31)
|
||||||
|
|
||||||
/* Bit fields in CTRLR1 */
|
/* Bit fields in CTRLR1 */
|
||||||
#define SPI_NDF_MASK GENMASK(15, 0)
|
#define DW_SPI_NDF_MASK GENMASK(15, 0)
|
||||||
|
|
||||||
/* Bit fields in SR, 7 bits */
|
/* Bit fields in SR, 7 bits */
|
||||||
#define SR_MASK 0x7f /* cover 7 bits */
|
#define DW_SPI_SR_MASK GENMASK(6, 0)
|
||||||
#define SR_BUSY (1 << 0)
|
#define DW_SPI_SR_BUSY BIT(0)
|
||||||
#define SR_TF_NOT_FULL (1 << 1)
|
#define DW_SPI_SR_TF_NOT_FULL BIT(1)
|
||||||
#define SR_TF_EMPT (1 << 2)
|
#define DW_SPI_SR_TF_EMPT BIT(2)
|
||||||
#define SR_RF_NOT_EMPT (1 << 3)
|
#define DW_SPI_SR_RF_NOT_EMPT BIT(3)
|
||||||
#define SR_RF_FULL (1 << 4)
|
#define DW_SPI_SR_RF_FULL BIT(4)
|
||||||
#define SR_TX_ERR (1 << 5)
|
#define DW_SPI_SR_TX_ERR BIT(5)
|
||||||
#define SR_DCOL (1 << 6)
|
#define DW_SPI_SR_DCOL BIT(6)
|
||||||
|
|
||||||
/* Bit fields in ISR, IMR, RISR, 7 bits */
|
/* Bit fields in ISR, IMR, RISR, 7 bits */
|
||||||
#define SPI_INT_TXEI (1 << 0)
|
#define DW_SPI_INT_MASK GENMASK(5, 0)
|
||||||
#define SPI_INT_TXOI (1 << 1)
|
#define DW_SPI_INT_TXEI BIT(0)
|
||||||
#define SPI_INT_RXUI (1 << 2)
|
#define DW_SPI_INT_TXOI BIT(1)
|
||||||
#define SPI_INT_RXOI (1 << 3)
|
#define DW_SPI_INT_RXUI BIT(2)
|
||||||
#define SPI_INT_RXFI (1 << 4)
|
#define DW_SPI_INT_RXOI BIT(3)
|
||||||
#define SPI_INT_MSTI (1 << 5)
|
#define DW_SPI_INT_RXFI BIT(4)
|
||||||
|
#define DW_SPI_INT_MSTI BIT(5)
|
||||||
|
|
||||||
/* Bit fields in DMACR */
|
/* Bit fields in DMACR */
|
||||||
#define SPI_DMA_RDMAE (1 << 0)
|
#define DW_SPI_DMACR_RDMAE BIT(0)
|
||||||
#define SPI_DMA_TDMAE (1 << 1)
|
#define DW_SPI_DMACR_TDMAE BIT(1)
|
||||||
|
|
||||||
#define SPI_WAIT_RETRIES 5
|
/* Mem/DMA operations helpers */
|
||||||
#define SPI_BUF_SIZE \
|
#define DW_SPI_WAIT_RETRIES 5
|
||||||
|
#define DW_SPI_BUF_SIZE \
|
||||||
(sizeof_field(struct spi_mem_op, cmd.opcode) + \
|
(sizeof_field(struct spi_mem_op, cmd.opcode) + \
|
||||||
sizeof_field(struct spi_mem_op, addr.val) + 256)
|
sizeof_field(struct spi_mem_op, addr.val) + 256)
|
||||||
#define SPI_GET_BYTE(_val, _idx) \
|
#define DW_SPI_GET_BYTE(_val, _idx) \
|
||||||
((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff)
|
((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff)
|
||||||
|
|
||||||
enum dw_ssi_type {
|
|
||||||
SSI_MOTO_SPI = 0,
|
|
||||||
SSI_TI_SSP,
|
|
||||||
SSI_NS_MICROWIRE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* DW SPI capabilities */
|
|
||||||
#define DW_SPI_CAP_CS_OVERRIDE BIT(0)
|
|
||||||
#define DW_SPI_CAP_KEEMBAY_MST BIT(1)
|
|
||||||
#define DW_SPI_CAP_DWC_SSI BIT(2)
|
|
||||||
#define DW_SPI_CAP_DFS32 BIT(3)
|
|
||||||
|
|
||||||
/* Slave spi_transfer/spi_mem_op related */
|
/* Slave spi_transfer/spi_mem_op related */
|
||||||
struct dw_spi_cfg {
|
struct dw_spi_cfg {
|
||||||
u8 tmode;
|
u8 tmode;
|
||||||
@ -148,6 +158,10 @@ struct dw_spi_dma_ops {
|
|||||||
struct dw_spi {
|
struct dw_spi {
|
||||||
struct spi_controller *master;
|
struct spi_controller *master;
|
||||||
|
|
||||||
|
u32 ip; /* Synopsys DW SSI IP-core ID */
|
||||||
|
u32 ver; /* Synopsys component version */
|
||||||
|
u32 caps; /* DW SPI capabilities */
|
||||||
|
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
unsigned long paddr;
|
unsigned long paddr;
|
||||||
int irq;
|
int irq;
|
||||||
@ -156,8 +170,6 @@ struct dw_spi {
|
|||||||
u32 max_mem_freq; /* max mem-ops bus freq */
|
u32 max_mem_freq; /* max mem-ops bus freq */
|
||||||
u32 max_freq; /* max bus freq supported */
|
u32 max_freq; /* max bus freq supported */
|
||||||
|
|
||||||
u32 caps; /* DW SPI capabilities */
|
|
||||||
|
|
||||||
u32 reg_io_width; /* DR I/O width in bytes */
|
u32 reg_io_width; /* DR I/O width in bytes */
|
||||||
u16 bus_num;
|
u16 bus_num;
|
||||||
u16 num_cs; /* supported slave numbers */
|
u16 num_cs; /* supported slave numbers */
|
||||||
@ -168,7 +180,7 @@ struct dw_spi {
|
|||||||
unsigned int tx_len;
|
unsigned int tx_len;
|
||||||
void *rx;
|
void *rx;
|
||||||
unsigned int rx_len;
|
unsigned int rx_len;
|
||||||
u8 buf[SPI_BUF_SIZE];
|
u8 buf[DW_SPI_BUF_SIZE];
|
||||||
int dma_mapped;
|
int dma_mapped;
|
||||||
u8 n_bytes; /* current is a 1/2 bytes op */
|
u8 n_bytes; /* current is a 1/2 bytes op */
|
||||||
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
|
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
|
||||||
@ -230,18 +242,18 @@ static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_enable_chip(struct dw_spi *dws, int enable)
|
static inline void dw_spi_enable_chip(struct dw_spi *dws, int enable)
|
||||||
{
|
{
|
||||||
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
|
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_set_clk(struct dw_spi *dws, u16 div)
|
static inline void dw_spi_set_clk(struct dw_spi *dws, u16 div)
|
||||||
{
|
{
|
||||||
dw_writel(dws, DW_SPI_BAUDR, div);
|
dw_writel(dws, DW_SPI_BAUDR, div);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable IRQ bits */
|
/* Disable IRQ bits */
|
||||||
static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
|
static inline void dw_spi_mask_intr(struct dw_spi *dws, u32 mask)
|
||||||
{
|
{
|
||||||
u32 new_mask;
|
u32 new_mask;
|
||||||
|
|
||||||
@ -250,7 +262,7 @@ static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable IRQ bits */
|
/* Enable IRQ bits */
|
||||||
static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
|
static inline void dw_spi_umask_intr(struct dw_spi *dws, u32 mask)
|
||||||
{
|
{
|
||||||
u32 new_mask;
|
u32 new_mask;
|
||||||
|
|
||||||
@ -263,19 +275,19 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
|
|||||||
* and CS, then re-enables the controller back. Transmit and receive FIFO
|
* and CS, then re-enables the controller back. Transmit and receive FIFO
|
||||||
* buffers are cleared when the device is disabled.
|
* buffers are cleared when the device is disabled.
|
||||||
*/
|
*/
|
||||||
static inline void spi_reset_chip(struct dw_spi *dws)
|
static inline void dw_spi_reset_chip(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
spi_enable_chip(dws, 0);
|
dw_spi_enable_chip(dws, 0);
|
||||||
spi_mask_intr(dws, 0xff);
|
dw_spi_mask_intr(dws, 0xff);
|
||||||
dw_readl(dws, DW_SPI_ICR);
|
dw_readl(dws, DW_SPI_ICR);
|
||||||
dw_writel(dws, DW_SPI_SER, 0);
|
dw_writel(dws, DW_SPI_SER, 0);
|
||||||
spi_enable_chip(dws, 1);
|
dw_spi_enable_chip(dws, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_shutdown_chip(struct dw_spi *dws)
|
static inline void dw_spi_shutdown_chip(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
spi_enable_chip(dws, 0);
|
dw_spi_enable_chip(dws, 0);
|
||||||
spi_set_clk(dws, 0);
|
dw_spi_set_clk(dws, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
|
extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
|
||||||
@ -299,4 +311,4 @@ static inline void dw_spi_dma_setup_generic(struct dw_spi *dws) {}
|
|||||||
|
|
||||||
#endif /* !CONFIG_SPI_DW_DMA */
|
#endif /* !CONFIG_SPI_DW_DMA */
|
||||||
|
|
||||||
#endif /* DW_SPI_HEADER_H */
|
#endif /* __SPI_DW_H__ */
|
||||||
|
@ -913,7 +913,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
|
|||||||
ret = devm_spi_register_controller(&pdev->dev, controller);
|
ret = devm_spi_register_controller(&pdev->dev, controller);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err_probe(&pdev->dev, ret, "spi_register_controller error: %i\n", ret);
|
dev_err_probe(&pdev->dev, ret, "spi_register_controller error: %i\n", ret);
|
||||||
goto out_pm_get;
|
goto free_dma;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_mark_last_busy(fsl_lpspi->dev);
|
pm_runtime_mark_last_busy(fsl_lpspi->dev);
|
||||||
@ -921,6 +921,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
free_dma:
|
||||||
|
fsl_lpspi_dma_exit(controller);
|
||||||
out_pm_get:
|
out_pm_get:
|
||||||
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
|
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
|
||||||
pm_runtime_put_sync(fsl_lpspi->dev);
|
pm_runtime_put_sync(fsl_lpspi->dev);
|
||||||
@ -937,6 +939,8 @@ static int fsl_lpspi_remove(struct platform_device *pdev)
|
|||||||
struct fsl_lpspi_data *fsl_lpspi =
|
struct fsl_lpspi_data *fsl_lpspi =
|
||||||
spi_controller_get_devdata(controller);
|
spi_controller_get_devdata(controller);
|
||||||
|
|
||||||
|
fsl_lpspi_dma_exit(controller);
|
||||||
|
|
||||||
pm_runtime_disable(fsl_lpspi->dev);
|
pm_runtime_disable(fsl_lpspi->dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,6 @@
|
|||||||
#define GSI_CPHA BIT(4)
|
#define GSI_CPHA BIT(4)
|
||||||
#define GSI_CPOL BIT(5)
|
#define GSI_CPOL BIT(5)
|
||||||
|
|
||||||
#define MAX_TX_SG 3
|
|
||||||
#define NUM_SPI_XFER 8
|
|
||||||
#define SPI_XFER_TIMEOUT_MS 250
|
|
||||||
|
|
||||||
struct spi_geni_master {
|
struct spi_geni_master {
|
||||||
struct geni_se se;
|
struct geni_se se;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
@ -168,6 +164,30 @@ static void handle_fifo_timeout(struct spi_master *spi,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_gpi_timeout(struct spi_master *spi, struct spi_message *msg)
|
||||||
|
{
|
||||||
|
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
|
dmaengine_terminate_sync(mas->tx);
|
||||||
|
dmaengine_terminate_sync(mas->rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_geni_handle_err(struct spi_master *spi, struct spi_message *msg)
|
||||||
|
{
|
||||||
|
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
|
switch (mas->cur_xfer_mode) {
|
||||||
|
case GENI_SE_FIFO:
|
||||||
|
handle_fifo_timeout(spi, msg);
|
||||||
|
break;
|
||||||
|
case GENI_GPI_DMA:
|
||||||
|
handle_gpi_timeout(spi, msg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(mas->dev, "Abort on Mode:%d not supported", mas->cur_xfer_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas)
|
static bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas)
|
||||||
{
|
{
|
||||||
struct geni_se *se = &mas->se;
|
struct geni_se *se = &mas->se;
|
||||||
@ -350,17 +370,21 @@ spi_gsi_callback_result(void *cb, const struct dmaengine_result *result)
|
|||||||
{
|
{
|
||||||
struct spi_master *spi = cb;
|
struct spi_master *spi = cb;
|
||||||
|
|
||||||
|
spi->cur_msg->status = -EIO;
|
||||||
if (result->result != DMA_TRANS_NOERROR) {
|
if (result->result != DMA_TRANS_NOERROR) {
|
||||||
dev_err(&spi->dev, "DMA txn failed: %d\n", result->result);
|
dev_err(&spi->dev, "DMA txn failed: %d\n", result->result);
|
||||||
|
spi_finalize_current_transfer(spi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result->residue) {
|
if (!result->residue) {
|
||||||
|
spi->cur_msg->status = 0;
|
||||||
dev_dbg(&spi->dev, "DMA txn completed\n");
|
dev_dbg(&spi->dev, "DMA txn completed\n");
|
||||||
spi_finalize_current_transfer(spi);
|
|
||||||
} else {
|
} else {
|
||||||
dev_err(&spi->dev, "DMA xfer has pending: %d\n", result->residue);
|
dev_err(&spi->dev, "DMA xfer has pending: %d\n", result->residue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spi_finalize_current_transfer(spi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas,
|
static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas,
|
||||||
@ -922,7 +946,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
|||||||
spi->can_dma = geni_can_dma;
|
spi->can_dma = geni_can_dma;
|
||||||
spi->dma_map_dev = dev->parent;
|
spi->dma_map_dev = dev->parent;
|
||||||
spi->auto_runtime_pm = true;
|
spi->auto_runtime_pm = true;
|
||||||
spi->handle_err = handle_fifo_timeout;
|
spi->handle_err = spi_geni_handle_err;
|
||||||
spi->use_gpio_descriptors = true;
|
spi->use_gpio_descriptors = true;
|
||||||
|
|
||||||
init_completion(&mas->cs_done);
|
init_completion(&mas->cs_done);
|
||||||
|
@ -127,7 +127,6 @@ struct hisi_spi {
|
|||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
int irq;
|
int irq;
|
||||||
u32 fifo_len; /* depth of the FIFO buffer */
|
u32 fifo_len; /* depth of the FIFO buffer */
|
||||||
u16 bus_num;
|
|
||||||
|
|
||||||
/* Current message transfer state info */
|
/* Current message transfer state info */
|
||||||
const void *tx;
|
const void *tx;
|
||||||
@ -165,7 +164,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs)
|
|||||||
{
|
{
|
||||||
char name[32];
|
char name[32];
|
||||||
|
|
||||||
snprintf(name, 32, "hisi_spi%d", hs->bus_num);
|
struct spi_controller *master;
|
||||||
|
|
||||||
|
master = container_of(hs->dev, struct spi_controller, dev);
|
||||||
|
snprintf(name, 32, "hisi_spi%d", master->bus_num);
|
||||||
hs->debugfs = debugfs_create_dir(name, NULL);
|
hs->debugfs = debugfs_create_dir(name, NULL);
|
||||||
if (!hs->debugfs)
|
if (!hs->debugfs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -467,7 +469,6 @@ static int hisi_spi_probe(struct platform_device *pdev)
|
|||||||
hs = spi_controller_get_devdata(master);
|
hs = spi_controller_get_devdata(master);
|
||||||
hs->dev = dev;
|
hs->dev = dev;
|
||||||
hs->irq = irq;
|
hs->irq = irq;
|
||||||
hs->bus_num = pdev->id;
|
|
||||||
|
|
||||||
hs->regs = devm_platform_ioremap_resource(pdev, 0);
|
hs->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(hs->regs))
|
if (IS_ERR(hs->regs))
|
||||||
@ -490,7 +491,7 @@ static int hisi_spi_probe(struct platform_device *pdev)
|
|||||||
master->use_gpio_descriptors = true;
|
master->use_gpio_descriptors = true;
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
|
||||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||||
master->bus_num = hs->bus_num;
|
master->bus_num = pdev->id;
|
||||||
master->setup = hisi_spi_setup;
|
master->setup = hisi_spi_setup;
|
||||||
master->cleanup = hisi_spi_cleanup;
|
master->cleanup = hisi_spi_cleanup;
|
||||||
master->transfer_one = hisi_spi_transfer_one;
|
master->transfer_one = hisi_spi_transfer_one;
|
||||||
@ -506,15 +507,15 @@ static int hisi_spi_probe(struct platform_device *pdev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hisi_spi_debugfs_init(hs))
|
|
||||||
dev_info(dev, "failed to create debugfs dir\n");
|
|
||||||
|
|
||||||
ret = spi_register_controller(master);
|
ret = spi_register_controller(master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to register spi master, ret=%d\n", ret);
|
dev_err(dev, "failed to register spi master, ret=%d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hisi_spi_debugfs_init(hs))
|
||||||
|
dev_info(dev, "failed to create debugfs dir\n");
|
||||||
|
|
||||||
dev_info(dev, "hw version:0x%x max-freq:%u kHz\n",
|
dev_info(dev, "hw version:0x%x max-freq:%u kHz\n",
|
||||||
readl(hs->regs + HISI_SPI_VERSION),
|
readl(hs->regs + HISI_SPI_VERSION),
|
||||||
master->max_speed_hz / 1000);
|
master->max_speed_hz / 1000);
|
||||||
|
@ -349,6 +349,7 @@ static int meson_spifc_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
out_clk:
|
out_clk:
|
||||||
clk_disable_unprepare(spifc->clk);
|
clk_disable_unprepare(spifc->clk);
|
||||||
|
pm_runtime_disable(spifc->dev);
|
||||||
out_err:
|
out_err:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -427,7 +427,6 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
|
|||||||
|
|
||||||
static void cs_assert(struct spi_device *spi)
|
static void cs_assert(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct chip_data *chip = spi_get_ctldata(spi);
|
|
||||||
struct driver_data *drv_data =
|
struct driver_data *drv_data =
|
||||||
spi_controller_get_devdata(spi->controller);
|
spi_controller_get_devdata(spi->controller);
|
||||||
|
|
||||||
@ -436,18 +435,12 @@ static void cs_assert(struct spi_device *spi)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->cs_control) {
|
|
||||||
chip->cs_control(PXA2XX_CS_ASSERT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_lpss_ssp(drv_data))
|
if (is_lpss_ssp(drv_data))
|
||||||
lpss_ssp_cs_control(spi, true);
|
lpss_ssp_cs_control(spi, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cs_deassert(struct spi_device *spi)
|
static void cs_deassert(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct chip_data *chip = spi_get_ctldata(spi);
|
|
||||||
struct driver_data *drv_data =
|
struct driver_data *drv_data =
|
||||||
spi_controller_get_devdata(spi->controller);
|
spi_controller_get_devdata(spi->controller);
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@ -461,11 +454,6 @@ static void cs_deassert(struct spi_device *spi)
|
|||||||
!time_after(jiffies, timeout))
|
!time_after(jiffies, timeout))
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
|
|
||||||
if (chip->cs_control) {
|
|
||||||
chip->cs_control(PXA2XX_CS_DEASSERT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_lpss_ssp(drv_data))
|
if (is_lpss_ssp(drv_data))
|
||||||
lpss_ssp_cs_control(spi, false);
|
lpss_ssp_cs_control(spi, false);
|
||||||
}
|
}
|
||||||
@ -994,13 +982,10 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
|
|||||||
dev_err(&spi->dev, "Flush failed\n");
|
dev_err(&spi->dev, "Flush failed\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
drv_data->n_bytes = chip->n_bytes;
|
|
||||||
drv_data->tx = (void *)transfer->tx_buf;
|
drv_data->tx = (void *)transfer->tx_buf;
|
||||||
drv_data->tx_end = drv_data->tx + transfer->len;
|
drv_data->tx_end = drv_data->tx + transfer->len;
|
||||||
drv_data->rx = transfer->rx_buf;
|
drv_data->rx = transfer->rx_buf;
|
||||||
drv_data->rx_end = drv_data->rx + transfer->len;
|
drv_data->rx_end = drv_data->rx + transfer->len;
|
||||||
drv_data->write = drv_data->tx ? chip->write : null_writer;
|
|
||||||
drv_data->read = drv_data->rx ? chip->read : null_reader;
|
|
||||||
|
|
||||||
/* Change speed and bit per word on a per transfer */
|
/* Change speed and bit per word on a per transfer */
|
||||||
bits = transfer->bits_per_word;
|
bits = transfer->bits_per_word;
|
||||||
@ -1010,22 +995,16 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
|
|||||||
|
|
||||||
if (bits <= 8) {
|
if (bits <= 8) {
|
||||||
drv_data->n_bytes = 1;
|
drv_data->n_bytes = 1;
|
||||||
drv_data->read = drv_data->read != null_reader ?
|
drv_data->read = drv_data->rx ? u8_reader : null_reader;
|
||||||
u8_reader : null_reader;
|
drv_data->write = drv_data->tx ? u8_writer : null_writer;
|
||||||
drv_data->write = drv_data->write != null_writer ?
|
|
||||||
u8_writer : null_writer;
|
|
||||||
} else if (bits <= 16) {
|
} else if (bits <= 16) {
|
||||||
drv_data->n_bytes = 2;
|
drv_data->n_bytes = 2;
|
||||||
drv_data->read = drv_data->read != null_reader ?
|
drv_data->read = drv_data->rx ? u16_reader : null_reader;
|
||||||
u16_reader : null_reader;
|
drv_data->write = drv_data->tx ? u16_writer : null_writer;
|
||||||
drv_data->write = drv_data->write != null_writer ?
|
|
||||||
u16_writer : null_writer;
|
|
||||||
} else if (bits <= 32) {
|
} else if (bits <= 32) {
|
||||||
drv_data->n_bytes = 4;
|
drv_data->n_bytes = 4;
|
||||||
drv_data->read = drv_data->read != null_reader ?
|
drv_data->read = drv_data->rx ? u32_reader : null_reader;
|
||||||
u32_reader : null_reader;
|
drv_data->write = drv_data->tx ? u32_writer : null_writer;
|
||||||
drv_data->write = drv_data->write != null_writer ?
|
|
||||||
u32_writer : null_writer;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* If bits per word is changed in DMA mode, then must check
|
* If bits per word is changed in DMA mode, then must check
|
||||||
@ -1213,12 +1192,6 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
|
|||||||
*/
|
*/
|
||||||
cleanup_cs(spi);
|
cleanup_cs(spi);
|
||||||
|
|
||||||
/* If ->cs_control() is provided, ignore GPIO chip select */
|
|
||||||
if (chip_info->cs_control) {
|
|
||||||
chip->cs_control = chip_info->cs_control;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gpio_is_valid(chip_info->gpio_cs)) {
|
if (gpio_is_valid(chip_info->gpio_cs)) {
|
||||||
int gpio = chip_info->gpio_cs;
|
int gpio = chip_info->gpio_cs;
|
||||||
int err;
|
int err;
|
||||||
@ -1316,7 +1289,6 @@ static int setup(struct spi_device *spi)
|
|||||||
chip_info = spi->controller_data;
|
chip_info = spi->controller_data;
|
||||||
|
|
||||||
/* chip_info isn't always needed */
|
/* chip_info isn't always needed */
|
||||||
chip->cr1 = 0;
|
|
||||||
if (chip_info) {
|
if (chip_info) {
|
||||||
if (chip_info->timeout)
|
if (chip_info->timeout)
|
||||||
chip->timeout = chip_info->timeout;
|
chip->timeout = chip_info->timeout;
|
||||||
@ -1327,9 +1299,9 @@ static int setup(struct spi_device *spi)
|
|||||||
if (chip_info->rx_threshold)
|
if (chip_info->rx_threshold)
|
||||||
rx_thres = chip_info->rx_threshold;
|
rx_thres = chip_info->rx_threshold;
|
||||||
chip->dma_threshold = 0;
|
chip->dma_threshold = 0;
|
||||||
if (chip_info->enable_loopback)
|
|
||||||
chip->cr1 = SSCR1_LBM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chip->cr1 = 0;
|
||||||
if (spi_controller_is_slave(drv_data->controller)) {
|
if (spi_controller_is_slave(drv_data->controller)) {
|
||||||
chip->cr1 |= SSCR1_SCFR;
|
chip->cr1 |= SSCR1_SCFR;
|
||||||
chip->cr1 |= SSCR1_SCLKDIR;
|
chip->cr1 |= SSCR1_SCLKDIR;
|
||||||
@ -1391,20 +1363,6 @@ static int setup(struct spi_device *spi)
|
|||||||
if (spi->mode & SPI_LOOP)
|
if (spi->mode & SPI_LOOP)
|
||||||
chip->cr1 |= SSCR1_LBM;
|
chip->cr1 |= SSCR1_LBM;
|
||||||
|
|
||||||
if (spi->bits_per_word <= 8) {
|
|
||||||
chip->n_bytes = 1;
|
|
||||||
chip->read = u8_reader;
|
|
||||||
chip->write = u8_writer;
|
|
||||||
} else if (spi->bits_per_word <= 16) {
|
|
||||||
chip->n_bytes = 2;
|
|
||||||
chip->read = u16_reader;
|
|
||||||
chip->write = u16_writer;
|
|
||||||
} else if (spi->bits_per_word <= 32) {
|
|
||||||
chip->n_bytes = 4;
|
|
||||||
chip->read = u32_reader;
|
|
||||||
chip->write = u32_writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
spi_set_ctldata(spi, chip);
|
spi_set_ctldata(spi, chip);
|
||||||
|
|
||||||
if (drv_data->ssp_type == CE4100_SSP)
|
if (drv_data->ssp_type == CE4100_SSP)
|
||||||
@ -1706,8 +1664,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
|||||||
drv_data->controller_info = platform_info;
|
drv_data->controller_info = platform_info;
|
||||||
drv_data->ssp = ssp;
|
drv_data->ssp = ssp;
|
||||||
|
|
||||||
controller->dev.of_node = dev->of_node;
|
device_set_node(&controller->dev, dev_fwnode(dev));
|
||||||
controller->dev.fwnode = dev->fwnode;
|
|
||||||
|
|
||||||
/* The spi->mode bits understood by this driver: */
|
/* The spi->mode bits understood by this driver: */
|
||||||
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
|
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
|
||||||
|
@ -49,7 +49,6 @@ struct driver_data {
|
|||||||
int (*write)(struct driver_data *drv_data);
|
int (*write)(struct driver_data *drv_data);
|
||||||
int (*read)(struct driver_data *drv_data);
|
int (*read)(struct driver_data *drv_data);
|
||||||
irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
|
irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
|
||||||
void (*cs_control)(u32 command);
|
|
||||||
|
|
||||||
void __iomem *lpss_base;
|
void __iomem *lpss_base;
|
||||||
|
|
||||||
@ -61,18 +60,12 @@ struct chip_data {
|
|||||||
u32 cr1;
|
u32 cr1;
|
||||||
u32 dds_rate;
|
u32 dds_rate;
|
||||||
u32 timeout;
|
u32 timeout;
|
||||||
u8 n_bytes;
|
|
||||||
u8 enable_dma;
|
u8 enable_dma;
|
||||||
u32 dma_burst_size;
|
u32 dma_burst_size;
|
||||||
u32 dma_threshold;
|
u32 dma_threshold;
|
||||||
u32 threshold;
|
u32 threshold;
|
||||||
u16 lpss_rx_threshold;
|
u16 lpss_rx_threshold;
|
||||||
u16 lpss_tx_threshold;
|
u16 lpss_tx_threshold;
|
||||||
|
|
||||||
int (*write)(struct driver_data *drv_data);
|
|
||||||
int (*read)(struct driver_data *drv_data);
|
|
||||||
|
|
||||||
void (*cs_control)(u32 command);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg)
|
static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg)
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
#include <linux/sh_dma.h>
|
#include <linux/sh_dma.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/rspi.h>
|
#include <linux/spi/rspi.h>
|
||||||
@ -834,7 +835,7 @@ static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (rspi->ctlr->can_dma && __rspi_can_dma(rspi, xfer)) {
|
if (rspi->ctlr->can_dma && __rspi_can_dma(rspi, xfer)) {
|
||||||
int ret = rspi_dma_transfer(rspi, NULL, &xfer->rx_sg);
|
ret = rspi_dma_transfer(rspi, NULL, &xfer->rx_sg);
|
||||||
if (ret != -EAGAIN)
|
if (ret != -EAGAIN)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1225,8 +1226,14 @@ static const struct of_device_id rspi_of_match[] = {
|
|||||||
|
|
||||||
MODULE_DEVICE_TABLE(of, rspi_of_match);
|
MODULE_DEVICE_TABLE(of, rspi_of_match);
|
||||||
|
|
||||||
|
static void rspi_reset_control_assert(void *data)
|
||||||
|
{
|
||||||
|
reset_control_assert(data);
|
||||||
|
}
|
||||||
|
|
||||||
static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr)
|
static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr)
|
||||||
{
|
{
|
||||||
|
struct reset_control *rstc;
|
||||||
u32 num_cs;
|
u32 num_cs;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -1238,6 +1245,24 @@ static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctlr->num_chipselect = num_cs;
|
ctlr->num_chipselect = num_cs;
|
||||||
|
|
||||||
|
rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
|
||||||
|
if (IS_ERR(rstc))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(rstc),
|
||||||
|
"failed to get reset ctrl\n");
|
||||||
|
|
||||||
|
error = reset_control_deassert(rstc);
|
||||||
|
if (error) {
|
||||||
|
dev_err(dev, "failed to deassert reset %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = devm_add_action_or_reset(dev, rspi_reset_control_assert, rstc);
|
||||||
|
if (error) {
|
||||||
|
dev_err(dev, "failed to register assert devm action, %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -877,7 +877,7 @@ static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_devic
|
|||||||
struct tegra_qspi_client_data *cdata;
|
struct tegra_qspi_client_data *cdata;
|
||||||
struct device_node *slave_np = spi->dev.of_node;
|
struct device_node *slave_np = spi->dev.of_node;
|
||||||
|
|
||||||
cdata = kzalloc(sizeof(*cdata), GFP_KERNEL);
|
cdata = devm_kzalloc(&spi->dev, sizeof(*cdata), GFP_KERNEL);
|
||||||
if (!cdata)
|
if (!cdata)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -888,14 +888,6 @@ static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_devic
|
|||||||
return cdata;
|
return cdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_qspi_cleanup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
struct tegra_qspi_client_data *cdata = spi->controller_data;
|
|
||||||
|
|
||||||
spi->controller_data = NULL;
|
|
||||||
kfree(cdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tegra_qspi_setup(struct spi_device *spi)
|
static int tegra_qspi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
|
struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
|
||||||
@ -1229,7 +1221,6 @@ static int tegra_qspi_probe(struct platform_device *pdev)
|
|||||||
SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
|
SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
|
||||||
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
|
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
|
||||||
master->setup = tegra_qspi_setup;
|
master->setup = tegra_qspi_setup;
|
||||||
master->cleanup = tegra_qspi_cleanup;
|
|
||||||
master->transfer_one_message = tegra_qspi_transfer_one_message;
|
master->transfer_one_message = tegra_qspi_transfer_one_message;
|
||||||
master->num_chipselect = 1;
|
master->num_chipselect = 1;
|
||||||
master->auto_runtime_pm = true;
|
master->auto_runtime_pm = true;
|
||||||
|
@ -767,12 +767,13 @@ out_master_put:
|
|||||||
|
|
||||||
static int uniphier_spi_remove(struct platform_device *pdev)
|
static int uniphier_spi_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct uniphier_spi_priv *priv = platform_get_drvdata(pdev);
|
struct spi_master *master = platform_get_drvdata(pdev);
|
||||||
|
struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
|
||||||
|
|
||||||
if (priv->master->dma_tx)
|
if (master->dma_tx)
|
||||||
dma_release_channel(priv->master->dma_tx);
|
dma_release_channel(master->dma_tx);
|
||||||
if (priv->master->dma_rx)
|
if (master->dma_rx)
|
||||||
dma_release_channel(priv->master->dma_rx);
|
dma_release_channel(master->dma_rx);
|
||||||
|
|
||||||
clk_disable_unprepare(priv->clk);
|
clk_disable_unprepare(priv->clk);
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
/* SPI Configuration Register */
|
/* SPI Configuration Register */
|
||||||
@ -436,17 +435,10 @@ static const struct acpi_device_id xlp_spi_acpi_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match);
|
MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct of_device_id xlp_spi_dt_id[] = {
|
|
||||||
{ .compatible = "netlogic,xlp832-spi" },
|
|
||||||
{ },
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, xlp_spi_dt_id);
|
|
||||||
|
|
||||||
static struct platform_driver xlp_spi_driver = {
|
static struct platform_driver xlp_spi_driver = {
|
||||||
.probe = xlp_spi_probe,
|
.probe = xlp_spi_probe,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "xlp-spi",
|
.name = "xlp-spi",
|
||||||
.of_match_table = xlp_spi_dt_id,
|
|
||||||
.acpi_match_table = ACPI_PTR(xlp_spi_acpi_match),
|
.acpi_match_table = ACPI_PTR(xlp_spi_acpi_match),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <linux/highmem.h>
|
#include <linux/highmem.h>
|
||||||
#include <linux/idr.h>
|
#include <linux/idr.h>
|
||||||
#include <linux/platform_data/x86/apple.h>
|
#include <linux/platform_data/x86/apple.h>
|
||||||
|
#include <linux/ptp_clock_kernel.h>
|
||||||
|
|
||||||
#define CREATE_TRACE_POINTS
|
#define CREATE_TRACE_POINTS
|
||||||
#include <trace/events/spi.h>
|
#include <trace/events/spi.h>
|
||||||
@ -311,15 +312,14 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
|
|||||||
spin_unlock_irqrestore(&stats->lock, flags);
|
spin_unlock_irqrestore(&stats->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
|
/*
|
||||||
|
* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
|
||||||
* and the sysfs version makes coldplug work too.
|
* and the sysfs version makes coldplug work too.
|
||||||
*/
|
*/
|
||||||
|
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, const char *name)
|
||||||
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,
|
|
||||||
const struct spi_device *sdev)
|
|
||||||
{
|
{
|
||||||
while (id->name[0]) {
|
while (id->name[0]) {
|
||||||
if (!strcmp(sdev->modalias, id->name))
|
if (!strcmp(name, id->name))
|
||||||
return id;
|
return id;
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
@ -330,7 +330,7 @@ const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev)
|
|||||||
{
|
{
|
||||||
const struct spi_driver *sdrv = to_spi_driver(sdev->dev.driver);
|
const struct spi_driver *sdrv = to_spi_driver(sdev->dev.driver);
|
||||||
|
|
||||||
return spi_match_id(sdrv->id_table, sdev);
|
return spi_match_id(sdrv->id_table, sdev->modalias);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_get_device_id);
|
EXPORT_SYMBOL_GPL(spi_get_device_id);
|
||||||
|
|
||||||
@ -352,7 +352,7 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (sdrv->id_table)
|
if (sdrv->id_table)
|
||||||
return !!spi_match_id(sdrv->id_table, spi);
|
return !!spi_match_id(sdrv->id_table, spi->modalias);
|
||||||
|
|
||||||
return strcmp(spi->modalias, drv->name) == 0;
|
return strcmp(spi->modalias, drv->name) == 0;
|
||||||
}
|
}
|
||||||
@ -474,12 +474,8 @@ int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
|
|||||||
if (sdrv->id_table) {
|
if (sdrv->id_table) {
|
||||||
const struct spi_device_id *spi_id;
|
const struct spi_device_id *spi_id;
|
||||||
|
|
||||||
for (spi_id = sdrv->id_table; spi_id->name[0];
|
spi_id = spi_match_id(sdrv->id_table, of_name);
|
||||||
spi_id++)
|
if (spi_id)
|
||||||
if (strcmp(spi_id->name, of_name) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (spi_id->name[0])
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (strcmp(sdrv->driver.name, of_name) == 0)
|
if (strcmp(sdrv->driver.name, of_name) == 0)
|
||||||
@ -497,7 +493,8 @@ EXPORT_SYMBOL_GPL(__spi_register_driver);
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* SPI devices should normally not be created by SPI device drivers; that
|
/*
|
||||||
|
* SPI devices should normally not be created by SPI device drivers; that
|
||||||
* would make them board-specific. Similarly with SPI controller drivers.
|
* would make them board-specific. Similarly with SPI controller drivers.
|
||||||
* Device registration normally goes into like arch/.../mach.../board-YYY.c
|
* Device registration normally goes into like arch/.../mach.../board-YYY.c
|
||||||
* with other readonly (flashable) information about mainboard devices.
|
* with other readonly (flashable) information about mainboard devices.
|
||||||
@ -513,8 +510,8 @@ static LIST_HEAD(spi_controller_list);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to protect add/del operation for board_info list and
|
* Used to protect add/del operation for board_info list and
|
||||||
* spi_controller list, and their matching process
|
* spi_controller list, and their matching process also used
|
||||||
* also used to protect object of type struct idr
|
* to protect object of type struct idr.
|
||||||
*/
|
*/
|
||||||
static DEFINE_MUTEX(board_lock);
|
static DEFINE_MUTEX(board_lock);
|
||||||
|
|
||||||
@ -621,7 +618,8 @@ static int __spi_add_device(struct spi_device *spi)
|
|||||||
else if (ctlr->cs_gpios)
|
else if (ctlr->cs_gpios)
|
||||||
spi->cs_gpio = ctlr->cs_gpios[spi->chip_select];
|
spi->cs_gpio = ctlr->cs_gpios[spi->chip_select];
|
||||||
|
|
||||||
/* Drivers may modify this initial i/o setup, but will
|
/*
|
||||||
|
* Drivers may modify this initial i/o setup, but will
|
||||||
* normally rely on the device being setup. Devices
|
* normally rely on the device being setup. Devices
|
||||||
* using SPI_CS_HIGH can't coexist well otherwise...
|
* using SPI_CS_HIGH can't coexist well otherwise...
|
||||||
*/
|
*/
|
||||||
@ -715,7 +713,8 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
|
|||||||
struct spi_device *proxy;
|
struct spi_device *proxy;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* NOTE: caller did any chip->bus_num checks necessary.
|
/*
|
||||||
|
* NOTE: caller did any chip->bus_num checks necessary.
|
||||||
*
|
*
|
||||||
* Also, unless we change the return value convention to use
|
* Also, unless we change the return value convention to use
|
||||||
* error-or-pointer (not NULL-or-pointer), troubleshootability
|
* error-or-pointer (not NULL-or-pointer), troubleshootability
|
||||||
@ -883,7 +882,6 @@ static void *spi_res_alloc(struct spi_device *spi, spi_res_release_t release,
|
|||||||
/**
|
/**
|
||||||
* spi_res_free - free an spi resource
|
* spi_res_free - free an spi resource
|
||||||
* @res: pointer to the custom data of a resource
|
* @res: pointer to the custom data of a resource
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static void spi_res_free(void *res)
|
static void spi_res_free(void *res)
|
||||||
{
|
{
|
||||||
@ -947,12 +945,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
|
|||||||
spi->controller->last_cs_enable = enable;
|
spi->controller->last_cs_enable = enable;
|
||||||
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
|
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
|
||||||
|
|
||||||
if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) ||
|
if ((spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) ||
|
||||||
!spi->controller->set_cs_timing) {
|
!spi->controller->set_cs_timing) && !activate) {
|
||||||
if (activate)
|
spi_delay_exec(&spi->cs_hold, NULL);
|
||||||
spi_delay_exec(&spi->cs_setup, NULL);
|
|
||||||
else
|
|
||||||
spi_delay_exec(&spi->cs_hold, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spi->mode & SPI_CS_HIGH)
|
if (spi->mode & SPI_CS_HIGH)
|
||||||
@ -978,7 +973,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
|
|||||||
gpiod_set_value_cansleep(spi->cs_gpiod, activate);
|
gpiod_set_value_cansleep(spi->cs_gpiod, activate);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* invert the enable line, as active low is
|
* Invert the enable line, as active low is
|
||||||
* default for SPI.
|
* default for SPI.
|
||||||
*/
|
*/
|
||||||
gpio_set_value_cansleep(spi->cs_gpio, !enable);
|
gpio_set_value_cansleep(spi->cs_gpio, !enable);
|
||||||
@ -994,7 +989,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
|
|||||||
|
|
||||||
if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) ||
|
if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) ||
|
||||||
!spi->controller->set_cs_timing) {
|
!spi->controller->set_cs_timing) {
|
||||||
if (!activate)
|
if (activate)
|
||||||
|
spi_delay_exec(&spi->cs_setup, NULL);
|
||||||
|
else
|
||||||
spi_delay_exec(&spi->cs_inactive, NULL);
|
spi_delay_exec(&spi->cs_inactive, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1227,11 +1224,10 @@ static int spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
|
|||||||
|
|
||||||
if (max_tx) {
|
if (max_tx) {
|
||||||
tmp = krealloc(ctlr->dummy_tx, max_tx,
|
tmp = krealloc(ctlr->dummy_tx, max_tx,
|
||||||
GFP_KERNEL | GFP_DMA);
|
GFP_KERNEL | GFP_DMA | __GFP_ZERO);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
ctlr->dummy_tx = tmp;
|
ctlr->dummy_tx = tmp;
|
||||||
memset(tmp, 0, max_tx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_rx) {
|
if (max_rx) {
|
||||||
@ -1717,16 +1713,7 @@ static void spi_pump_messages(struct kthread_work *work)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_take_timestamp_pre - helper for drivers to collect the beginning of the
|
* spi_take_timestamp_pre - helper to collect the beginning of the TX timestamp
|
||||||
* TX timestamp for the requested byte from the SPI
|
|
||||||
* transfer. The frequency with which this function
|
|
||||||
* must be called (once per word, once for the whole
|
|
||||||
* transfer, once per batch of words etc) is arbitrary
|
|
||||||
* as long as the @tx buffer offset is greater than or
|
|
||||||
* equal to the requested byte at the time of the
|
|
||||||
* call. The timestamp is only taken once, at the
|
|
||||||
* first such call. It is assumed that the driver
|
|
||||||
* advances its @tx buffer pointer monotonically.
|
|
||||||
* @ctlr: Pointer to the spi_controller structure of the driver
|
* @ctlr: Pointer to the spi_controller structure of the driver
|
||||||
* @xfer: Pointer to the transfer being timestamped
|
* @xfer: Pointer to the transfer being timestamped
|
||||||
* @progress: How many words (not bytes) have been transferred so far
|
* @progress: How many words (not bytes) have been transferred so far
|
||||||
@ -1736,6 +1723,14 @@ static void spi_pump_messages(struct kthread_work *work)
|
|||||||
* spi_take_timestamp_post or otherwise system will crash.
|
* spi_take_timestamp_post or otherwise system will crash.
|
||||||
* WARNING: for fully predictable results, the CPU frequency must
|
* WARNING: for fully predictable results, the CPU frequency must
|
||||||
* also be under control (governor).
|
* also be under control (governor).
|
||||||
|
*
|
||||||
|
* This is a helper for drivers to collect the beginning of the TX timestamp
|
||||||
|
* for the requested byte from the SPI transfer. The frequency with which this
|
||||||
|
* function must be called (once per word, once for the whole transfer, once
|
||||||
|
* per batch of words etc) is arbitrary as long as the @tx buffer offset is
|
||||||
|
* greater than or equal to the requested byte at the time of the call. The
|
||||||
|
* timestamp is only taken once, at the first such call. It is assumed that
|
||||||
|
* the driver advances its @tx buffer pointer monotonically.
|
||||||
*/
|
*/
|
||||||
void spi_take_timestamp_pre(struct spi_controller *ctlr,
|
void spi_take_timestamp_pre(struct spi_controller *ctlr,
|
||||||
struct spi_transfer *xfer,
|
struct spi_transfer *xfer,
|
||||||
@ -1763,16 +1758,16 @@ void spi_take_timestamp_pre(struct spi_controller *ctlr,
|
|||||||
EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
|
EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_take_timestamp_post - helper for drivers to collect the end of the
|
* spi_take_timestamp_post - helper to collect the end of the TX timestamp
|
||||||
* TX timestamp for the requested byte from the SPI
|
|
||||||
* transfer. Can be called with an arbitrary
|
|
||||||
* frequency: only the first call where @tx exceeds
|
|
||||||
* or is equal to the requested word will be
|
|
||||||
* timestamped.
|
|
||||||
* @ctlr: Pointer to the spi_controller structure of the driver
|
* @ctlr: Pointer to the spi_controller structure of the driver
|
||||||
* @xfer: Pointer to the transfer being timestamped
|
* @xfer: Pointer to the transfer being timestamped
|
||||||
* @progress: How many words (not bytes) have been transferred so far
|
* @progress: How many words (not bytes) have been transferred so far
|
||||||
* @irqs_off: If true, will re-enable IRQs and preemption for the local CPU.
|
* @irqs_off: If true, will re-enable IRQs and preemption for the local CPU.
|
||||||
|
*
|
||||||
|
* This is a helper for drivers to collect the end of the TX timestamp for
|
||||||
|
* the requested byte from the SPI transfer. Can be called with an arbitrary
|
||||||
|
* frequency: only the first call where @tx exceeds or is equal to the
|
||||||
|
* requested word will be timestamped.
|
||||||
*/
|
*/
|
||||||
void spi_take_timestamp_post(struct spi_controller *ctlr,
|
void spi_take_timestamp_post(struct spi_controller *ctlr,
|
||||||
struct spi_transfer *xfer,
|
struct spi_transfer *xfer,
|
||||||
@ -1905,10 +1900,12 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
|
|||||||
|
|
||||||
spi_unmap_msg(ctlr, mesg);
|
spi_unmap_msg(ctlr, mesg);
|
||||||
|
|
||||||
/* In the prepare_messages callback the spi bus has the opportunity to
|
/*
|
||||||
* split a transfer to smaller chunks.
|
* In the prepare_messages callback the SPI bus has the opportunity
|
||||||
* Release splited transfers here since spi_map_msg is done on the
|
* to split a transfer to smaller chunks.
|
||||||
* splited transfers.
|
*
|
||||||
|
* Release the split transfers here since spi_map_msg() is done on
|
||||||
|
* the split transfers.
|
||||||
*/
|
*/
|
||||||
spi_res_release(ctlr, mesg);
|
spi_res_release(ctlr, mesg);
|
||||||
|
|
||||||
@ -2950,8 +2947,9 @@ int spi_register_controller(struct spi_controller *ctlr)
|
|||||||
if (!ctlr->max_dma_len)
|
if (!ctlr->max_dma_len)
|
||||||
ctlr->max_dma_len = INT_MAX;
|
ctlr->max_dma_len = INT_MAX;
|
||||||
|
|
||||||
/* register the device, then userspace will see it.
|
/*
|
||||||
* registration fails if the bus ID is in use.
|
* Register the device, then userspace will see it.
|
||||||
|
* Registration fails if the bus ID is in use.
|
||||||
*/
|
*/
|
||||||
dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
|
dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
|
||||||
|
|
||||||
@ -3217,16 +3215,18 @@ static struct spi_replaced_transfers *spi_replace_transfers(
|
|||||||
/* init the replaced_transfers list */
|
/* init the replaced_transfers list */
|
||||||
INIT_LIST_HEAD(&rxfer->replaced_transfers);
|
INIT_LIST_HEAD(&rxfer->replaced_transfers);
|
||||||
|
|
||||||
/* assign the list_entry after which we should reinsert
|
/*
|
||||||
|
* Assign the list_entry after which we should reinsert
|
||||||
* the @replaced_transfers - it may be spi_message.messages!
|
* the @replaced_transfers - it may be spi_message.messages!
|
||||||
*/
|
*/
|
||||||
rxfer->replaced_after = xfer_first->transfer_list.prev;
|
rxfer->replaced_after = xfer_first->transfer_list.prev;
|
||||||
|
|
||||||
/* remove the requested number of transfers */
|
/* remove the requested number of transfers */
|
||||||
for (i = 0; i < remove; i++) {
|
for (i = 0; i < remove; i++) {
|
||||||
/* if the entry after replaced_after it is msg->transfers
|
/*
|
||||||
|
* If the entry after replaced_after it is msg->transfers
|
||||||
* then we have been requested to remove more transfers
|
* then we have been requested to remove more transfers
|
||||||
* than are in the list
|
* than are in the list.
|
||||||
*/
|
*/
|
||||||
if (rxfer->replaced_after->next == &msg->transfers) {
|
if (rxfer->replaced_after->next == &msg->transfers) {
|
||||||
dev_err(&msg->spi->dev,
|
dev_err(&msg->spi->dev,
|
||||||
@ -3242,15 +3242,17 @@ static struct spi_replaced_transfers *spi_replace_transfers(
|
|||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove the entry after replaced_after from list of
|
/*
|
||||||
* transfers and add it to list of replaced_transfers
|
* Remove the entry after replaced_after from list of
|
||||||
|
* transfers and add it to list of replaced_transfers.
|
||||||
*/
|
*/
|
||||||
list_move_tail(rxfer->replaced_after->next,
|
list_move_tail(rxfer->replaced_after->next,
|
||||||
&rxfer->replaced_transfers);
|
&rxfer->replaced_transfers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create copy of the given xfer with identical settings
|
/*
|
||||||
* based on the first transfer to get removed
|
* Create copy of the given xfer with identical settings
|
||||||
|
* based on the first transfer to get removed.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < insert; i++) {
|
for (i = 0; i < insert; i++) {
|
||||||
/* we need to run in reverse order */
|
/* we need to run in reverse order */
|
||||||
@ -3298,18 +3300,20 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
|
|||||||
return PTR_ERR(srt);
|
return PTR_ERR(srt);
|
||||||
xfers = srt->inserted_transfers;
|
xfers = srt->inserted_transfers;
|
||||||
|
|
||||||
/* now handle each of those newly inserted spi_transfers
|
/*
|
||||||
* note that the replacements spi_transfers all are preset
|
* Now handle each of those newly inserted spi_transfers.
|
||||||
|
* Note that the replacements spi_transfers all are preset
|
||||||
* to the same values as *xferp, so tx_buf, rx_buf and len
|
* to the same values as *xferp, so tx_buf, rx_buf and len
|
||||||
* are all identical (as well as most others)
|
* are all identical (as well as most others)
|
||||||
* so we just have to fix up len and the pointers.
|
* so we just have to fix up len and the pointers.
|
||||||
*
|
*
|
||||||
* this also includes support for the depreciated
|
* This also includes support for the depreciated
|
||||||
* spi_message.is_dma_mapped interface
|
* spi_message.is_dma_mapped interface.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* the first transfer just needs the length modified, so we
|
/*
|
||||||
* run it outside the loop
|
* The first transfer just needs the length modified, so we
|
||||||
|
* run it outside the loop.
|
||||||
*/
|
*/
|
||||||
xfers[0].len = min_t(size_t, maxsize, xfer[0].len);
|
xfers[0].len = min_t(size_t, maxsize, xfer[0].len);
|
||||||
|
|
||||||
@ -3329,8 +3333,9 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
|
|||||||
xfers[i].len = min(maxsize, xfers[i].len - offset);
|
xfers[i].len = min(maxsize, xfers[i].len - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we set up xferp to the last entry we have inserted,
|
/*
|
||||||
* so that we skip those already split transfers
|
* We set up xferp to the last entry we have inserted,
|
||||||
|
* so that we skip those already split transfers.
|
||||||
*/
|
*/
|
||||||
*xferp = &xfers[count - 1];
|
*xferp = &xfers[count - 1];
|
||||||
|
|
||||||
@ -3362,11 +3367,12 @@ int spi_split_transfers_maxsize(struct spi_controller *ctlr,
|
|||||||
struct spi_transfer *xfer;
|
struct spi_transfer *xfer;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* iterate over the transfer_list,
|
/*
|
||||||
|
* Iterate over the transfer_list,
|
||||||
* but note that xfer is advanced to the last transfer inserted
|
* but note that xfer is advanced to the last transfer inserted
|
||||||
* to avoid checking sizes again unnecessarily (also xfer does
|
* to avoid checking sizes again unnecessarily (also xfer does
|
||||||
* potentiall belong to a different list by the time the
|
* potentially belong to a different list by the time the
|
||||||
* replacement has happened
|
* replacement has happened).
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||||
if (xfer->len > maxsize) {
|
if (xfer->len > maxsize) {
|
||||||
@ -3427,8 +3433,8 @@ int spi_setup(struct spi_device *spi)
|
|||||||
int status;
|
int status;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO
|
* Check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO
|
||||||
* are set at the same time
|
* are set at the same time.
|
||||||
*/
|
*/
|
||||||
if ((hweight_long(spi->mode &
|
if ((hweight_long(spi->mode &
|
||||||
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_NO_TX)) > 1) ||
|
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_NO_TX)) > 1) ||
|
||||||
@ -3438,20 +3444,21 @@ int spi_setup(struct spi_device *spi)
|
|||||||
"setup: can not select any two of dual, quad and no-rx/tx at the same time\n");
|
"setup: can not select any two of dual, quad and no-rx/tx at the same time\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden
|
/* If it is SPI_3WIRE mode, DUAL and QUAD should be forbidden */
|
||||||
*/
|
|
||||||
if ((spi->mode & SPI_3WIRE) && (spi->mode &
|
if ((spi->mode & SPI_3WIRE) && (spi->mode &
|
||||||
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
|
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
|
||||||
SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
|
SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
/* help drivers fail *cleanly* when they need options
|
/*
|
||||||
* that aren't supported with their current controller
|
* Help drivers fail *cleanly* when they need options
|
||||||
|
* that aren't supported with their current controller.
|
||||||
* SPI_CS_WORD has a fallback software implementation,
|
* SPI_CS_WORD has a fallback software implementation,
|
||||||
* so it is ignored here.
|
* so it is ignored here.
|
||||||
*/
|
*/
|
||||||
bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD |
|
bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD |
|
||||||
SPI_NO_TX | SPI_NO_RX);
|
SPI_NO_TX | SPI_NO_RX);
|
||||||
/* nothing prevents from working with active-high CS in case if it
|
/*
|
||||||
|
* Nothing prevents from working with active-high CS in case if it
|
||||||
* is driven by GPIO.
|
* is driven by GPIO.
|
||||||
*/
|
*/
|
||||||
if (gpio_is_valid(spi->cs_gpio))
|
if (gpio_is_valid(spi->cs_gpio))
|
||||||
@ -3573,7 +3580,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
|||||||
if (list_empty(&message->transfers))
|
if (list_empty(&message->transfers))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* If an SPI controller does not support toggling the CS line on each
|
/*
|
||||||
|
* If an SPI controller does not support toggling the CS line on each
|
||||||
* transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
|
* transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
|
||||||
* for the CS line, we can emulate the CS-per-word hardware function by
|
* for the CS line, we can emulate the CS-per-word hardware function by
|
||||||
* splitting transfers into one-word transfers and ensuring that
|
* splitting transfers into one-word transfers and ensuring that
|
||||||
@ -3603,7 +3611,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Half-duplex links include original MicroWire, and ones with
|
/*
|
||||||
|
* Half-duplex links include original MicroWire, and ones with
|
||||||
* only one data pin like SPI_3WIRE (switches direction) or where
|
* only one data pin like SPI_3WIRE (switches direction) or where
|
||||||
* either MOSI or MISO is missing. They can also be caused by
|
* either MOSI or MISO is missing. They can also be caused by
|
||||||
* software limitations.
|
* software limitations.
|
||||||
@ -3622,7 +3631,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Set transfer bits_per_word and max speed as spi device default if
|
* Set transfer bits_per_word and max speed as spi device default if
|
||||||
* it is not set for this transfer.
|
* it is not set for this transfer.
|
||||||
* Set transfer tx_nbits and rx_nbits as single transfer default
|
* Set transfer tx_nbits and rx_nbits as single transfer default
|
||||||
@ -3648,7 +3657,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* SPI transfer length should be multiple of SPI word size
|
* SPI transfer length should be multiple of SPI word size
|
||||||
* where SPI word size should be power-of-two multiple
|
* where SPI word size should be power-of-two multiple.
|
||||||
*/
|
*/
|
||||||
if (xfer->bits_per_word <= 8)
|
if (xfer->bits_per_word <= 8)
|
||||||
w_size = 1;
|
w_size = 1;
|
||||||
@ -3669,7 +3678,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
|||||||
xfer->tx_nbits = SPI_NBITS_SINGLE;
|
xfer->tx_nbits = SPI_NBITS_SINGLE;
|
||||||
if (xfer->rx_buf && !xfer->rx_nbits)
|
if (xfer->rx_buf && !xfer->rx_nbits)
|
||||||
xfer->rx_nbits = SPI_NBITS_SINGLE;
|
xfer->rx_nbits = SPI_NBITS_SINGLE;
|
||||||
/* check transfer tx/rx_nbits:
|
/*
|
||||||
|
* Check transfer tx/rx_nbits:
|
||||||
* 1. check the value matches one of single, dual and quad
|
* 1. check the value matches one of single, dual and quad
|
||||||
* 2. check tx/rx_nbits match the mode in spi_device
|
* 2. check tx/rx_nbits match the mode in spi_device
|
||||||
*/
|
*/
|
||||||
@ -3848,7 +3858,8 @@ static int spi_async_locked(struct spi_device *spi, struct spi_message *message)
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* Utility methods for SPI protocol drivers, layered on
|
/*
|
||||||
|
* Utility methods for SPI protocol drivers, layered on
|
||||||
* top of the core. Some other utility methods are defined as
|
* top of the core. Some other utility methods are defined as
|
||||||
* inline functions.
|
* inline functions.
|
||||||
*/
|
*/
|
||||||
@ -3876,7 +3887,8 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
|
|||||||
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync);
|
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync);
|
||||||
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
|
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
|
||||||
|
|
||||||
/* If we're not using the legacy transfer method then we will
|
/*
|
||||||
|
* If we're not using the legacy transfer method then we will
|
||||||
* try to transfer in the calling context so special case.
|
* try to transfer in the calling context so special case.
|
||||||
* This code would be less tricky if we could remove the
|
* This code would be less tricky if we could remove the
|
||||||
* support for driver implemented message queues.
|
* support for driver implemented message queues.
|
||||||
@ -3894,9 +3906,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
/* Push out the messages in the calling context if we
|
/* Push out the messages in the calling context if we can */
|
||||||
* can.
|
|
||||||
*/
|
|
||||||
if (ctlr->transfer == spi_queued_transfer) {
|
if (ctlr->transfer == spi_queued_transfer) {
|
||||||
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
|
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
|
||||||
spi_sync_immediate);
|
spi_sync_immediate);
|
||||||
@ -4057,7 +4067,8 @@ int spi_write_then_read(struct spi_device *spi,
|
|||||||
struct spi_transfer x[2];
|
struct spi_transfer x[2];
|
||||||
u8 *local_buf;
|
u8 *local_buf;
|
||||||
|
|
||||||
/* Use preallocated DMA-safe buffer if we can. We can't avoid
|
/*
|
||||||
|
* Use preallocated DMA-safe buffer if we can. We can't avoid
|
||||||
* copying here, (as a pure convenience thing), but we can
|
* copying here, (as a pure convenience thing), but we can
|
||||||
* keep heap costs out of the hot path unless someone else is
|
* keep heap costs out of the hot path unless someone else is
|
||||||
* using the pre-allocated buffer or the transfer is too large.
|
* using the pre-allocated buffer or the transfer is too large.
|
||||||
@ -4293,11 +4304,12 @@ err0:
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* board_info is normally registered in arch_initcall(),
|
/*
|
||||||
* but even essential drivers wait till later
|
* A board_info is normally registered in arch_initcall(),
|
||||||
|
* but even essential drivers wait till later.
|
||||||
*
|
*
|
||||||
* REVISIT only boardinfo really needs static linking. the rest (device and
|
* REVISIT only boardinfo really needs static linking. The rest (device and
|
||||||
* driver registration) _could_ be dynamically linked (modular) ... costs
|
* driver registration) _could_ be dynamically linked (modular) ... Costs
|
||||||
* include needing to have boardinfo data structures be much more public.
|
* include needing to have boardinfo data structures be much more public.
|
||||||
*/
|
*/
|
||||||
postcore_initcall(spi_init);
|
postcore_initcall(spi_init);
|
||||||
|
@ -415,7 +415,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||||||
tmp |= SPI_CS_HIGH;
|
tmp |= SPI_CS_HIGH;
|
||||||
|
|
||||||
tmp |= spi->mode & ~SPI_MODE_MASK;
|
tmp |= spi->mode & ~SPI_MODE_MASK;
|
||||||
spi->mode = (u16)tmp;
|
spi->mode = tmp & SPI_MODE_USER_MASK;
|
||||||
retval = spi_setup(spi);
|
retval = spi_setup(spi);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
spi->mode = save;
|
spi->mode = save;
|
||||||
@ -751,9 +751,10 @@ static int spidev_probe(struct spi_device *spi)
|
|||||||
* compatible string, it is a Linux implementation thing
|
* compatible string, it is a Linux implementation thing
|
||||||
* rather than a description of the hardware.
|
* rather than a description of the hardware.
|
||||||
*/
|
*/
|
||||||
WARN(spi->dev.of_node &&
|
if (spi->dev.of_node && of_device_is_compatible(spi->dev.of_node, "spidev")) {
|
||||||
of_device_is_compatible(spi->dev.of_node, "spidev"),
|
dev_err(&spi->dev, "spidev listed directly in DT is not supported\n");
|
||||||
"%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
spidev_probe_acpi(spi);
|
spidev_probe_acpi(spi);
|
||||||
|
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
/*
|
|
||||||
* CLPS711X SPI bus driver definitions
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ____LINUX_PLATFORM_DATA_SPI_CLPS711X_H
|
|
||||||
#define ____LINUX_PLATFORM_DATA_SPI_CLPS711X_H
|
|
||||||
|
|
||||||
/* Board specific platform_data */
|
|
||||||
struct spi_clps711x_pdata {
|
|
||||||
int *chipselect; /* Array of GPIO-numbers */
|
|
||||||
int num_chipselect; /* Total count of GPIOs */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -9,9 +9,6 @@
|
|||||||
|
|
||||||
#include <linux/pxa2xx_ssp.h>
|
#include <linux/pxa2xx_ssp.h>
|
||||||
|
|
||||||
#define PXA2XX_CS_ASSERT (0x01)
|
|
||||||
#define PXA2XX_CS_DEASSERT (0x02)
|
|
||||||
|
|
||||||
struct dma_chan;
|
struct dma_chan;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -45,9 +42,7 @@ struct pxa2xx_spi_chip {
|
|||||||
u8 rx_threshold;
|
u8 rx_threshold;
|
||||||
u8 dma_burst_size;
|
u8 dma_burst_size;
|
||||||
u32 timeout;
|
u32 timeout;
|
||||||
u8 enable_loopback;
|
|
||||||
int gpio_cs;
|
int gpio_cs;
|
||||||
void (*cs_control)(u32 command);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
|
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/ptp_clock_kernel.h>
|
|
||||||
|
|
||||||
#include <uapi/linux/spi/spi.h>
|
#include <uapi/linux/spi/spi.h>
|
||||||
|
|
||||||
struct dma_chan;
|
struct dma_chan;
|
||||||
struct software_node;
|
struct software_node;
|
||||||
|
struct ptp_system_timestamp;
|
||||||
struct spi_controller;
|
struct spi_controller;
|
||||||
struct spi_transfer;
|
struct spi_transfer;
|
||||||
struct spi_controller_mem_ops;
|
struct spi_controller_mem_ops;
|
||||||
|
Loading…
Reference in New Issue
Block a user