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:
|
||||
- $ref: "mtd.yaml#"
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -88,7 +89,7 @@ patternProperties:
|
||||
"^otp(-[0-9]+)?$":
|
||||
type: object
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
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:
|
||||
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:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -43,14 +43,19 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
items:
|
||||
- description: clock used for spi bus
|
||||
- description: clock used for controller
|
||||
- description: clock used for nor dma bus. this depends on hardware
|
||||
design, so this is optional.
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: spi
|
||||
- const: sf
|
||||
- const: axi
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -72,7 +77,7 @@ examples:
|
||||
nor_flash: spi@1100d000 {
|
||||
compatible = "mediatek,mt8173-nor";
|
||||
reg = <0 0x1100d000 0 0xe0>;
|
||||
interrupts = <&spi_flash_irq>;
|
||||
interrupts = <1>;
|
||||
clocks = <&pericfg CLK_PERI_SPI>, <&topckgen CLK_TOP_SPINFI_IFR_SEL>;
|
||||
clock-names = "spi", "sf";
|
||||
#address-cells = <1>;
|
||||
@ -84,4 +89,3 @@ examples:
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,8 @@ properties:
|
||||
- enum:
|
||||
- renesas,rspi-r7s72100 # RZ/A1H
|
||||
- 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:
|
||||
- enum:
|
||||
@ -122,6 +123,7 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,qspi
|
||||
- renesas,r9a07g044-rspi
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
|
@ -94,73 +94,8 @@ patternProperties:
|
||||
"^.*@[0-9a-f]+$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
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.
|
||||
allOf:
|
||||
- $ref: spi-peripheral-props.yaml
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -14,10 +14,13 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
oneOf:
|
||||
- enum:
|
||||
- fsl,imx7ulp-spi
|
||||
- fsl,imx8qxp-spi
|
||||
|
||||
- items:
|
||||
- const: fsl,imx8ulp-spi
|
||||
- const: fsl,imx7ulp-spi
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
|
@ -31,6 +31,7 @@ description: |
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||
- $ref: "/schemas/spi/spi-peripheral-props.yaml#"
|
||||
|
||||
maintainers:
|
||||
- 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: tx
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$":
|
||||
type: object
|
||||
|
@ -101,8 +101,7 @@ device. All fields are optional.
|
||||
u8 rx_threshold;
|
||||
u8 dma_burst_size;
|
||||
u32 timeout;
|
||||
u8 enable_loopback;
|
||||
void (*cs_control)(u32 command);
|
||||
int gpio_cs;
|
||||
};
|
||||
|
||||
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
|
||||
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
|
||||
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)
|
||||
@ -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 = {
|
||||
.tx_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 */
|
||||
.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 = {
|
||||
@ -183,7 +154,7 @@ field. Below is a sample configuration using the PXA255 NSSP.
|
||||
.rx_threshold = 8, /* SSP hardward FIFO threshold */
|
||||
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
||||
.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 = {
|
||||
|
@ -29,21 +29,49 @@ of the driver stack) that are not accessible to userspace.
|
||||
|
||||
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
|
||||
devices. That mechanism might be supported here in the future.)
|
||||
The spidev driver contains lists of SPI devices that are supported for
|
||||
the different hardware topology representations.
|
||||
|
||||
When you do that, the sysfs node for the SPI device will include a child
|
||||
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
|
||||
busybox; it's less featureful, but often enough.) For a SPI device with
|
||||
chipselect C on bus B, you should see:
|
||||
The following are the SPI device tables supported by the spidev driver:
|
||||
|
||||
- struct spi_device_id spidev_spi_ids[]: list of devices that can be
|
||||
bound when these are defined using a struct spi_board_info with a
|
||||
.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 ...
|
||||
character special device, major number 153 with
|
||||
|
@ -211,16 +211,17 @@ static struct ads7846_platform_data ads_info = {
|
||||
// .y_plate_ohms = 500, /* GUESS! */
|
||||
};
|
||||
|
||||
static void ads7846_cs(u32 command)
|
||||
{
|
||||
static const unsigned TS_nCS = 1 << 11;
|
||||
lubbock_set_misc_wr(TS_nCS, (command == PXA2XX_CS_ASSERT) ? 0 : TS_nCS);
|
||||
}
|
||||
static struct gpiod_lookup_table ads7846_cs_gpios = {
|
||||
.dev_id = "ads7846",
|
||||
.table = {
|
||||
GPIO_LOOKUP("lubbock", 11, "cs", GPIO_ACTIVE_LOW),
|
||||
{}
|
||||
},
|
||||
};
|
||||
|
||||
static struct pxa2xx_spi_chip ads_hw = {
|
||||
.tx_threshold = 1,
|
||||
.rx_threshold = 2,
|
||||
.cs_control = ads7846_cs,
|
||||
};
|
||||
|
||||
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";
|
||||
(void) platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
|
||||
gpiod_add_lookup_table(&ads7846_cs_gpios);
|
||||
|
||||
pxa2xx_set_spi_info(1, &pxa_ssp_master_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
|
||||
* 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 = {
|
||||
.tx_threshold = 8,
|
||||
.rx_threshold = 8,
|
||||
|
@ -974,14 +974,13 @@ config SPI_XILINX
|
||||
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
|
||||
|
||||
config SPI_XLP
|
||||
tristate "Netlogic XLP SPI controller driver"
|
||||
depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST
|
||||
tristate "Cavium ThunderX2 SPI controller driver"
|
||||
depends on ARCH_THUNDER2 || COMPILE_TEST
|
||||
help
|
||||
Enable support for the SPI controller on the Netlogic XLP SoCs.
|
||||
Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX
|
||||
and XLP5XX.
|
||||
Enable support for the SPI controller on the Cavium ThunderX2.
|
||||
(Originally on Netlogic XLP SoCs.)
|
||||
|
||||
If you have a Netlogic XLP platform say Y here.
|
||||
If you have a Cavium ThunderX2 platform say Y here.
|
||||
If unsure, say N.
|
||||
|
||||
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;
|
||||
unsigned long trx_done, trx_cur;
|
||||
int stat = 0;
|
||||
u8 term = 0;
|
||||
u8 bpw, term = 0;
|
||||
int div, i;
|
||||
u32 reg;
|
||||
const u8 *tx_buf;
|
||||
@ -90,6 +90,11 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
|
||||
|
||||
m->actual_length = 0;
|
||||
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)
|
||||
div = ar934x_spi_clk_div(sp, t->speed_hz);
|
||||
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(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;
|
||||
if (trx_cur > 4)
|
||||
trx_cur = 4;
|
||||
if (trx_cur > bpw)
|
||||
trx_cur = bpw;
|
||||
else if (list_is_last(&t->transfer_list, &m->transfers))
|
||||
term = 1;
|
||||
|
||||
@ -137,8 +142,10 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
|
||||
reg >>= 8;
|
||||
}
|
||||
}
|
||||
spi_delay_exec(&t->word_delay, t);
|
||||
}
|
||||
m->actual_length += t->len;
|
||||
spi_transfer_delay_exec(t);
|
||||
}
|
||||
|
||||
msg_done:
|
||||
@ -191,7 +198,8 @@ static int ar934x_spi_probe(struct platform_device *pdev)
|
||||
ctlr->mode_bits = SPI_LSB_FIRST;
|
||||
ctlr->setup = ar934x_spi_setup;
|
||||
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->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,
|
||||
struct dma_slave_config *slave_config,
|
||||
u8 bits_per_word)
|
||||
static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(as->pdev);
|
||||
struct dma_slave_config slave_config;
|
||||
int err = 0;
|
||||
|
||||
if (bits_per_word > 8) {
|
||||
slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
slave_config->src_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;
|
||||
} else {
|
||||
slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave_config->src_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->dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
|
||||
slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR;
|
||||
slave_config->src_maxburst = 1;
|
||||
slave_config->dst_maxburst = 1;
|
||||
slave_config->device_fc = false;
|
||||
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_maxburst = 1;
|
||||
slave_config.dst_maxburst = 1;
|
||||
slave_config.device_fc = false;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* the second data into the highest 16 bits of the Transmit
|
||||
* 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
|
||||
* 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,
|
||||
"failed to configure tx dma channel\n");
|
||||
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
|
||||
* 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,
|
||||
"failed to configure rx dma channel\n");
|
||||
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,
|
||||
struct atmel_spi *as)
|
||||
{
|
||||
struct dma_slave_config slave_config;
|
||||
struct device *dev = &as->pdev->dev;
|
||||
int err;
|
||||
|
||||
@ -518,7 +514,7 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = atmel_spi_dma_slave_config(as, &slave_config, 8);
|
||||
err = atmel_spi_dma_slave_config(as, 8);
|
||||
if (err)
|
||||
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_async_tx_descriptor *rxdesc;
|
||||
struct dma_async_tx_descriptor *txdesc;
|
||||
struct dma_slave_config slave_config;
|
||||
dma_cookie_t cookie;
|
||||
|
||||
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;
|
||||
|
||||
if (atmel_spi_dma_slave_config(as, &slave_config,
|
||||
xfer->bits_per_word))
|
||||
if (atmel_spi_dma_slave_config(as, xfer->bits_per_word))
|
||||
goto err_exit;
|
||||
|
||||
/* Send both scatterlists */
|
||||
|
@ -287,6 +287,18 @@ static inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi)
|
||||
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*/
|
||||
static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type,
|
||||
unsigned int offset)
|
||||
@ -586,12 +598,24 @@ static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int 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 */
|
||||
static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
||||
const struct bcm_qspi_parms *xp)
|
||||
{
|
||||
u32 spcr, spbr = 0;
|
||||
|
||||
if (!bcmspi_parms_did_change(xp, &qspi->last_parms))
|
||||
return;
|
||||
|
||||
if (!qspi->mspi_maj_rev)
|
||||
/* legacy controller */
|
||||
spcr = MSPI_MASTER_BIT;
|
||||
@ -621,10 +645,18 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
||||
spcr |= MSPI_SPCR3_HALFDUPLEX | MSPI_SPCR3_HDOUTTYPE;
|
||||
|
||||
if (bcm_qspi_has_sysclk_108(qspi)) {
|
||||
/* SYSCLK_108 */
|
||||
/* check requested baud rate before moving to 108Mhz */
|
||||
spbr = bcm_qspi_calc_spbr(MSPI_BASE_FREQ * 4, xp);
|
||||
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) {
|
||||
/* data_reg_size 1 (64bit) */
|
||||
@ -649,9 +681,9 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
|
||||
}
|
||||
|
||||
if (xp->speed_hz)
|
||||
spbr = qspi->base_clk / (2 * xp->speed_hz);
|
||||
|
||||
/* SCK Baud Rate = System Clock/(2 * SPBR) */
|
||||
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);
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spbr);
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/mfd/dln2.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -688,6 +689,8 @@ static int dln2_spi_probe(struct platform_device *pdev)
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
device_set_node(&master->dev, dev_fwnode(dev));
|
||||
|
||||
platform_set_drvdata(pdev, 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->dev.of_node = dev->of_node;
|
||||
dln2->pdev = pdev;
|
||||
dln2->port = pdata->port;
|
||||
/* 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);
|
||||
|
||||
/* Collect the controller configuration required by the operation */
|
||||
cfg.tmode = SPI_TMOD_EPROMREAD;
|
||||
cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;
|
||||
cfg.dfs = 8;
|
||||
cfg.ndf = 4;
|
||||
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 */
|
||||
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);
|
||||
|
||||
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.
|
||||
@ -339,3 +339,4 @@ module_platform_driver(dw_spi_bt1_driver);
|
||||
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
|
||||
MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(SPI_DW_CORE);
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2009, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
@ -24,7 +25,7 @@
|
||||
#endif
|
||||
|
||||
/* Slave spi_device related */
|
||||
struct chip_data {
|
||||
struct dw_spi_chip_data {
|
||||
u32 cr0;
|
||||
u32 rx_sample_dly; /* RX sample delay */
|
||||
};
|
||||
@ -106,10 +107,10 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
else
|
||||
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 */
|
||||
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;
|
||||
|
||||
@ -129,14 +130,14 @@ static inline u32 tx_max(struct dw_spi *dws)
|
||||
}
|
||||
|
||||
/* 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));
|
||||
}
|
||||
|
||||
static void dw_writer(struct dw_spi *dws)
|
||||
{
|
||||
u32 max = tx_max(dws);
|
||||
u32 max = dw_spi_tx_max(dws);
|
||||
u32 txw = 0;
|
||||
|
||||
while (max--) {
|
||||
@ -157,7 +158,7 @@ static void dw_writer(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;
|
||||
|
||||
while (max--) {
|
||||
@ -186,31 +187,31 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw)
|
||||
else
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
/* Generically handle the erroneous situation */
|
||||
if (ret) {
|
||||
spi_reset_chip(dws);
|
||||
dw_spi_reset_chip(dws);
|
||||
if (dws->master->cur_msg)
|
||||
dws->master->cur_msg->status = 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)
|
||||
{
|
||||
@ -230,7 +231,7 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
|
||||
*/
|
||||
dw_reader(dws);
|
||||
if (!dws->rx_len) {
|
||||
spi_mask_intr(dws, 0xff);
|
||||
dw_spi_mask_intr(dws, 0xff);
|
||||
spi_finalize_current_transfer(dws->master);
|
||||
} else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
|
||||
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
|
||||
* 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);
|
||||
if (!dws->tx_len)
|
||||
spi_mask_intr(dws, SPI_INT_TXEI);
|
||||
dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
|
||||
}
|
||||
|
||||
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 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)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (!master->cur_msg) {
|
||||
spi_mask_intr(dws, 0xff);
|
||||
dw_spi_mask_intr(dws, 0xff);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -271,37 +272,43 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
|
||||
{
|
||||
u32 cr0 = 0;
|
||||
|
||||
if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) {
|
||||
if (dw_spi_ip_is(dws, PSSI)) {
|
||||
/* 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)
|
||||
* CTRLR0[ 6] Serial Clock Phase
|
||||
* CTRLR0[ 7] Serial Clock Polarity
|
||||
*/
|
||||
cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET;
|
||||
cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET;
|
||||
if (spi->mode & SPI_CPOL)
|
||||
cr0 |= DW_PSSI_CTRLR0_SCPOL;
|
||||
if (spi->mode & SPI_CPHA)
|
||||
cr0 |= DW_PSSI_CTRLR0_SCPHA;
|
||||
|
||||
/* 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 {
|
||||
/* 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)
|
||||
* CTRLR0[ 8] Serial Clock Phase
|
||||
* CTRLR0[ 9] Serial Clock Polarity
|
||||
*/
|
||||
cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
|
||||
cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
|
||||
if (spi->mode & SPI_CPOL)
|
||||
cr0 |= DW_HSSI_CTRLR0_SCPOL;
|
||||
if (spi->mode & SPI_CPHA)
|
||||
cr0 |= DW_HSSI_CTRLR0_SCPHA;
|
||||
|
||||
/* 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)
|
||||
cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST;
|
||||
cr0 |= DW_HSSI_CTRLR0_KEEMBAY_MST;
|
||||
}
|
||||
|
||||
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,
|
||||
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 speed_hz;
|
||||
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 */
|
||||
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 */
|
||||
cr0 |= cfg->tmode << SPI_TMOD_OFFSET;
|
||||
cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_TMOD_MASK, cfg->tmode);
|
||||
else
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
|
||||
if (dws->current_freq != speed_hz) {
|
||||
spi_set_clk(dws, clk_div);
|
||||
dw_spi_set_clk(dws, clk_div);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -363,9 +371,9 @@ static void dw_spi_irq_setup(struct dw_spi *dws)
|
||||
|
||||
dws->transfer_handler = dw_spi_transfer_handler;
|
||||
|
||||
imask = SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI |
|
||||
SPI_INT_RXFI;
|
||||
spi_umask_intr(dws, imask);
|
||||
imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI |
|
||||
DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI;
|
||||
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,
|
||||
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_cfg cfg = {
|
||||
.tmode = SPI_TMOD_TR,
|
||||
.tmode = DW_SPI_CTRLR0_TMOD_TR,
|
||||
.dfs = transfer->bits_per_word,
|
||||
.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 */
|
||||
smp_mb();
|
||||
|
||||
spi_enable_chip(dws, 0);
|
||||
dw_spi_enable_chip(dws, 0);
|
||||
|
||||
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;
|
||||
|
||||
/* For poll mode just disable all interrupts */
|
||||
spi_mask_intr(dws, 0xff);
|
||||
dw_spi_mask_intr(dws, 0xff);
|
||||
|
||||
if (dws->dma_mapped) {
|
||||
ret = dws->dma_ops->dma_setup(dws, transfer);
|
||||
@ -444,7 +453,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_enable_chip(dws, 1);
|
||||
dw_spi_enable_chip(dws, 1);
|
||||
|
||||
if (dws->dma_mapped)
|
||||
return dws->dma_ops->dma_transfer(dws, transfer);
|
||||
@ -464,13 +473,13 @@ static void dw_spi_handle_err(struct spi_controller *master,
|
||||
if (dws->dma_mapped)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -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)
|
||||
len += op->data.nbytes;
|
||||
|
||||
if (len <= SPI_BUF_SIZE) {
|
||||
if (len <= DW_SPI_BUF_SIZE) {
|
||||
out = dws->buf;
|
||||
} else {
|
||||
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.
|
||||
*/
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
if (!entries) {
|
||||
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");
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int retry = SPI_WAIT_RETRIES;
|
||||
int retry = DW_SPI_WAIT_RETRIES;
|
||||
struct spi_delay delay;
|
||||
unsigned long ns, us;
|
||||
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)
|
||||
{
|
||||
spi_enable_chip(dws, 0);
|
||||
dw_spi_enable_chip(dws, 0);
|
||||
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.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq);
|
||||
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;
|
||||
} 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);
|
||||
|
||||
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
|
||||
@ -768,7 +777,7 @@ static void dw_spi_init_mem_ops(struct dw_spi *dws)
|
||||
static int dw_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
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 */
|
||||
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);
|
||||
u32 rx_sample_dly_ns;
|
||||
|
||||
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
|
||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
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)
|
||||
{
|
||||
struct chip_data *chip = spi_get_ctldata(spi);
|
||||
struct dw_spi_chip_data *chip = spi_get_ctldata(spi);
|
||||
|
||||
kfree(chip);
|
||||
spi_set_ctldata(spi, NULL);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
@ -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
|
||||
* 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);
|
||||
|
||||
spi_enable_chip(dws, 0);
|
||||
dw_spi_enable_chip(dws, 0);
|
||||
dw_writel(dws, DW_SPI_CTRLR0, 0xffffffff);
|
||||
cr0 = dw_readl(dws, DW_SPI_CTRLR0);
|
||||
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->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");
|
||||
}
|
||||
} else {
|
||||
@ -872,13 +895,15 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
device_set_node(&master->dev, dev_fwnode(dev));
|
||||
|
||||
dws->master = master;
|
||||
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
|
||||
|
||||
spi_controller_set_devdata(master, dws);
|
||||
|
||||
/* 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),
|
||||
master);
|
||||
@ -908,8 +933,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||
if (dws->mem_ops.exec_op)
|
||||
master->mem_ops = &dws->mem_ops;
|
||||
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->auto_runtime_pm = true;
|
||||
|
||||
@ -939,13 +962,13 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||
err_dma_exit:
|
||||
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
||||
dws->dma_ops->dma_exit(dws);
|
||||
spi_enable_chip(dws, 0);
|
||||
dw_spi_enable_chip(dws, 0);
|
||||
free_irq(dws->irq, master);
|
||||
err_free_master:
|
||||
spi_controller_put(master);
|
||||
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)
|
||||
{
|
||||
@ -956,11 +979,11 @@ void dw_spi_remove_host(struct dw_spi *dws)
|
||||
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
||||
dws->dma_ops->dma_exit(dws);
|
||||
|
||||
spi_shutdown_chip(dws);
|
||||
dw_spi_shutdown_chip(dws);
|
||||
|
||||
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)
|
||||
{
|
||||
@ -970,17 +993,17 @@ int dw_spi_suspend_host(struct dw_spi *dws)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_shutdown_chip(dws);
|
||||
dw_spi_shutdown_chip(dws);
|
||||
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)
|
||||
{
|
||||
spi_hw_init(&dws->master->dev, dws);
|
||||
dw_spi_hw_init(&dws->master->dev, dws);
|
||||
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_DESCRIPTION("Driver for DesignWare SPI controller core");
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_data/dma-dw.h>
|
||||
#include <linux/spi/spi.h>
|
||||
@ -17,10 +18,10 @@
|
||||
|
||||
#include "spi-dw.h"
|
||||
|
||||
#define RX_BUSY 0
|
||||
#define RX_BURST_LEVEL 16
|
||||
#define TX_BUSY 1
|
||||
#define TX_BURST_LEVEL 16
|
||||
#define DW_SPI_RX_BUSY 0
|
||||
#define DW_SPI_RX_BURST_LEVEL 16
|
||||
#define DW_SPI_TX_BUSY 1
|
||||
#define DW_SPI_TX_BURST_LEVEL 16
|
||||
|
||||
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)
|
||||
max_burst = caps.max_burst;
|
||||
else
|
||||
max_burst = RX_BURST_LEVEL;
|
||||
max_burst = DW_SPI_RX_BURST_LEVEL;
|
||||
|
||||
dws->rxburst = min(max_burst, def_burst);
|
||||
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)
|
||||
max_burst = caps.max_burst;
|
||||
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
|
||||
@ -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)
|
||||
{
|
||||
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,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
int retry = SPI_WAIT_RETRIES;
|
||||
int retry = DW_SPI_WAIT_RETRIES;
|
||||
struct spi_delay delay;
|
||||
u32 nents;
|
||||
|
||||
@ -259,8 +260,8 @@ static void dw_spi_dma_tx_done(void *arg)
|
||||
{
|
||||
struct dw_spi *dws = arg;
|
||||
|
||||
clear_bit(TX_BUSY, &dws->dma_chan_busy);
|
||||
if (test_bit(RX_BUSY, &dws->dma_chan_busy))
|
||||
clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
|
||||
if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy))
|
||||
return;
|
||||
|
||||
complete(&dws->dma_completion);
|
||||
@ -304,19 +305,19 @@ static int dw_spi_dma_submit_tx(struct dw_spi *dws, struct scatterlist *sgl,
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_bit(TX_BUSY, &dws->dma_chan_busy);
|
||||
set_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int retry = SPI_WAIT_RETRIES;
|
||||
int retry = DW_SPI_WAIT_RETRIES;
|
||||
struct spi_delay delay;
|
||||
unsigned long ns, us;
|
||||
u32 nents;
|
||||
@ -360,8 +361,8 @@ static void dw_spi_dma_rx_done(void *arg)
|
||||
{
|
||||
struct dw_spi *dws = arg;
|
||||
|
||||
clear_bit(RX_BUSY, &dws->dma_chan_busy);
|
||||
if (test_bit(TX_BUSY, &dws->dma_chan_busy))
|
||||
clear_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
|
||||
if (test_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy))
|
||||
return;
|
||||
|
||||
complete(&dws->dma_completion);
|
||||
@ -405,7 +406,7 @@ static int dw_spi_dma_submit_rx(struct dw_spi *dws, struct scatterlist *sgl,
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_bit(RX_BUSY, &dws->dma_chan_busy);
|
||||
set_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
|
||||
|
||||
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 */
|
||||
dma_ctrl = SPI_DMA_TDMAE;
|
||||
dma_ctrl = DW_SPI_DMACR_TDMAE;
|
||||
if (xfer->rx_buf)
|
||||
dma_ctrl |= SPI_DMA_RDMAE;
|
||||
dma_ctrl |= DW_SPI_DMACR_RDMAE;
|
||||
dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
|
||||
|
||||
/* Set the interrupt mask */
|
||||
imr = SPI_INT_TXOI;
|
||||
imr = DW_SPI_INT_TXOI;
|
||||
if (xfer->rx_buf)
|
||||
imr |= SPI_INT_RXUI | SPI_INT_RXOI;
|
||||
spi_umask_intr(dws, imr);
|
||||
imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI;
|
||||
dw_spi_umask_intr(dws, imr);
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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 = {
|
||||
.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;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_spi_dma_setup_generic);
|
||||
EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_generic, SPI_DW_CORE);
|
||||
|
@ -196,7 +196,7 @@ static int dw_spi_alpine_init(struct platform_device *pdev,
|
||||
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)
|
||||
{
|
||||
dw_spi_dma_setup_generic(&dwsmmio->dws);
|
||||
@ -204,10 +204,10 @@ static int dw_spi_dw_apb_init(struct platform_device *pdev,
|
||||
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)
|
||||
{
|
||||
dwsmmio->dws.caps = DW_SPI_CAP_DWC_SSI;
|
||||
dwsmmio->dws.ip = DW_HSSI_ID;
|
||||
|
||||
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,
|
||||
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;
|
||||
}
|
||||
@ -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[] = {
|
||||
{ .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,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
|
||||
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
|
||||
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init},
|
||||
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
|
||||
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
|
||||
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
|
||||
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
|
||||
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_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
|
||||
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);
|
||||
@ -377,3 +378,4 @@ module_platform_driver(dw_spi_mmio_driver);
|
||||
MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
|
||||
MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(SPI_DW_CORE);
|
||||
|
@ -24,14 +24,14 @@
|
||||
#define CLK_SPI_CDIV_MASK 0x00000e00
|
||||
#define CLK_SPI_DISABLE_OFFSET 8
|
||||
|
||||
struct spi_pci_desc {
|
||||
struct dw_spi_pci_desc {
|
||||
int (*setup)(struct dw_spi *);
|
||||
u16 num_cs;
|
||||
u16 bus_num;
|
||||
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;
|
||||
u32 clk_cdiv;
|
||||
@ -53,36 +53,36 @@ static int spi_mid_init(struct dw_spi *dws)
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_pci_desc spi_pci_mid_desc_1 = {
|
||||
.setup = spi_mid_init,
|
||||
static struct dw_spi_pci_desc dw_spi_pci_mid_desc_1 = {
|
||||
.setup = dw_spi_pci_mid_init,
|
||||
.num_cs = 5,
|
||||
.bus_num = 0,
|
||||
};
|
||||
|
||||
static struct spi_pci_desc spi_pci_mid_desc_2 = {
|
||||
.setup = spi_mid_init,
|
||||
static struct dw_spi_pci_desc dw_spi_pci_mid_desc_2 = {
|
||||
.setup = dw_spi_pci_mid_init,
|
||||
.num_cs = 2,
|
||||
.bus_num = 1,
|
||||
};
|
||||
|
||||
static struct spi_pci_desc spi_pci_ehl_desc = {
|
||||
.setup = spi_generic_init,
|
||||
static struct dw_spi_pci_desc dw_spi_pci_ehl_desc = {
|
||||
.setup = dw_spi_pci_generic_init,
|
||||
.num_cs = 2,
|
||||
.bus_num = -1,
|
||||
.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 spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data;
|
||||
int pci_bar = 0;
|
||||
int ret;
|
||||
|
||||
@ -150,7 +150,7 @@ err_free_irq_vectors:
|
||||
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);
|
||||
|
||||
@ -162,14 +162,14 @@ static void spi_pci_remove(struct pci_dev *pdev)
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
||||
@ -177,39 +177,39 @@ static int spi_resume(struct device *dev)
|
||||
}
|
||||
#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 */
|
||||
/*
|
||||
* The access to the device 8086:0801 is disabled by HW, since it's
|
||||
* exclusively used by SCU to communicate with MSIC.
|
||||
*/
|
||||
/* 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 */
|
||||
{ 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 */
|
||||
{ PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&spi_pci_ehl_desc},
|
||||
{ PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&spi_pci_ehl_desc},
|
||||
{ PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&spi_pci_ehl_desc},
|
||||
{ PCI_VDEVICE(INTEL, 0x4b87), (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)&dw_spi_pci_ehl_desc},
|
||||
{ PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&dw_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,
|
||||
.id_table = pci_ids,
|
||||
.probe = spi_pci_probe,
|
||||
.remove = spi_pci_remove,
|
||||
.id_table = dw_spi_pci_ids,
|
||||
.probe = dw_spi_pci_probe,
|
||||
.remove = dw_spi_pci_remove,
|
||||
.driver = {
|
||||
.pm = &dw_spi_pm_ops,
|
||||
.pm = &dw_spi_pci_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_pci_driver(dw_spi_driver);
|
||||
module_pci_driver(dw_spi_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
|
||||
MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(SPI_DW_CORE);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef DW_SPI_HEADER_H
|
||||
#define DW_SPI_HEADER_H
|
||||
#ifndef __SPI_DW_H__
|
||||
#define __SPI_DW_H__
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/completion.h>
|
||||
@ -11,7 +11,30 @@
|
||||
#include <linux/spi/spi-mem.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_CTRLR1 0x04
|
||||
#define DW_SPI_SSIENR 0x08
|
||||
@ -40,92 +63,79 @@
|
||||
#define DW_SPI_RX_SAMPLE_DLY 0xf0
|
||||
#define DW_SPI_CS_OVERRIDE 0xf4
|
||||
|
||||
/* Bit fields in CTRLR0 */
|
||||
#define SPI_DFS_OFFSET 0
|
||||
#define SPI_DFS_MASK GENMASK(3, 0)
|
||||
#define SPI_DFS32_OFFSET 16
|
||||
/* Bit fields in CTRLR0 (DWC APB SSI) */
|
||||
#define DW_PSSI_CTRLR0_DFS_MASK GENMASK(3, 0)
|
||||
#define DW_PSSI_CTRLR0_DFS32_MASK GENMASK(20, 16)
|
||||
|
||||
#define SPI_FRF_OFFSET 4
|
||||
#define SPI_FRF_SPI 0x0
|
||||
#define SPI_FRF_SSP 0x1
|
||||
#define SPI_FRF_MICROWIRE 0x2
|
||||
#define SPI_FRF_RESV 0x3
|
||||
#define DW_PSSI_CTRLR0_FRF_MASK GENMASK(5, 4)
|
||||
#define DW_SPI_CTRLR0_FRF_MOTO_SPI 0x0
|
||||
#define DW_SPI_CTRLR0_FRF_TI_SSP 0x1
|
||||
#define DW_SPI_CTRLR0_FRF_NS_MICROWIRE 0x2
|
||||
#define DW_SPI_CTRLR0_FRF_RESV 0x3
|
||||
|
||||
#define SPI_MODE_OFFSET 6
|
||||
#define SPI_SCPH_OFFSET 6
|
||||
#define SPI_SCOL_OFFSET 7
|
||||
#define DW_PSSI_CTRLR0_MODE_MASK GENMASK(7, 6)
|
||||
#define DW_PSSI_CTRLR0_SCPHA BIT(6)
|
||||
#define DW_PSSI_CTRLR0_SCPOL BIT(7)
|
||||
|
||||
#define SPI_TMOD_OFFSET 8
|
||||
#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET)
|
||||
#define SPI_TMOD_TR 0x0 /* xmit & recv */
|
||||
#define SPI_TMOD_TO 0x1 /* xmit only */
|
||||
#define SPI_TMOD_RO 0x2 /* recv only */
|
||||
#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
|
||||
#define DW_PSSI_CTRLR0_TMOD_MASK GENMASK(9, 8)
|
||||
#define DW_SPI_CTRLR0_TMOD_TR 0x0 /* xmit & recv */
|
||||
#define DW_SPI_CTRLR0_TMOD_TO 0x1 /* xmit only */
|
||||
#define DW_SPI_CTRLR0_TMOD_RO 0x2 /* recv only */
|
||||
#define DW_SPI_CTRLR0_TMOD_EPROMREAD 0x3 /* eeprom read mode */
|
||||
|
||||
#define SPI_SLVOE_OFFSET 10
|
||||
#define SPI_SRL_OFFSET 11
|
||||
#define SPI_CFS_OFFSET 12
|
||||
#define DW_PSSI_CTRLR0_SLV_OE BIT(10)
|
||||
#define DW_PSSI_CTRLR0_SRL BIT(11)
|
||||
#define DW_PSSI_CTRLR0_CFS BIT(12)
|
||||
|
||||
/* Bit fields in CTRLR0 based on DWC_ssi_databook.pdf v1.01a */
|
||||
#define DWC_SSI_CTRLR0_SRL_OFFSET 13
|
||||
#define DWC_SSI_CTRLR0_TMOD_OFFSET 10
|
||||
#define DWC_SSI_CTRLR0_TMOD_MASK GENMASK(11, 10)
|
||||
#define DWC_SSI_CTRLR0_SCPOL_OFFSET 9
|
||||
#define DWC_SSI_CTRLR0_SCPH_OFFSET 8
|
||||
#define DWC_SSI_CTRLR0_FRF_OFFSET 6
|
||||
#define DWC_SSI_CTRLR0_DFS_OFFSET 0
|
||||
/* Bit fields in CTRLR0 (DWC SSI with AHB interface) */
|
||||
#define DW_HSSI_CTRLR0_DFS_MASK GENMASK(4, 0)
|
||||
#define DW_HSSI_CTRLR0_FRF_MASK GENMASK(7, 6)
|
||||
#define DW_HSSI_CTRLR0_SCPHA BIT(8)
|
||||
#define DW_HSSI_CTRLR0_SCPOL BIT(9)
|
||||
#define DW_HSSI_CTRLR0_TMOD_MASK GENMASK(11, 10)
|
||||
#define DW_HSSI_CTRLR0_SRL BIT(13)
|
||||
|
||||
/*
|
||||
* For Keem Bay, CTRLR0[31] is used to select controller mode.
|
||||
* 0: SSI is slave
|
||||
* 1: SSI is master
|
||||
*/
|
||||
#define DWC_SSI_CTRLR0_KEEMBAY_MST BIT(31)
|
||||
#define DW_HSSI_CTRLR0_KEEMBAY_MST BIT(31)
|
||||
|
||||
/* 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 */
|
||||
#define SR_MASK 0x7f /* cover 7 bits */
|
||||
#define SR_BUSY (1 << 0)
|
||||
#define SR_TF_NOT_FULL (1 << 1)
|
||||
#define SR_TF_EMPT (1 << 2)
|
||||
#define SR_RF_NOT_EMPT (1 << 3)
|
||||
#define SR_RF_FULL (1 << 4)
|
||||
#define SR_TX_ERR (1 << 5)
|
||||
#define SR_DCOL (1 << 6)
|
||||
#define DW_SPI_SR_MASK GENMASK(6, 0)
|
||||
#define DW_SPI_SR_BUSY BIT(0)
|
||||
#define DW_SPI_SR_TF_NOT_FULL BIT(1)
|
||||
#define DW_SPI_SR_TF_EMPT BIT(2)
|
||||
#define DW_SPI_SR_RF_NOT_EMPT BIT(3)
|
||||
#define DW_SPI_SR_RF_FULL BIT(4)
|
||||
#define DW_SPI_SR_TX_ERR BIT(5)
|
||||
#define DW_SPI_SR_DCOL BIT(6)
|
||||
|
||||
/* Bit fields in ISR, IMR, RISR, 7 bits */
|
||||
#define SPI_INT_TXEI (1 << 0)
|
||||
#define SPI_INT_TXOI (1 << 1)
|
||||
#define SPI_INT_RXUI (1 << 2)
|
||||
#define SPI_INT_RXOI (1 << 3)
|
||||
#define SPI_INT_RXFI (1 << 4)
|
||||
#define SPI_INT_MSTI (1 << 5)
|
||||
#define DW_SPI_INT_MASK GENMASK(5, 0)
|
||||
#define DW_SPI_INT_TXEI BIT(0)
|
||||
#define DW_SPI_INT_TXOI BIT(1)
|
||||
#define DW_SPI_INT_RXUI BIT(2)
|
||||
#define DW_SPI_INT_RXOI BIT(3)
|
||||
#define DW_SPI_INT_RXFI BIT(4)
|
||||
#define DW_SPI_INT_MSTI BIT(5)
|
||||
|
||||
/* Bit fields in DMACR */
|
||||
#define SPI_DMA_RDMAE (1 << 0)
|
||||
#define SPI_DMA_TDMAE (1 << 1)
|
||||
#define DW_SPI_DMACR_RDMAE BIT(0)
|
||||
#define DW_SPI_DMACR_TDMAE BIT(1)
|
||||
|
||||
#define SPI_WAIT_RETRIES 5
|
||||
#define SPI_BUF_SIZE \
|
||||
/* Mem/DMA operations helpers */
|
||||
#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, addr.val) + 256)
|
||||
#define SPI_GET_BYTE(_val, _idx) \
|
||||
#define DW_SPI_GET_BYTE(_val, _idx) \
|
||||
((_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 */
|
||||
struct dw_spi_cfg {
|
||||
u8 tmode;
|
||||
@ -148,6 +158,10 @@ struct dw_spi_dma_ops {
|
||||
struct dw_spi {
|
||||
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;
|
||||
unsigned long paddr;
|
||||
int irq;
|
||||
@ -156,8 +170,6 @@ struct dw_spi {
|
||||
u32 max_mem_freq; /* max mem-ops bus freq */
|
||||
u32 max_freq; /* max bus freq supported */
|
||||
|
||||
u32 caps; /* DW SPI capabilities */
|
||||
|
||||
u32 reg_io_width; /* DR I/O width in bytes */
|
||||
u16 bus_num;
|
||||
u16 num_cs; /* supported slave numbers */
|
||||
@ -168,7 +180,7 @@ struct dw_spi {
|
||||
unsigned int tx_len;
|
||||
void *rx;
|
||||
unsigned int rx_len;
|
||||
u8 buf[SPI_BUF_SIZE];
|
||||
u8 buf[DW_SPI_BUF_SIZE];
|
||||
int dma_mapped;
|
||||
u8 n_bytes; /* current is a 1/2 bytes op */
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
@ -250,7 +262,7 @@ static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
@ -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
|
||||
* 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);
|
||||
spi_mask_intr(dws, 0xff);
|
||||
dw_spi_enable_chip(dws, 0);
|
||||
dw_spi_mask_intr(dws, 0xff);
|
||||
dw_readl(dws, DW_SPI_ICR);
|
||||
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);
|
||||
spi_set_clk(dws, 0);
|
||||
dw_spi_enable_chip(dws, 0);
|
||||
dw_spi_set_clk(dws, 0);
|
||||
}
|
||||
|
||||
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 /* 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);
|
||||
if (ret < 0) {
|
||||
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);
|
||||
@ -921,6 +921,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
free_dma:
|
||||
fsl_lpspi_dma_exit(controller);
|
||||
out_pm_get:
|
||||
pm_runtime_dont_use_autosuspend(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 =
|
||||
spi_controller_get_devdata(controller);
|
||||
|
||||
fsl_lpspi_dma_exit(controller);
|
||||
|
||||
pm_runtime_disable(fsl_lpspi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
@ -71,10 +71,6 @@
|
||||
#define GSI_CPHA BIT(4)
|
||||
#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 geni_se se;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
spi->cur_msg->status = -EIO;
|
||||
if (result->result != DMA_TRANS_NOERROR) {
|
||||
dev_err(&spi->dev, "DMA txn failed: %d\n", result->result);
|
||||
spi_finalize_current_transfer(spi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result->residue) {
|
||||
spi->cur_msg->status = 0;
|
||||
dev_dbg(&spi->dev, "DMA txn completed\n");
|
||||
spi_finalize_current_transfer(spi);
|
||||
} else {
|
||||
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,
|
||||
@ -922,7 +946,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
spi->can_dma = geni_can_dma;
|
||||
spi->dma_map_dev = dev->parent;
|
||||
spi->auto_runtime_pm = true;
|
||||
spi->handle_err = handle_fifo_timeout;
|
||||
spi->handle_err = spi_geni_handle_err;
|
||||
spi->use_gpio_descriptors = true;
|
||||
|
||||
init_completion(&mas->cs_done);
|
||||
|
@ -127,7 +127,6 @@ struct hisi_spi {
|
||||
void __iomem *regs;
|
||||
int irq;
|
||||
u32 fifo_len; /* depth of the FIFO buffer */
|
||||
u16 bus_num;
|
||||
|
||||
/* Current message transfer state info */
|
||||
const void *tx;
|
||||
@ -165,7 +164,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs)
|
||||
{
|
||||
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);
|
||||
if (!hs->debugfs)
|
||||
return -ENOMEM;
|
||||
@ -467,7 +469,6 @@ static int hisi_spi_probe(struct platform_device *pdev)
|
||||
hs = spi_controller_get_devdata(master);
|
||||
hs->dev = dev;
|
||||
hs->irq = irq;
|
||||
hs->bus_num = pdev->id;
|
||||
|
||||
hs->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hs->regs))
|
||||
@ -490,7 +491,7 @@ static int hisi_spi_probe(struct platform_device *pdev)
|
||||
master->use_gpio_descriptors = true;
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
|
||||
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->cleanup = hisi_spi_cleanup;
|
||||
master->transfer_one = hisi_spi_transfer_one;
|
||||
@ -506,15 +507,15 @@ static int hisi_spi_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hisi_spi_debugfs_init(hs))
|
||||
dev_info(dev, "failed to create debugfs dir\n");
|
||||
|
||||
ret = spi_register_controller(master);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register spi master, ret=%d\n", 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",
|
||||
readl(hs->regs + HISI_SPI_VERSION),
|
||||
master->max_speed_hz / 1000);
|
||||
|
@ -349,6 +349,7 @@ static int meson_spifc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
out_clk:
|
||||
clk_disable_unprepare(spifc->clk);
|
||||
pm_runtime_disable(spifc->dev);
|
||||
out_err:
|
||||
spi_master_put(master);
|
||||
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)
|
||||
{
|
||||
struct chip_data *chip = spi_get_ctldata(spi);
|
||||
struct driver_data *drv_data =
|
||||
spi_controller_get_devdata(spi->controller);
|
||||
|
||||
@ -436,18 +435,12 @@ static void cs_assert(struct spi_device *spi)
|
||||
return;
|
||||
}
|
||||
|
||||
if (chip->cs_control) {
|
||||
chip->cs_control(PXA2XX_CS_ASSERT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_lpss_ssp(drv_data))
|
||||
lpss_ssp_cs_control(spi, true);
|
||||
}
|
||||
|
||||
static void cs_deassert(struct spi_device *spi)
|
||||
{
|
||||
struct chip_data *chip = spi_get_ctldata(spi);
|
||||
struct driver_data *drv_data =
|
||||
spi_controller_get_devdata(spi->controller);
|
||||
unsigned long timeout;
|
||||
@ -461,11 +454,6 @@ static void cs_deassert(struct spi_device *spi)
|
||||
!time_after(jiffies, timeout))
|
||||
cpu_relax();
|
||||
|
||||
if (chip->cs_control) {
|
||||
chip->cs_control(PXA2XX_CS_DEASSERT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_lpss_ssp(drv_data))
|
||||
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");
|
||||
return -EIO;
|
||||
}
|
||||
drv_data->n_bytes = chip->n_bytes;
|
||||
drv_data->tx = (void *)transfer->tx_buf;
|
||||
drv_data->tx_end = drv_data->tx + transfer->len;
|
||||
drv_data->rx = transfer->rx_buf;
|
||||
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 */
|
||||
bits = transfer->bits_per_word;
|
||||
@ -1010,22 +995,16 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
|
||||
|
||||
if (bits <= 8) {
|
||||
drv_data->n_bytes = 1;
|
||||
drv_data->read = drv_data->read != null_reader ?
|
||||
u8_reader : null_reader;
|
||||
drv_data->write = drv_data->write != null_writer ?
|
||||
u8_writer : null_writer;
|
||||
drv_data->read = drv_data->rx ? u8_reader : null_reader;
|
||||
drv_data->write = drv_data->tx ? u8_writer : null_writer;
|
||||
} else if (bits <= 16) {
|
||||
drv_data->n_bytes = 2;
|
||||
drv_data->read = drv_data->read != null_reader ?
|
||||
u16_reader : null_reader;
|
||||
drv_data->write = drv_data->write != null_writer ?
|
||||
u16_writer : null_writer;
|
||||
drv_data->read = drv_data->rx ? u16_reader : null_reader;
|
||||
drv_data->write = drv_data->tx ? u16_writer : null_writer;
|
||||
} else if (bits <= 32) {
|
||||
drv_data->n_bytes = 4;
|
||||
drv_data->read = drv_data->read != null_reader ?
|
||||
u32_reader : null_reader;
|
||||
drv_data->write = drv_data->write != null_writer ?
|
||||
u32_writer : null_writer;
|
||||
drv_data->read = drv_data->rx ? u32_reader : null_reader;
|
||||
drv_data->write = drv_data->tx ? u32_writer : null_writer;
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* 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)) {
|
||||
int gpio = chip_info->gpio_cs;
|
||||
int err;
|
||||
@ -1316,7 +1289,6 @@ static int setup(struct spi_device *spi)
|
||||
chip_info = spi->controller_data;
|
||||
|
||||
/* chip_info isn't always needed */
|
||||
chip->cr1 = 0;
|
||||
if (chip_info) {
|
||||
if (chip_info->timeout)
|
||||
chip->timeout = chip_info->timeout;
|
||||
@ -1327,9 +1299,9 @@ static int setup(struct spi_device *spi)
|
||||
if (chip_info->rx_threshold)
|
||||
rx_thres = chip_info->rx_threshold;
|
||||
chip->dma_threshold = 0;
|
||||
if (chip_info->enable_loopback)
|
||||
chip->cr1 = SSCR1_LBM;
|
||||
}
|
||||
|
||||
chip->cr1 = 0;
|
||||
if (spi_controller_is_slave(drv_data->controller)) {
|
||||
chip->cr1 |= SSCR1_SCFR;
|
||||
chip->cr1 |= SSCR1_SCLKDIR;
|
||||
@ -1391,20 +1363,6 @@ static int setup(struct spi_device *spi)
|
||||
if (spi->mode & SPI_LOOP)
|
||||
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);
|
||||
|
||||
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->ssp = ssp;
|
||||
|
||||
controller->dev.of_node = dev->of_node;
|
||||
controller->dev.fwnode = dev->fwnode;
|
||||
device_set_node(&controller->dev, dev_fwnode(dev));
|
||||
|
||||
/* The spi->mode bits understood by this driver: */
|
||||
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 (*read)(struct driver_data *drv_data);
|
||||
irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
|
||||
void (*cs_control)(u32 command);
|
||||
|
||||
void __iomem *lpss_base;
|
||||
|
||||
@ -61,18 +60,12 @@ struct chip_data {
|
||||
u32 cr1;
|
||||
u32 dds_rate;
|
||||
u32 timeout;
|
||||
u8 n_bytes;
|
||||
u8 enable_dma;
|
||||
u32 dma_burst_size;
|
||||
u32 dma_threshold;
|
||||
u32 threshold;
|
||||
u16 lpss_rx_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)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/spi/spi.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;
|
||||
|
||||
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)
|
||||
return ret;
|
||||
}
|
||||
@ -1225,8 +1226,14 @@ static const struct of_device_id 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)
|
||||
{
|
||||
struct reset_control *rstc;
|
||||
u32 num_cs;
|
||||
int error;
|
||||
|
||||
@ -1238,6 +1245,24 @@ static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#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 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)
|
||||
return NULL;
|
||||
|
||||
@ -888,14 +888,6 @@ static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_devic
|
||||
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)
|
||||
{
|
||||
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;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
|
||||
master->setup = tegra_qspi_setup;
|
||||
master->cleanup = tegra_qspi_cleanup;
|
||||
master->transfer_one_message = tegra_qspi_transfer_one_message;
|
||||
master->num_chipselect = 1;
|
||||
master->auto_runtime_pm = true;
|
||||
|
@ -767,12 +767,13 @@ out_master_put:
|
||||
|
||||
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)
|
||||
dma_release_channel(priv->master->dma_tx);
|
||||
if (priv->master->dma_rx)
|
||||
dma_release_channel(priv->master->dma_rx);
|
||||
if (master->dma_tx)
|
||||
dma_release_channel(master->dma_tx);
|
||||
if (master->dma_rx)
|
||||
dma_release_channel(master->dma_rx);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
/* 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);
|
||||
#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 = {
|
||||
.probe = xlp_spi_probe,
|
||||
.driver = {
|
||||
.name = "xlp-spi",
|
||||
.of_match_table = xlp_spi_dt_id,
|
||||
.acpi_match_table = ACPI_PTR(xlp_spi_acpi_match),
|
||||
},
|
||||
};
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/platform_data/x86/apple.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#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);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,
|
||||
const struct spi_device *sdev)
|
||||
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, const char *name)
|
||||
{
|
||||
while (id->name[0]) {
|
||||
if (!strcmp(sdev->modalias, id->name))
|
||||
if (!strcmp(name, id->name))
|
||||
return 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);
|
||||
|
||||
return spi_match_id(sdrv->id_table, sdev);
|
||||
return spi_match_id(sdrv->id_table, sdev->modalias);
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
@ -474,12 +474,8 @@ int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
|
||||
if (sdrv->id_table) {
|
||||
const struct spi_device_id *spi_id;
|
||||
|
||||
for (spi_id = sdrv->id_table; spi_id->name[0];
|
||||
spi_id++)
|
||||
if (strcmp(spi_id->name, of_name) == 0)
|
||||
break;
|
||||
|
||||
if (spi_id->name[0])
|
||||
spi_id = spi_match_id(sdrv->id_table, of_name);
|
||||
if (spi_id)
|
||||
continue;
|
||||
} else {
|
||||
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.
|
||||
* Device registration normally goes into like arch/.../mach.../board-YYY.c
|
||||
* 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
|
||||
* spi_controller list, and their matching process
|
||||
* also used to protect object of type struct idr
|
||||
* spi_controller list, and their matching process also used
|
||||
* to protect object of type struct idr.
|
||||
*/
|
||||
static DEFINE_MUTEX(board_lock);
|
||||
|
||||
@ -621,7 +618,8 @@ static int __spi_add_device(struct spi_device *spi)
|
||||
else if (ctlr->cs_gpios)
|
||||
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
|
||||
* 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;
|
||||
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
|
||||
* 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
|
||||
* @res: pointer to the custom data of a resource
|
||||
*
|
||||
*/
|
||||
static void spi_res_free(void *res)
|
||||
{
|
||||
@ -947,11 +945,8 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
|
||||
spi->controller->last_cs_enable = enable;
|
||||
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
|
||||
|
||||
if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) ||
|
||||
!spi->controller->set_cs_timing) {
|
||||
if (activate)
|
||||
spi_delay_exec(&spi->cs_setup, NULL);
|
||||
else
|
||||
if ((spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) ||
|
||||
!spi->controller->set_cs_timing) && !activate) {
|
||||
spi_delay_exec(&spi->cs_hold, NULL);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
} else {
|
||||
/*
|
||||
* invert the enable line, as active low is
|
||||
* Invert the enable line, as active low is
|
||||
* default for SPI.
|
||||
*/
|
||||
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) ||
|
||||
!spi->controller->set_cs_timing) {
|
||||
if (!activate)
|
||||
if (activate)
|
||||
spi_delay_exec(&spi->cs_setup, NULL);
|
||||
else
|
||||
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) {
|
||||
tmp = krealloc(ctlr->dummy_tx, max_tx,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
GFP_KERNEL | GFP_DMA | __GFP_ZERO);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
ctlr->dummy_tx = tmp;
|
||||
memset(tmp, 0, max_tx);
|
||||
}
|
||||
|
||||
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
|
||||
* 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.
|
||||
* spi_take_timestamp_pre - helper to collect the beginning of the TX timestamp
|
||||
* @ctlr: Pointer to the spi_controller structure of the driver
|
||||
* @xfer: Pointer to the transfer being timestamped
|
||||
* @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.
|
||||
* WARNING: for fully predictable results, the CPU frequency must
|
||||
* 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,
|
||||
struct spi_transfer *xfer,
|
||||
@ -1763,16 +1758,16 @@ void spi_take_timestamp_pre(struct spi_controller *ctlr,
|
||||
EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
|
||||
|
||||
/**
|
||||
* spi_take_timestamp_post - 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.
|
||||
* spi_take_timestamp_post - helper to collect the end of the TX timestamp
|
||||
* @ctlr: Pointer to the spi_controller structure of the driver
|
||||
* @xfer: Pointer to the transfer being timestamped
|
||||
* @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.
|
||||
*
|
||||
* 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,
|
||||
struct spi_transfer *xfer,
|
||||
@ -1905,10 +1900,12 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
|
||||
|
||||
spi_unmap_msg(ctlr, mesg);
|
||||
|
||||
/* In the prepare_messages callback the spi bus has the opportunity to
|
||||
* split a transfer to smaller chunks.
|
||||
* Release splited transfers here since spi_map_msg is done on the
|
||||
* splited transfers.
|
||||
/*
|
||||
* In the prepare_messages callback the SPI bus has the opportunity
|
||||
* to split a transfer to smaller chunks.
|
||||
*
|
||||
* Release the split transfers here since spi_map_msg() is done on
|
||||
* the split transfers.
|
||||
*/
|
||||
spi_res_release(ctlr, mesg);
|
||||
|
||||
@ -2950,8 +2947,9 @@ int spi_register_controller(struct spi_controller *ctlr)
|
||||
if (!ctlr->max_dma_len)
|
||||
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);
|
||||
|
||||
@ -3217,16 +3215,18 @@ static struct spi_replaced_transfers *spi_replace_transfers(
|
||||
/* init the replaced_transfers list */
|
||||
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!
|
||||
*/
|
||||
rxfer->replaced_after = xfer_first->transfer_list.prev;
|
||||
|
||||
/* remove the requested number of transfers */
|
||||
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
|
||||
* than are in the list
|
||||
* than are in the list.
|
||||
*/
|
||||
if (rxfer->replaced_after->next == &msg->transfers) {
|
||||
dev_err(&msg->spi->dev,
|
||||
@ -3242,15 +3242,17 @@ static struct spi_replaced_transfers *spi_replace_transfers(
|
||||
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,
|
||||
&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++) {
|
||||
/* 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);
|
||||
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
|
||||
* are all identical (as well as most others)
|
||||
* so we just have to fix up len and the pointers.
|
||||
*
|
||||
* this also includes support for the depreciated
|
||||
* spi_message.is_dma_mapped interface
|
||||
* This also includes support for the depreciated
|
||||
* 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);
|
||||
|
||||
@ -3329,8 +3333,9 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
|
||||
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];
|
||||
|
||||
@ -3362,11 +3367,12 @@ int spi_split_transfers_maxsize(struct spi_controller *ctlr,
|
||||
struct spi_transfer *xfer;
|
||||
int ret;
|
||||
|
||||
/* iterate over the transfer_list,
|
||||
/*
|
||||
* Iterate over the transfer_list,
|
||||
* but note that xfer is advanced to the last transfer inserted
|
||||
* to avoid checking sizes again unnecessarily (also xfer does
|
||||
* potentiall belong to a different list by the time the
|
||||
* replacement has happened
|
||||
* potentially belong to a different list by the time the
|
||||
* replacement has happened).
|
||||
*/
|
||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||
if (xfer->len > maxsize) {
|
||||
@ -3427,8 +3433,8 @@ int spi_setup(struct spi_device *spi)
|
||||
int status;
|
||||
|
||||
/*
|
||||
* check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO
|
||||
* are set at the same time
|
||||
* Check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO
|
||||
* are set at the same time.
|
||||
*/
|
||||
if ((hweight_long(spi->mode &
|
||||
(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");
|
||||
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 &
|
||||
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
|
||||
SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
|
||||
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,
|
||||
* so it is ignored here.
|
||||
*/
|
||||
bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD |
|
||||
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.
|
||||
*/
|
||||
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))
|
||||
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
|
||||
* for the CS line, we can emulate the CS-per-word hardware function by
|
||||
* 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
|
||||
* either MOSI or MISO is missing. They can also be caused by
|
||||
* 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
|
||||
* it is not set for this transfer.
|
||||
* 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
|
||||
* 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)
|
||||
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;
|
||||
if (xfer->rx_buf && !xfer->rx_nbits)
|
||||
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
|
||||
* 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
|
||||
* 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(&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.
|
||||
* This code would be less tricky if we could remove the
|
||||
* 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) {
|
||||
/* Push out the messages in the calling context if we
|
||||
* can.
|
||||
*/
|
||||
/* Push out the messages in the calling context if we can */
|
||||
if (ctlr->transfer == spi_queued_transfer) {
|
||||
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
|
||||
spi_sync_immediate);
|
||||
@ -4057,7 +4067,8 @@ int spi_write_then_read(struct spi_device *spi,
|
||||
struct spi_transfer x[2];
|
||||
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
|
||||
* keep heap costs out of the hot path unless someone else is
|
||||
* using the pre-allocated buffer or the transfer is too large.
|
||||
@ -4293,11 +4304,12 @@ err0:
|
||||
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
|
||||
* driver registration) _could_ be dynamically linked (modular) ... costs
|
||||
* REVISIT only boardinfo really needs static linking. The rest (device and
|
||||
* driver registration) _could_ be dynamically linked (modular) ... Costs
|
||||
* include needing to have boardinfo data structures be much more public.
|
||||
*/
|
||||
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->mode & ~SPI_MODE_MASK;
|
||||
spi->mode = (u16)tmp;
|
||||
spi->mode = tmp & SPI_MODE_USER_MASK;
|
||||
retval = spi_setup(spi);
|
||||
if (retval < 0)
|
||||
spi->mode = save;
|
||||
@ -751,9 +751,10 @@ static int spidev_probe(struct spi_device *spi)
|
||||
* compatible string, it is a Linux implementation thing
|
||||
* rather than a description of the hardware.
|
||||
*/
|
||||
WARN(spi->dev.of_node &&
|
||||
of_device_is_compatible(spi->dev.of_node, "spidev"),
|
||||
"%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
|
||||
if (spi->dev.of_node && of_device_is_compatible(spi->dev.of_node, "spidev")) {
|
||||
dev_err(&spi->dev, "spidev listed directly in DT is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
#define PXA2XX_CS_ASSERT (0x01)
|
||||
#define PXA2XX_CS_DEASSERT (0x02)
|
||||
|
||||
struct dma_chan;
|
||||
|
||||
/*
|
||||
@ -45,9 +42,7 @@ struct pxa2xx_spi_chip {
|
||||
u8 rx_threshold;
|
||||
u8 dma_burst_size;
|
||||
u32 timeout;
|
||||
u8 enable_loopback;
|
||||
int gpio_cs;
|
||||
void (*cs_control)(u32 command);
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
|
||||
|
@ -14,12 +14,12 @@
|
||||
#include <linux/completion.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
#include <uapi/linux/spi/spi.h>
|
||||
|
||||
struct dma_chan;
|
||||
struct software_node;
|
||||
struct ptp_system_timestamp;
|
||||
struct spi_controller;
|
||||
struct spi_transfer;
|
||||
struct spi_controller_mem_ops;
|
||||
|
Loading…
Reference in New Issue
Block a user