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:
Linus Torvalds 2022-01-11 12:19:47 -08:00
commit 282aa44c21
42 changed files with 846 additions and 681 deletions

View File

@ -11,6 +11,7 @@ maintainers:
allOf: allOf:
- $ref: "mtd.yaml#" - $ref: "mtd.yaml#"
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties: properties:
compatible: compatible:
@ -88,7 +89,7 @@ patternProperties:
"^otp(-[0-9]+)?$": "^otp(-[0-9]+)?$":
type: object type: object
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |

View 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>;
};
};

View File

@ -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 {
...
};
};

View File

@ -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

View File

@ -87,39 +87,6 @@ properties:
items: items:
enum: [ qspi, qspi-ocp ] enum: [ qspi, qspi-ocp ]
# subnode's properties
patternProperties:
"@[0-9a-f]+$":
type: object
description:
Flash device uses the below defined properties in the subnode.
properties:
cdns,read-delay:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Delay for read capture logic, in clock cycles.
cdns,tshsl-ns:
description:
Delay in nanoseconds for the length that the master mode chip select
outputs are de-asserted between transactions.
cdns,tsd2d-ns:
description:
Delay in nanoseconds between one chip select being de-activated
and the activation of another.
cdns,tchsh-ns:
description:
Delay in nanoseconds between last bit of current transaction and
deasserting the device chip select (qspi_n_ss_out).
cdns,tslch-ns:
description:
Delay in nanoseconds between setting qspi_n_ss_out low and
first bit transfer.
required: required:
- compatible - compatible
- reg - reg

View File

@ -43,14 +43,19 @@ properties:
maxItems: 1 maxItems: 1
clocks: clocks:
minItems: 2
items: items:
- description: clock used for spi bus - description: clock used for spi bus
- description: clock used for controller - description: clock used for controller
- description: clock used for nor dma bus. this depends on hardware
design, so this is optional.
clock-names: clock-names:
minItems: 2
items: items:
- const: spi - const: spi
- const: sf - const: sf
- const: axi
required: required:
- compatible - compatible
@ -72,7 +77,7 @@ examples:
nor_flash: spi@1100d000 { nor_flash: spi@1100d000 {
compatible = "mediatek,mt8173-nor"; compatible = "mediatek,mt8173-nor";
reg = <0 0x1100d000 0 0xe0>; reg = <0 0x1100d000 0 0xe0>;
interrupts = <&spi_flash_irq>; interrupts = <1>;
clocks = <&pericfg CLK_PERI_SPI>, <&topckgen CLK_TOP_SPINFI_IFR_SEL>; clocks = <&pericfg CLK_PERI_SPI>, <&topckgen CLK_TOP_SPINFI_IFR_SEL>;
clock-names = "spi", "sf"; clock-names = "spi", "sf";
#address-cells = <1>; #address-cells = <1>;
@ -84,4 +89,3 @@ examples:
}; };
}; };
}; };

View File

@ -21,7 +21,8 @@ properties:
- enum: - enum:
- renesas,rspi-r7s72100 # RZ/A1H - renesas,rspi-r7s72100 # RZ/A1H
- renesas,rspi-r7s9210 # RZ/A2 - renesas,rspi-r7s9210 # RZ/A2
- const: renesas,rspi-rz # RZ/A - renesas,r9a07g044-rspi # RZ/G2{L,LC}
- const: renesas,rspi-rz # RZ/A and RZ/G2{L,LC}
- items: - items:
- enum: - enum:
@ -122,6 +123,7 @@ allOf:
contains: contains:
enum: enum:
- renesas,qspi - renesas,qspi
- renesas,r9a07g044-rspi
then: then:
required: required:
- resets - resets

View File

@ -94,73 +94,8 @@ patternProperties:
"^.*@[0-9a-f]+$": "^.*@[0-9a-f]+$":
type: object type: object
properties: allOf:
compatible: - $ref: spi-peripheral-props.yaml
description:
Compatible of the SPI device.
reg:
minItems: 1
maxItems: 256
items:
minimum: 0
maximum: 256
description:
Chip select used by the device.
spi-3wire:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires 3-wire mode.
spi-cpha:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires shifted clock phase (CPHA) mode.
spi-cpol:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires inverse clock polarity (CPOL) mode.
spi-cs-high:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires the chip select active high.
spi-lsb-first:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires the LSB first mode.
spi-max-frequency:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Maximum SPI clocking speed of the device in Hz.
spi-rx-bus-width:
description:
Bus width to the SPI bus used for read transfers.
If 0 is provided, then no RX will be possible on this device.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 4, 8]
default: 1
spi-rx-delay-us:
description:
Delay, in microseconds, after a read transfer.
spi-tx-bus-width:
description:
Bus width to the SPI bus used for write transfers.
If 0 is provided, then no TX will be possible on this device.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 4, 8]
default: 1
spi-tx-delay-us:
description:
Delay, in microseconds, after a write transfer.
required: required:
- compatible - compatible

View File

@ -14,10 +14,13 @@ allOf:
properties: properties:
compatible: compatible:
enum: oneOf:
- fsl,imx7ulp-spi - enum:
- fsl,imx8qxp-spi - fsl,imx7ulp-spi
- fsl,imx8qxp-spi
- items:
- const: fsl,imx8ulp-spi
- const: fsl,imx7ulp-spi
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -31,6 +31,7 @@ description: |
allOf: allOf:
- $ref: "/schemas/spi/spi-controller.yaml#" - $ref: "/schemas/spi/spi-controller.yaml#"
- $ref: "/schemas/spi/spi-peripheral-props.yaml#"
maintainers: maintainers:
- Chris Packham <chris.packham@alliedtelesis.co.nz> - Chris Packham <chris.packham@alliedtelesis.co.nz>

View File

@ -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

View File

@ -72,6 +72,9 @@ properties:
- const: rx - const: rx
- const: tx - const: tx
resets:
maxItems: 1
patternProperties: patternProperties:
"^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$": "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$":
type: object type: object

View File

@ -101,8 +101,7 @@ device. All fields are optional.
u8 rx_threshold; u8 rx_threshold;
u8 dma_burst_size; u8 dma_burst_size;
u32 timeout; u32 timeout;
u8 enable_loopback; int gpio_cs;
void (*cs_control)(u32 command);
}; };
The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are
@ -128,16 +127,6 @@ dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
slave device. Please note that the PXA2xx SSP 1 does not support trailing byte slave device. Please note that the PXA2xx SSP 1 does not support trailing byte
timeouts and must busy-wait any trailing bytes. timeouts and must busy-wait any trailing bytes.
The "pxa2xx_spi_chip.enable_loopback" field is used to place the SSP porting
into internal loopback mode. In this mode the SSP controller internally
connects the SSPTX pin to the SSPRX pin. This is useful for initial setup
testing.
The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific
function for asserting/deasserting a slave device chip select. If the field is
NULL, the pxa2xx_spi master controller driver assumes that the SSP port is
configured to use GPIO or SSPFRM instead.
NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the
chipselect is dropped after each spi_transfer. Most devices need chip select chipselect is dropped after each spi_transfer. Most devices need chip select
asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor) asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor)
@ -152,30 +141,12 @@ field. Below is a sample configuration using the PXA255 NSSP.
:: ::
/* Chip Select control for the CS8415A SPI slave device */
static void cs8415a_cs_control(u32 command)
{
if (command & PXA2XX_CS_ASSERT)
GPCR(2) = GPIO_bit(2);
else
GPSR(2) = GPIO_bit(2);
}
/* Chip Select control for the CS8405A SPI slave device */
static void cs8405a_cs_control(u32 command)
{
if (command & PXA2XX_CS_ASSERT)
GPCR(3) = GPIO_bit(3);
else
GPSR(3) = GPIO_bit(3);
}
static struct pxa2xx_spi_chip cs8415a_chip_info = { static struct pxa2xx_spi_chip cs8415a_chip_info = {
.tx_threshold = 8, /* SSP hardward FIFO threshold */ .tx_threshold = 8, /* SSP hardward FIFO threshold */
.rx_threshold = 8, /* SSP hardward FIFO threshold */ .rx_threshold = 8, /* SSP hardward FIFO threshold */
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
.timeout = 235, /* See Intel documentation */ .timeout = 235, /* See Intel documentation */
.cs_control = cs8415a_cs_control, /* Use external chip select */ .gpio_cs = 2, /* Use external chip select */
}; };
static struct pxa2xx_spi_chip cs8405a_chip_info = { static struct pxa2xx_spi_chip cs8405a_chip_info = {
@ -183,7 +154,7 @@ field. Below is a sample configuration using the PXA255 NSSP.
.rx_threshold = 8, /* SSP hardward FIFO threshold */ .rx_threshold = 8, /* SSP hardward FIFO threshold */
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
.timeout = 235, /* See Intel documentation */ .timeout = 235, /* See Intel documentation */
.cs_control = cs8405a_cs_control, /* Use external chip select */ .gpio_cs = 3, /* Use external chip select */
}; };
static struct spi_board_info streetracer_spi_board_info[] __initdata = { static struct spi_board_info streetracer_spi_board_info[] __initdata = {

View File

@ -29,21 +29,49 @@ of the driver stack) that are not accessible to userspace.
DEVICE CREATION, DRIVER BINDING DEVICE CREATION, DRIVER BINDING
=============================== ===============================
The simplest way to arrange to use this driver is to just list it in the
spi_board_info for a device as the driver it should use: the "modalias"
entry is "spidev", matching the name of the driver exposing this API.
Set up the other device characteristics (bits per word, SPI clocking,
chipselect polarity, etc) as usual, so you won't always need to override
them later.
(Sysfs also supports userspace driven binding/unbinding of drivers to The spidev driver contains lists of SPI devices that are supported for
devices. That mechanism might be supported here in the future.) the different hardware topology representations.
When you do that, the sysfs node for the SPI device will include a child The following are the SPI device tables supported by the spidev driver:
device node with a "dev" attribute that will be understood by udev or mdev.
(Larger systems will have "udev". Smaller ones may configure "mdev" into - struct spi_device_id spidev_spi_ids[]: list of devices that can be
busybox; it's less featureful, but often enough.) For a SPI device with bound when these are defined using a struct spi_board_info with a
chipselect C on bus B, you should see: .modalias field matching one of the entries in the table.
- struct of_device_id spidev_dt_ids[]: list of devices that can be
bound when these are defined using a Device Tree node that has a
compatible string matching one of the entries in the table.
- struct acpi_device_id spidev_acpi_ids[]: list of devices that can
be bound when these are defined using a ACPI device object with a
_HID matching one of the entries in the table.
You are encouraged to add an entry for your SPI device name to relevant
tables, if these don't already have an entry for the device. To do that,
post a patch for spidev to the linux-spi@vger.kernel.org mailing list.
It used to be supported to define an SPI device using the "spidev" name.
For example, as .modalias = "spidev" or compatible = "spidev". But this
is no longer supported by the Linux kernel and instead a real SPI device
name as listed in one of the tables must be used.
Not having a real SPI device name will lead to an error being printed and
the spidev driver failing to probe.
Sysfs also supports userspace driven binding/unbinding of drivers to
devices that do not bind automatically using one of the tables above.
To make the spidev driver bind to such a device, use the following:
echo spidev > /sys/bus/spi/devices/spiB.C/driver_override
echo spiB.C > /sys/bus/spi/drivers/spidev/bind
When the spidev driver is bound to a SPI device, the sysfs node for the
device will include a child device node with a "dev" attribute that will
be understood by udev or mdev (udev replacement from BusyBox; it's less
featureful, but often enough).
For a SPI device with chipselect C on bus B, you should see:
/dev/spidevB.C ... /dev/spidevB.C ...
character special device, major number 153 with character special device, major number 153 with

View File

@ -211,16 +211,17 @@ static struct ads7846_platform_data ads_info = {
// .y_plate_ohms = 500, /* GUESS! */ // .y_plate_ohms = 500, /* GUESS! */
}; };
static void ads7846_cs(u32 command) static struct gpiod_lookup_table ads7846_cs_gpios = {
{ .dev_id = "ads7846",
static const unsigned TS_nCS = 1 << 11; .table = {
lubbock_set_misc_wr(TS_nCS, (command == PXA2XX_CS_ASSERT) ? 0 : TS_nCS); GPIO_LOOKUP("lubbock", 11, "cs", GPIO_ACTIVE_LOW),
} {}
},
};
static struct pxa2xx_spi_chip ads_hw = { static struct pxa2xx_spi_chip ads_hw = {
.tx_threshold = 1, .tx_threshold = 1,
.rx_threshold = 2, .rx_threshold = 2,
.cs_control = ads7846_cs,
}; };
static struct spi_board_info spi_board_info[] __initdata = { { static struct spi_board_info spi_board_info[] __initdata = { {
@ -512,6 +513,8 @@ static void __init lubbock_init(void)
lubbock_flash_data[flashboot].name = "boot-rom"; lubbock_flash_data[flashboot].name = "boot-rom";
(void) platform_add_devices(devices, ARRAY_SIZE(devices)); (void) platform_add_devices(devices, ARRAY_SIZE(devices));
gpiod_add_lookup_table(&ads7846_cs_gpios);
pxa2xx_set_spi_info(1, &pxa_ssp_master_info); pxa2xx_set_spi_info(1, &pxa_ssp_master_info);
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
} }

View File

@ -347,7 +347,7 @@ static struct pxa2xx_spi_controller pxa_ssp_master_2_info = {
}; };
/* An upcoming kernel change will scrap SFRM usage so these /* An upcoming kernel change will scrap SFRM usage so these
* drivers have been moved to use gpio's via cs_control */ * drivers have been moved to use GPIOs */
static struct pxa2xx_spi_chip staccel_chip_info = { static struct pxa2xx_spi_chip staccel_chip_info = {
.tx_threshold = 8, .tx_threshold = 8,
.rx_threshold = 8, .rx_threshold = 8,

View File

@ -974,14 +974,13 @@ config SPI_XILINX
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
config SPI_XLP config SPI_XLP
tristate "Netlogic XLP SPI controller driver" tristate "Cavium ThunderX2 SPI controller driver"
depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST depends on ARCH_THUNDER2 || COMPILE_TEST
help help
Enable support for the SPI controller on the Netlogic XLP SoCs. Enable support for the SPI controller on the Cavium ThunderX2.
Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX (Originally on Netlogic XLP SoCs.)
and XLP5XX.
If you have a Netlogic XLP platform say Y here. If you have a Cavium ThunderX2 platform say Y here.
If unsure, say N. If unsure, say N.
config SPI_XTENSA_XTFPGA config SPI_XTENSA_XTFPGA

View File

@ -82,7 +82,7 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
struct spi_device *spi = m->spi; struct spi_device *spi = m->spi;
unsigned long trx_done, trx_cur; unsigned long trx_done, trx_cur;
int stat = 0; int stat = 0;
u8 term = 0; u8 bpw, term = 0;
int div, i; int div, i;
u32 reg; u32 reg;
const u8 *tx_buf; const u8 *tx_buf;
@ -90,6 +90,11 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
m->actual_length = 0; m->actual_length = 0;
list_for_each_entry(t, &m->transfers, transfer_list) { list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->bits_per_word >= 8 && t->bits_per_word < 32)
bpw = t->bits_per_word >> 3;
else
bpw = 4;
if (t->speed_hz) if (t->speed_hz)
div = ar934x_spi_clk_div(sp, t->speed_hz); div = ar934x_spi_clk_div(sp, t->speed_hz);
else else
@ -105,10 +110,10 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL); iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL);
iowrite32(0, sp->base + AR934X_SPI_DATAOUT); iowrite32(0, sp->base + AR934X_SPI_DATAOUT);
for (trx_done = 0; trx_done < t->len; trx_done += 4) { for (trx_done = 0; trx_done < t->len; trx_done += bpw) {
trx_cur = t->len - trx_done; trx_cur = t->len - trx_done;
if (trx_cur > 4) if (trx_cur > bpw)
trx_cur = 4; trx_cur = bpw;
else if (list_is_last(&t->transfer_list, &m->transfers)) else if (list_is_last(&t->transfer_list, &m->transfers))
term = 1; term = 1;
@ -137,8 +142,10 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
reg >>= 8; reg >>= 8;
} }
} }
spi_delay_exec(&t->word_delay, t);
} }
m->actual_length += t->len; m->actual_length += t->len;
spi_transfer_delay_exec(t);
} }
msg_done: msg_done:
@ -191,7 +198,8 @@ static int ar934x_spi_probe(struct platform_device *pdev)
ctlr->mode_bits = SPI_LSB_FIRST; ctlr->mode_bits = SPI_LSB_FIRST;
ctlr->setup = ar934x_spi_setup; ctlr->setup = ar934x_spi_setup;
ctlr->transfer_one_message = ar934x_spi_transfer_one_message; ctlr->transfer_one_message = ar934x_spi_transfer_one_message;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
ctlr->dev.of_node = pdev->dev.of_node; ctlr->dev.of_node = pdev->dev.of_node;
ctlr->num_chipselect = 3; ctlr->num_chipselect = 3;

View File

@ -433,26 +433,25 @@ static bool atmel_spi_can_dma(struct spi_master *master,
} }
static int atmel_spi_dma_slave_config(struct atmel_spi *as, static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
struct dma_slave_config *slave_config,
u8 bits_per_word)
{ {
struct spi_master *master = platform_get_drvdata(as->pdev); struct spi_master *master = platform_get_drvdata(as->pdev);
struct dma_slave_config slave_config;
int err = 0; int err = 0;
if (bits_per_word > 8) { if (bits_per_word > 8) {
slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
} else { } else {
slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
} }
slave_config->dst_addr = (dma_addr_t)as->phybase + SPI_TDR; slave_config.dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR; slave_config.src_addr = (dma_addr_t)as->phybase + SPI_RDR;
slave_config->src_maxburst = 1; slave_config.src_maxburst = 1;
slave_config->dst_maxburst = 1; slave_config.dst_maxburst = 1;
slave_config->device_fc = false; slave_config.device_fc = false;
/* /*
* This driver uses fixed peripheral select mode (PS bit set to '0' in * This driver uses fixed peripheral select mode (PS bit set to '0' in
@ -464,12 +463,11 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
* However, the first data has to be written into the lowest 16 bits and * However, the first data has to be written into the lowest 16 bits and
* the second data into the highest 16 bits of the Transmit * the second data into the highest 16 bits of the Transmit
* Data Register. For 8bit data (the most frequent case), it would * Data Register. For 8bit data (the most frequent case), it would
* require to rework tx_buf so each data would actualy fit 16 bits. * require to rework tx_buf so each data would actually fit 16 bits.
* So we'd rather write only one data at the time. Hence the transmit * So we'd rather write only one data at the time. Hence the transmit
* path works the same whether FIFOs are available (and enabled) or not. * path works the same whether FIFOs are available (and enabled) or not.
*/ */
slave_config->direction = DMA_MEM_TO_DEV; if (dmaengine_slave_config(master->dma_tx, &slave_config)) {
if (dmaengine_slave_config(master->dma_tx, slave_config)) {
dev_err(&as->pdev->dev, dev_err(&as->pdev->dev,
"failed to configure tx dma channel\n"); "failed to configure tx dma channel\n");
err = -EINVAL; err = -EINVAL;
@ -483,8 +481,7 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
* So the receive path works the same whether FIFOs are available (and * So the receive path works the same whether FIFOs are available (and
* enabled) or not. * enabled) or not.
*/ */
slave_config->direction = DMA_DEV_TO_MEM; if (dmaengine_slave_config(master->dma_rx, &slave_config)) {
if (dmaengine_slave_config(master->dma_rx, slave_config)) {
dev_err(&as->pdev->dev, dev_err(&as->pdev->dev,
"failed to configure rx dma channel\n"); "failed to configure rx dma channel\n");
err = -EINVAL; err = -EINVAL;
@ -496,7 +493,6 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
static int atmel_spi_configure_dma(struct spi_master *master, static int atmel_spi_configure_dma(struct spi_master *master,
struct atmel_spi *as) struct atmel_spi *as)
{ {
struct dma_slave_config slave_config;
struct device *dev = &as->pdev->dev; struct device *dev = &as->pdev->dev;
int err; int err;
@ -518,7 +514,7 @@ static int atmel_spi_configure_dma(struct spi_master *master,
goto error; goto error;
} }
err = atmel_spi_dma_slave_config(as, &slave_config, 8); err = atmel_spi_dma_slave_config(as, 8);
if (err) if (err)
goto error; goto error;
@ -700,7 +696,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
struct dma_chan *txchan = master->dma_tx; struct dma_chan *txchan = master->dma_tx;
struct dma_async_tx_descriptor *rxdesc; struct dma_async_tx_descriptor *rxdesc;
struct dma_async_tx_descriptor *txdesc; struct dma_async_tx_descriptor *txdesc;
struct dma_slave_config slave_config;
dma_cookie_t cookie; dma_cookie_t cookie;
dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n"); dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n");
@ -712,8 +707,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
*plen = xfer->len; *plen = xfer->len;
if (atmel_spi_dma_slave_config(as, &slave_config, if (atmel_spi_dma_slave_config(as, xfer->bits_per_word))
xfer->bits_per_word))
goto err_exit; goto err_exit;
/* Send both scatterlists */ /* Send both scatterlists */

View File

@ -287,6 +287,18 @@ static inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi)
return 8; return 8;
} }
static u32 bcm_qspi_calc_spbr(u32 clk_speed_hz,
const struct bcm_qspi_parms *xp)
{
u32 spbr = 0;
/* SPBR = System Clock/(2 * SCK Baud Rate) */
if (xp->speed_hz)
spbr = clk_speed_hz / (xp->speed_hz * 2);
return spbr;
}
/* Read qspi controller register*/ /* Read qspi controller register*/
static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type, static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type,
unsigned int offset) unsigned int offset)
@ -586,12 +598,24 @@ static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs)
qspi->curr_cs = cs; qspi->curr_cs = cs;
} }
static bool bcmspi_parms_did_change(const struct bcm_qspi_parms * const cur,
const struct bcm_qspi_parms * const prev)
{
return (cur->speed_hz != prev->speed_hz) ||
(cur->mode != prev->mode) ||
(cur->bits_per_word != prev->bits_per_word);
}
/* MSPI helpers */ /* MSPI helpers */
static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi, static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
const struct bcm_qspi_parms *xp) const struct bcm_qspi_parms *xp)
{ {
u32 spcr, spbr = 0; u32 spcr, spbr = 0;
if (!bcmspi_parms_did_change(xp, &qspi->last_parms))
return;
if (!qspi->mspi_maj_rev) if (!qspi->mspi_maj_rev)
/* legacy controller */ /* legacy controller */
spcr = MSPI_MASTER_BIT; spcr = MSPI_MASTER_BIT;
@ -621,9 +645,17 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
spcr |= MSPI_SPCR3_HALFDUPLEX | MSPI_SPCR3_HDOUTTYPE; spcr |= MSPI_SPCR3_HALFDUPLEX | MSPI_SPCR3_HDOUTTYPE;
if (bcm_qspi_has_sysclk_108(qspi)) { if (bcm_qspi_has_sysclk_108(qspi)) {
/* SYSCLK_108 */ /* check requested baud rate before moving to 108Mhz */
spcr |= MSPI_SPCR3_SYSCLKSEL_108; spbr = bcm_qspi_calc_spbr(MSPI_BASE_FREQ * 4, xp);
qspi->base_clk = MSPI_BASE_FREQ * 4; if (spbr > QSPI_SPBR_MAX) {
/* use SYSCLK_27Mhz for slower baud rates */
spcr &= ~MSPI_SPCR3_SYSCLKSEL_MASK;
qspi->base_clk = MSPI_BASE_FREQ;
} else {
/* SYSCLK_108Mhz */
spcr |= MSPI_SPCR3_SYSCLKSEL_108;
qspi->base_clk = MSPI_BASE_FREQ * 4;
}
} }
if (xp->bits_per_word > 16) { if (xp->bits_per_word > 16) {
@ -649,9 +681,9 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr); bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
} }
if (xp->speed_hz) /* SCK Baud Rate = System Clock/(2 * SPBR) */
spbr = qspi->base_clk / (2 * xp->speed_hz); qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
spbr = bcm_qspi_calc_spbr(qspi->base_clk, xp);
spbr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX); spbr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spbr); bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spbr);

View File

@ -8,6 +8,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/mfd/dln2.h> #include <linux/mfd/dln2.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@ -688,6 +689,8 @@ static int dln2_spi_probe(struct platform_device *pdev)
if (!master) if (!master)
return -ENOMEM; return -ENOMEM;
device_set_node(&master->dev, dev_fwnode(dev));
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
dln2 = spi_master_get_devdata(master); dln2 = spi_master_get_devdata(master);
@ -699,7 +702,6 @@ static int dln2_spi_probe(struct platform_device *pdev)
} }
dln2->master = master; dln2->master = master;
dln2->master->dev.of_node = dev->of_node;
dln2->pdev = pdev; dln2->pdev = pdev;
dln2->port = pdata->port; dln2->port = pdata->port;
/* cs/mode can never be 0xff, so the first transfer will set them */ /* cs/mode can never be 0xff, so the first transfer will set them */

View File

@ -123,7 +123,7 @@ static ssize_t dw_spi_bt1_dirmap_read(struct spi_mem_dirmap_desc *desc,
len = min_t(size_t, len, dwsbt1->map_len - offs); len = min_t(size_t, len, dwsbt1->map_len - offs);
/* Collect the controller configuration required by the operation */ /* Collect the controller configuration required by the operation */
cfg.tmode = SPI_TMOD_EPROMREAD; cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;
cfg.dfs = 8; cfg.dfs = 8;
cfg.ndf = 4; cfg.ndf = 4;
cfg.freq = mem->spi->max_speed_hz; cfg.freq = mem->spi->max_speed_hz;
@ -131,13 +131,13 @@ static ssize_t dw_spi_bt1_dirmap_read(struct spi_mem_dirmap_desc *desc,
/* Make sure the corresponding CS is de-asserted on transmission */ /* Make sure the corresponding CS is de-asserted on transmission */
dw_spi_set_cs(mem->spi, false); dw_spi_set_cs(mem->spi, false);
spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
dw_spi_update_config(dws, mem->spi, &cfg); dw_spi_update_config(dws, mem->spi, &cfg);
spi_umask_intr(dws, SPI_INT_RXFI); dw_spi_umask_intr(dws, DW_SPI_INT_RXFI);
spi_enable_chip(dws, 1); dw_spi_enable_chip(dws, 1);
/* /*
* Enable the transparent mode of the System Boot Controller. * Enable the transparent mode of the System Boot Controller.
@ -339,3 +339,4 @@ module_platform_driver(dw_spi_bt1_driver);
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>"); MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver"); MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(SPI_DW_CORE);

View File

@ -5,6 +5,7 @@
* Copyright (c) 2009, Intel Corporation. * Copyright (c) 2009, Intel Corporation.
*/ */
#include <linux/bitfield.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
@ -24,7 +25,7 @@
#endif #endif
/* Slave spi_device related */ /* Slave spi_device related */
struct chip_data { struct dw_spi_chip_data {
u32 cr0; u32 cr0;
u32 rx_sample_dly; /* RX sample delay */ u32 rx_sample_dly; /* RX sample delay */
}; };
@ -106,10 +107,10 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
else else
dw_writel(dws, DW_SPI_SER, 0); dw_writel(dws, DW_SPI_SER, 0);
} }
EXPORT_SYMBOL_GPL(dw_spi_set_cs); EXPORT_SYMBOL_NS_GPL(dw_spi_set_cs, SPI_DW_CORE);
/* Return the max entries we can fill into tx fifo */ /* Return the max entries we can fill into tx fifo */
static inline u32 tx_max(struct dw_spi *dws) static inline u32 dw_spi_tx_max(struct dw_spi *dws)
{ {
u32 tx_room, rxtx_gap; u32 tx_room, rxtx_gap;
@ -129,14 +130,14 @@ static inline u32 tx_max(struct dw_spi *dws)
} }
/* Return the max entries we should read out of rx fifo */ /* Return the max entries we should read out of rx fifo */
static inline u32 rx_max(struct dw_spi *dws) static inline u32 dw_spi_rx_max(struct dw_spi *dws)
{ {
return min_t(u32, dws->rx_len, dw_readl(dws, DW_SPI_RXFLR)); return min_t(u32, dws->rx_len, dw_readl(dws, DW_SPI_RXFLR));
} }
static void dw_writer(struct dw_spi *dws) static void dw_writer(struct dw_spi *dws)
{ {
u32 max = tx_max(dws); u32 max = dw_spi_tx_max(dws);
u32 txw = 0; u32 txw = 0;
while (max--) { while (max--) {
@ -157,7 +158,7 @@ static void dw_writer(struct dw_spi *dws)
static void dw_reader(struct dw_spi *dws) static void dw_reader(struct dw_spi *dws)
{ {
u32 max = rx_max(dws); u32 max = dw_spi_rx_max(dws);
u32 rxw; u32 rxw;
while (max--) { while (max--) {
@ -186,31 +187,31 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw)
else else
irq_status = dw_readl(dws, DW_SPI_ISR); irq_status = dw_readl(dws, DW_SPI_ISR);
if (irq_status & SPI_INT_RXOI) { if (irq_status & DW_SPI_INT_RXOI) {
dev_err(&dws->master->dev, "RX FIFO overflow detected\n"); dev_err(&dws->master->dev, "RX FIFO overflow detected\n");
ret = -EIO; ret = -EIO;
} }
if (irq_status & SPI_INT_RXUI) { if (irq_status & DW_SPI_INT_RXUI) {
dev_err(&dws->master->dev, "RX FIFO underflow detected\n"); dev_err(&dws->master->dev, "RX FIFO underflow detected\n");
ret = -EIO; ret = -EIO;
} }
if (irq_status & SPI_INT_TXOI) { if (irq_status & DW_SPI_INT_TXOI) {
dev_err(&dws->master->dev, "TX FIFO overflow detected\n"); dev_err(&dws->master->dev, "TX FIFO overflow detected\n");
ret = -EIO; ret = -EIO;
} }
/* Generically handle the erroneous situation */ /* Generically handle the erroneous situation */
if (ret) { if (ret) {
spi_reset_chip(dws); dw_spi_reset_chip(dws);
if (dws->master->cur_msg) if (dws->master->cur_msg)
dws->master->cur_msg->status = ret; dws->master->cur_msg->status = ret;
} }
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(dw_spi_check_status); EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE);
static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
{ {
@ -230,7 +231,7 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
*/ */
dw_reader(dws); dw_reader(dws);
if (!dws->rx_len) { if (!dws->rx_len) {
spi_mask_intr(dws, 0xff); dw_spi_mask_intr(dws, 0xff);
spi_finalize_current_transfer(dws->master); spi_finalize_current_transfer(dws->master);
} else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) { } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1); dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
@ -241,10 +242,10 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
* disabled after the data transmission is finished so not to * disabled after the data transmission is finished so not to
* have the TXE IRQ flood at the final stage of the transfer. * have the TXE IRQ flood at the final stage of the transfer.
*/ */
if (irq_status & SPI_INT_TXEI) { if (irq_status & DW_SPI_INT_TXEI) {
dw_writer(dws); dw_writer(dws);
if (!dws->tx_len) if (!dws->tx_len)
spi_mask_intr(dws, SPI_INT_TXEI); dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@ -254,13 +255,13 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
{ {
struct spi_controller *master = dev_id; struct spi_controller *master = dev_id;
struct dw_spi *dws = spi_controller_get_devdata(master); struct dw_spi *dws = spi_controller_get_devdata(master);
u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f; u16 irq_status = dw_readl(dws, DW_SPI_ISR) & DW_SPI_INT_MASK;
if (!irq_status) if (!irq_status)
return IRQ_NONE; return IRQ_NONE;
if (!master->cur_msg) { if (!master->cur_msg) {
spi_mask_intr(dws, 0xff); dw_spi_mask_intr(dws, 0xff);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -271,37 +272,43 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
{ {
u32 cr0 = 0; u32 cr0 = 0;
if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) { if (dw_spi_ip_is(dws, PSSI)) {
/* CTRLR0[ 5: 4] Frame Format */ /* CTRLR0[ 5: 4] Frame Format */
cr0 |= SSI_MOTO_SPI << SPI_FRF_OFFSET; cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_FRF_MASK, DW_SPI_CTRLR0_FRF_MOTO_SPI);
/* /*
* SPI mode (SCPOL|SCPH) * SPI mode (SCPOL|SCPH)
* CTRLR0[ 6] Serial Clock Phase * CTRLR0[ 6] Serial Clock Phase
* CTRLR0[ 7] Serial Clock Polarity * CTRLR0[ 7] Serial Clock Polarity
*/ */
cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET; if (spi->mode & SPI_CPOL)
cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET; cr0 |= DW_PSSI_CTRLR0_SCPOL;
if (spi->mode & SPI_CPHA)
cr0 |= DW_PSSI_CTRLR0_SCPHA;
/* CTRLR0[11] Shift Register Loop */ /* CTRLR0[11] Shift Register Loop */
cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET; if (spi->mode & SPI_LOOP)
cr0 |= DW_PSSI_CTRLR0_SRL;
} else { } else {
/* CTRLR0[ 7: 6] Frame Format */ /* CTRLR0[ 7: 6] Frame Format */
cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET; cr0 |= FIELD_PREP(DW_HSSI_CTRLR0_FRF_MASK, DW_SPI_CTRLR0_FRF_MOTO_SPI);
/* /*
* SPI mode (SCPOL|SCPH) * SPI mode (SCPOL|SCPH)
* CTRLR0[ 8] Serial Clock Phase * CTRLR0[ 8] Serial Clock Phase
* CTRLR0[ 9] Serial Clock Polarity * CTRLR0[ 9] Serial Clock Polarity
*/ */
cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET; if (spi->mode & SPI_CPOL)
cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET; cr0 |= DW_HSSI_CTRLR0_SCPOL;
if (spi->mode & SPI_CPHA)
cr0 |= DW_HSSI_CTRLR0_SCPHA;
/* CTRLR0[13] Shift Register Loop */ /* CTRLR0[13] Shift Register Loop */
cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET; if (spi->mode & SPI_LOOP)
cr0 |= DW_HSSI_CTRLR0_SRL;
if (dws->caps & DW_SPI_CAP_KEEMBAY_MST) if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST; cr0 |= DW_HSSI_CTRLR0_KEEMBAY_MST;
} }
return cr0; return cr0;
@ -310,7 +317,7 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
struct dw_spi_cfg *cfg) struct dw_spi_cfg *cfg)
{ {
struct chip_data *chip = spi_get_ctldata(spi); struct dw_spi_chip_data *chip = spi_get_ctldata(spi);
u32 cr0 = chip->cr0; u32 cr0 = chip->cr0;
u32 speed_hz; u32 speed_hz;
u16 clk_div; u16 clk_div;
@ -318,16 +325,17 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
/* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */ /* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */
cr0 |= (cfg->dfs - 1) << dws->dfs_offset; cr0 |= (cfg->dfs - 1) << dws->dfs_offset;
if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) if (dw_spi_ip_is(dws, PSSI))
/* CTRLR0[ 9:8] Transfer Mode */ /* CTRLR0[ 9:8] Transfer Mode */
cr0 |= cfg->tmode << SPI_TMOD_OFFSET; cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_TMOD_MASK, cfg->tmode);
else else
/* CTRLR0[11:10] Transfer Mode */ /* CTRLR0[11:10] Transfer Mode */
cr0 |= cfg->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET; cr0 |= FIELD_PREP(DW_HSSI_CTRLR0_TMOD_MASK, cfg->tmode);
dw_writel(dws, DW_SPI_CTRLR0, cr0); dw_writel(dws, DW_SPI_CTRLR0, cr0);
if (cfg->tmode == SPI_TMOD_EPROMREAD || cfg->tmode == SPI_TMOD_RO) if (cfg->tmode == DW_SPI_CTRLR0_TMOD_EPROMREAD ||
cfg->tmode == DW_SPI_CTRLR0_TMOD_RO)
dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0); dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
/* Note DW APB SSI clock divider doesn't support odd numbers */ /* Note DW APB SSI clock divider doesn't support odd numbers */
@ -335,7 +343,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
speed_hz = dws->max_freq / clk_div; speed_hz = dws->max_freq / clk_div;
if (dws->current_freq != speed_hz) { if (dws->current_freq != speed_hz) {
spi_set_clk(dws, clk_div); dw_spi_set_clk(dws, clk_div);
dws->current_freq = speed_hz; dws->current_freq = speed_hz;
} }
@ -345,7 +353,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
dws->cur_rx_sample_dly = chip->rx_sample_dly; dws->cur_rx_sample_dly = chip->rx_sample_dly;
} }
} }
EXPORT_SYMBOL_GPL(dw_spi_update_config); EXPORT_SYMBOL_NS_GPL(dw_spi_update_config, SPI_DW_CORE);
static void dw_spi_irq_setup(struct dw_spi *dws) static void dw_spi_irq_setup(struct dw_spi *dws)
{ {
@ -363,9 +371,9 @@ static void dw_spi_irq_setup(struct dw_spi *dws)
dws->transfer_handler = dw_spi_transfer_handler; dws->transfer_handler = dw_spi_transfer_handler;
imask = SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI | imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI |
SPI_INT_RXFI; DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI;
spi_umask_intr(dws, imask); dw_spi_umask_intr(dws, imask);
} }
/* /*
@ -405,11 +413,12 @@ static int dw_spi_poll_transfer(struct dw_spi *dws,
} }
static int dw_spi_transfer_one(struct spi_controller *master, static int dw_spi_transfer_one(struct spi_controller *master,
struct spi_device *spi, struct spi_transfer *transfer) struct spi_device *spi,
struct spi_transfer *transfer)
{ {
struct dw_spi *dws = spi_controller_get_devdata(master); struct dw_spi *dws = spi_controller_get_devdata(master);
struct dw_spi_cfg cfg = { struct dw_spi_cfg cfg = {
.tmode = SPI_TMOD_TR, .tmode = DW_SPI_CTRLR0_TMOD_TR,
.dfs = transfer->bits_per_word, .dfs = transfer->bits_per_word,
.freq = transfer->speed_hz, .freq = transfer->speed_hz,
}; };
@ -425,7 +434,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
/* Ensure the data above is visible for all CPUs */ /* Ensure the data above is visible for all CPUs */
smp_mb(); smp_mb();
spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
dw_spi_update_config(dws, spi, &cfg); dw_spi_update_config(dws, spi, &cfg);
@ -436,7 +445,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
dws->dma_mapped = master->cur_msg_mapped; dws->dma_mapped = master->cur_msg_mapped;
/* For poll mode just disable all interrupts */ /* For poll mode just disable all interrupts */
spi_mask_intr(dws, 0xff); dw_spi_mask_intr(dws, 0xff);
if (dws->dma_mapped) { if (dws->dma_mapped) {
ret = dws->dma_ops->dma_setup(dws, transfer); ret = dws->dma_ops->dma_setup(dws, transfer);
@ -444,7 +453,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
return ret; return ret;
} }
spi_enable_chip(dws, 1); dw_spi_enable_chip(dws, 1);
if (dws->dma_mapped) if (dws->dma_mapped)
return dws->dma_ops->dma_transfer(dws, transfer); return dws->dma_ops->dma_transfer(dws, transfer);
@ -457,20 +466,20 @@ static int dw_spi_transfer_one(struct spi_controller *master,
} }
static void dw_spi_handle_err(struct spi_controller *master, static void dw_spi_handle_err(struct spi_controller *master,
struct spi_message *msg) struct spi_message *msg)
{ {
struct dw_spi *dws = spi_controller_get_devdata(master); struct dw_spi *dws = spi_controller_get_devdata(master);
if (dws->dma_mapped) if (dws->dma_mapped)
dws->dma_ops->dma_stop(dws); dws->dma_ops->dma_stop(dws);
spi_reset_chip(dws); dw_spi_reset_chip(dws);
} }
static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op) static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{ {
if (op->data.dir == SPI_MEM_DATA_IN) if (op->data.dir == SPI_MEM_DATA_IN)
op->data.nbytes = clamp_val(op->data.nbytes, 0, SPI_NDF_MASK + 1); op->data.nbytes = clamp_val(op->data.nbytes, 0, DW_SPI_NDF_MASK + 1);
return 0; return 0;
} }
@ -498,7 +507,7 @@ static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op)
if (op->data.dir == SPI_MEM_DATA_OUT) if (op->data.dir == SPI_MEM_DATA_OUT)
len += op->data.nbytes; len += op->data.nbytes;
if (len <= SPI_BUF_SIZE) { if (len <= DW_SPI_BUF_SIZE) {
out = dws->buf; out = dws->buf;
} else { } else {
out = kzalloc(len, GFP_KERNEL); out = kzalloc(len, GFP_KERNEL);
@ -512,9 +521,9 @@ static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op)
* single buffer in order to speed the data transmission up. * single buffer in order to speed the data transmission up.
*/ */
for (i = 0; i < op->cmd.nbytes; ++i) for (i = 0; i < op->cmd.nbytes; ++i)
out[i] = SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1); out[i] = DW_SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1);
for (j = 0; j < op->addr.nbytes; ++i, ++j) for (j = 0; j < op->addr.nbytes; ++i, ++j)
out[i] = SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1); out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1);
for (j = 0; j < op->dummy.nbytes; ++i, ++j) for (j = 0; j < op->dummy.nbytes; ++i, ++j)
out[i] = 0x0; out[i] = 0x0;
@ -587,7 +596,7 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
entries = readl_relaxed(dws->regs + DW_SPI_RXFLR); entries = readl_relaxed(dws->regs + DW_SPI_RXFLR);
if (!entries) { if (!entries) {
sts = readl_relaxed(dws->regs + DW_SPI_RISR); sts = readl_relaxed(dws->regs + DW_SPI_RISR);
if (sts & SPI_INT_RXOI) { if (sts & DW_SPI_INT_RXOI) {
dev_err(&dws->master->dev, "FIFO overflow on Rx\n"); dev_err(&dws->master->dev, "FIFO overflow on Rx\n");
return -EIO; return -EIO;
} }
@ -603,12 +612,12 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
static inline bool dw_spi_ctlr_busy(struct dw_spi *dws) static inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
{ {
return dw_readl(dws, DW_SPI_SR) & SR_BUSY; return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY;
} }
static int dw_spi_wait_mem_op_done(struct dw_spi *dws) static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
{ {
int retry = SPI_WAIT_RETRIES; int retry = DW_SPI_WAIT_RETRIES;
struct spi_delay delay; struct spi_delay delay;
unsigned long ns, us; unsigned long ns, us;
u32 nents; u32 nents;
@ -638,9 +647,9 @@ static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
static void dw_spi_stop_mem_op(struct dw_spi *dws, struct spi_device *spi) static void dw_spi_stop_mem_op(struct dw_spi *dws, struct spi_device *spi)
{ {
spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
dw_spi_set_cs(spi, true); dw_spi_set_cs(spi, true);
spi_enable_chip(dws, 1); dw_spi_enable_chip(dws, 1);
} }
/* /*
@ -673,19 +682,19 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
cfg.dfs = 8; cfg.dfs = 8;
cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq); cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq);
if (op->data.dir == SPI_MEM_DATA_IN) { if (op->data.dir == SPI_MEM_DATA_IN) {
cfg.tmode = SPI_TMOD_EPROMREAD; cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;
cfg.ndf = op->data.nbytes; cfg.ndf = op->data.nbytes;
} else { } else {
cfg.tmode = SPI_TMOD_TO; cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
} }
spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
dw_spi_update_config(dws, mem->spi, &cfg); dw_spi_update_config(dws, mem->spi, &cfg);
spi_mask_intr(dws, 0xff); dw_spi_mask_intr(dws, 0xff);
spi_enable_chip(dws, 1); dw_spi_enable_chip(dws, 1);
/* /*
* DW APB SSI controller has very nasty peculiarities. First originally * DW APB SSI controller has very nasty peculiarities. First originally
@ -768,7 +777,7 @@ static void dw_spi_init_mem_ops(struct dw_spi *dws)
static int dw_spi_setup(struct spi_device *spi) static int dw_spi_setup(struct spi_device *spi)
{ {
struct dw_spi *dws = spi_controller_get_devdata(spi->controller); struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct chip_data *chip; struct dw_spi_chip_data *chip;
/* Only alloc on first setup */ /* Only alloc on first setup */
chip = spi_get_ctldata(spi); chip = spi_get_ctldata(spi);
@ -776,7 +785,7 @@ static int dw_spi_setup(struct spi_device *spi)
struct dw_spi *dws = spi_controller_get_devdata(spi->controller); struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
u32 rx_sample_dly_ns; u32 rx_sample_dly_ns;
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) if (!chip)
return -ENOMEM; return -ENOMEM;
spi_set_ctldata(spi, chip); spi_set_ctldata(spi, chip);
@ -803,16 +812,30 @@ static int dw_spi_setup(struct spi_device *spi)
static void dw_spi_cleanup(struct spi_device *spi) static void dw_spi_cleanup(struct spi_device *spi)
{ {
struct chip_data *chip = spi_get_ctldata(spi); struct dw_spi_chip_data *chip = spi_get_ctldata(spi);
kfree(chip); kfree(chip);
spi_set_ctldata(spi, NULL); spi_set_ctldata(spi, NULL);
} }
/* Restart the controller, disable all interrupts, clean rx fifo */ /* Restart the controller, disable all interrupts, clean rx fifo */
static void spi_hw_init(struct device *dev, struct dw_spi *dws) static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
{ {
spi_reset_chip(dws); dw_spi_reset_chip(dws);
/*
* Retrieve the Synopsys component version if it hasn't been specified
* by the platform. CoreKit version ID is encoded as a 3-chars ASCII
* code enclosed with '*' (typical for the most of Synopsys IP-cores).
*/
if (!dws->ver) {
dws->ver = dw_readl(dws, DW_SPI_VERSION);
dev_dbg(dev, "Synopsys DWC%sSSI v%c.%c%c\n",
dw_spi_ip_is(dws, PSSI) ? " APB " : " ",
DW_SPI_GET_BYTE(dws->ver, 3), DW_SPI_GET_BYTE(dws->ver, 2),
DW_SPI_GET_BYTE(dws->ver, 1));
}
/* /*
* Try to detect the FIFO depth if not set by interface driver, * Try to detect the FIFO depth if not set by interface driver,
@ -837,18 +860,18 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
* writability. Note DWC SSI controller also has the extended DFS, but * writability. Note DWC SSI controller also has the extended DFS, but
* with zero offset. * with zero offset.
*/ */
if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) { if (dw_spi_ip_is(dws, PSSI)) {
u32 cr0, tmp = dw_readl(dws, DW_SPI_CTRLR0); u32 cr0, tmp = dw_readl(dws, DW_SPI_CTRLR0);
spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
dw_writel(dws, DW_SPI_CTRLR0, 0xffffffff); dw_writel(dws, DW_SPI_CTRLR0, 0xffffffff);
cr0 = dw_readl(dws, DW_SPI_CTRLR0); cr0 = dw_readl(dws, DW_SPI_CTRLR0);
dw_writel(dws, DW_SPI_CTRLR0, tmp); dw_writel(dws, DW_SPI_CTRLR0, tmp);
spi_enable_chip(dws, 1); dw_spi_enable_chip(dws, 1);
if (!(cr0 & SPI_DFS_MASK)) { if (!(cr0 & DW_PSSI_CTRLR0_DFS_MASK)) {
dws->caps |= DW_SPI_CAP_DFS32; dws->caps |= DW_SPI_CAP_DFS32;
dws->dfs_offset = SPI_DFS32_OFFSET; dws->dfs_offset = __bf_shf(DW_PSSI_CTRLR0_DFS32_MASK);
dev_dbg(dev, "Detected 32-bits max data frame size\n"); dev_dbg(dev, "Detected 32-bits max data frame size\n");
} }
} else { } else {
@ -872,13 +895,15 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
if (!master) if (!master)
return -ENOMEM; return -ENOMEM;
device_set_node(&master->dev, dev_fwnode(dev));
dws->master = master; dws->master = master;
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
spi_controller_set_devdata(master, dws); spi_controller_set_devdata(master, dws);
/* Basic HW init */ /* Basic HW init */
spi_hw_init(dev, dws); dw_spi_hw_init(dev, dws);
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
master); master);
@ -908,8 +933,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
if (dws->mem_ops.exec_op) if (dws->mem_ops.exec_op)
master->mem_ops = &dws->mem_ops; master->mem_ops = &dws->mem_ops;
master->max_speed_hz = dws->max_freq; master->max_speed_hz = dws->max_freq;
master->dev.of_node = dev->of_node;
master->dev.fwnode = dev->fwnode;
master->flags = SPI_MASTER_GPIO_SS; master->flags = SPI_MASTER_GPIO_SS;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
@ -939,13 +962,13 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
err_dma_exit: err_dma_exit:
if (dws->dma_ops && dws->dma_ops->dma_exit) if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws); dws->dma_ops->dma_exit(dws);
spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
free_irq(dws->irq, master); free_irq(dws->irq, master);
err_free_master: err_free_master:
spi_controller_put(master); spi_controller_put(master);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(dw_spi_add_host); EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, SPI_DW_CORE);
void dw_spi_remove_host(struct dw_spi *dws) void dw_spi_remove_host(struct dw_spi *dws)
{ {
@ -956,11 +979,11 @@ void dw_spi_remove_host(struct dw_spi *dws)
if (dws->dma_ops && dws->dma_ops->dma_exit) if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws); dws->dma_ops->dma_exit(dws);
spi_shutdown_chip(dws); dw_spi_shutdown_chip(dws);
free_irq(dws->irq, dws->master); free_irq(dws->irq, dws->master);
} }
EXPORT_SYMBOL_GPL(dw_spi_remove_host); EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, SPI_DW_CORE);
int dw_spi_suspend_host(struct dw_spi *dws) int dw_spi_suspend_host(struct dw_spi *dws)
{ {
@ -970,17 +993,17 @@ int dw_spi_suspend_host(struct dw_spi *dws)
if (ret) if (ret)
return ret; return ret;
spi_shutdown_chip(dws); dw_spi_shutdown_chip(dws);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(dw_spi_suspend_host); EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_host, SPI_DW_CORE);
int dw_spi_resume_host(struct dw_spi *dws) int dw_spi_resume_host(struct dw_spi *dws)
{ {
spi_hw_init(&dws->master->dev, dws); dw_spi_hw_init(&dws->master->dev, dws);
return spi_controller_resume(dws->master); return spi_controller_resume(dws->master);
} }
EXPORT_SYMBOL_GPL(dw_spi_resume_host); EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, SPI_DW_CORE);
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>"); MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
MODULE_DESCRIPTION("Driver for DesignWare SPI controller core"); MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");

View File

@ -10,6 +10,7 @@
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_data/dma-dw.h> #include <linux/platform_data/dma-dw.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
@ -17,10 +18,10 @@
#include "spi-dw.h" #include "spi-dw.h"
#define RX_BUSY 0 #define DW_SPI_RX_BUSY 0
#define RX_BURST_LEVEL 16 #define DW_SPI_RX_BURST_LEVEL 16
#define TX_BUSY 1 #define DW_SPI_TX_BUSY 1
#define TX_BURST_LEVEL 16 #define DW_SPI_TX_BURST_LEVEL 16
static bool dw_spi_dma_chan_filter(struct dma_chan *chan, void *param) static bool dw_spi_dma_chan_filter(struct dma_chan *chan, void *param)
{ {
@ -45,7 +46,7 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
if (!ret && caps.max_burst) if (!ret && caps.max_burst)
max_burst = caps.max_burst; max_burst = caps.max_burst;
else else
max_burst = RX_BURST_LEVEL; max_burst = DW_SPI_RX_BURST_LEVEL;
dws->rxburst = min(max_burst, def_burst); dws->rxburst = min(max_burst, def_burst);
dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1); dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
@ -54,7 +55,7 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
if (!ret && caps.max_burst) if (!ret && caps.max_burst)
max_burst = caps.max_burst; max_burst = caps.max_burst;
else else
max_burst = TX_BURST_LEVEL; max_burst = DW_SPI_TX_BURST_LEVEL;
/* /*
* Having a Rx DMA channel serviced with higher priority than a Tx DMA * Having a Rx DMA channel serviced with higher priority than a Tx DMA
@ -226,13 +227,13 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws) static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
{ {
return !(dw_readl(dws, DW_SPI_SR) & SR_TF_EMPT); return !(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_TF_EMPT);
} }
static int dw_spi_dma_wait_tx_done(struct dw_spi *dws, static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
int retry = SPI_WAIT_RETRIES; int retry = DW_SPI_WAIT_RETRIES;
struct spi_delay delay; struct spi_delay delay;
u32 nents; u32 nents;
@ -259,8 +260,8 @@ static void dw_spi_dma_tx_done(void *arg)
{ {
struct dw_spi *dws = arg; struct dw_spi *dws = arg;
clear_bit(TX_BUSY, &dws->dma_chan_busy); clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
if (test_bit(RX_BUSY, &dws->dma_chan_busy)) if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy))
return; return;
complete(&dws->dma_completion); complete(&dws->dma_completion);
@ -304,19 +305,19 @@ static int dw_spi_dma_submit_tx(struct dw_spi *dws, struct scatterlist *sgl,
return ret; return ret;
} }
set_bit(TX_BUSY, &dws->dma_chan_busy); set_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
return 0; return 0;
} }
static inline bool dw_spi_dma_rx_busy(struct dw_spi *dws) static inline bool dw_spi_dma_rx_busy(struct dw_spi *dws)
{ {
return !!(dw_readl(dws, DW_SPI_SR) & SR_RF_NOT_EMPT); return !!(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_RF_NOT_EMPT);
} }
static int dw_spi_dma_wait_rx_done(struct dw_spi *dws) static int dw_spi_dma_wait_rx_done(struct dw_spi *dws)
{ {
int retry = SPI_WAIT_RETRIES; int retry = DW_SPI_WAIT_RETRIES;
struct spi_delay delay; struct spi_delay delay;
unsigned long ns, us; unsigned long ns, us;
u32 nents; u32 nents;
@ -360,8 +361,8 @@ static void dw_spi_dma_rx_done(void *arg)
{ {
struct dw_spi *dws = arg; struct dw_spi *dws = arg;
clear_bit(RX_BUSY, &dws->dma_chan_busy); clear_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
if (test_bit(TX_BUSY, &dws->dma_chan_busy)) if (test_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy))
return; return;
complete(&dws->dma_completion); complete(&dws->dma_completion);
@ -405,7 +406,7 @@ static int dw_spi_dma_submit_rx(struct dw_spi *dws, struct scatterlist *sgl,
return ret; return ret;
} }
set_bit(RX_BUSY, &dws->dma_chan_busy); set_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
return 0; return 0;
} }
@ -430,16 +431,16 @@ static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
} }
/* Set the DMA handshaking interface */ /* Set the DMA handshaking interface */
dma_ctrl = SPI_DMA_TDMAE; dma_ctrl = DW_SPI_DMACR_TDMAE;
if (xfer->rx_buf) if (xfer->rx_buf)
dma_ctrl |= SPI_DMA_RDMAE; dma_ctrl |= DW_SPI_DMACR_RDMAE;
dw_writel(dws, DW_SPI_DMACR, dma_ctrl); dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
/* Set the interrupt mask */ /* Set the interrupt mask */
imr = SPI_INT_TXOI; imr = DW_SPI_INT_TXOI;
if (xfer->rx_buf) if (xfer->rx_buf)
imr |= SPI_INT_RXUI | SPI_INT_RXOI; imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI;
spi_umask_intr(dws, imr); dw_spi_umask_intr(dws, imr);
reinit_completion(&dws->dma_completion); reinit_completion(&dws->dma_completion);
@ -615,13 +616,13 @@ static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
static void dw_spi_dma_stop(struct dw_spi *dws) static void dw_spi_dma_stop(struct dw_spi *dws)
{ {
if (test_bit(TX_BUSY, &dws->dma_chan_busy)) { if (test_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy)) {
dmaengine_terminate_sync(dws->txchan); dmaengine_terminate_sync(dws->txchan);
clear_bit(TX_BUSY, &dws->dma_chan_busy); clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
} }
if (test_bit(RX_BUSY, &dws->dma_chan_busy)) { if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) {
dmaengine_terminate_sync(dws->rxchan); dmaengine_terminate_sync(dws->rxchan);
clear_bit(RX_BUSY, &dws->dma_chan_busy); clear_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
} }
} }
@ -638,7 +639,7 @@ void dw_spi_dma_setup_mfld(struct dw_spi *dws)
{ {
dws->dma_ops = &dw_spi_dma_mfld_ops; dws->dma_ops = &dw_spi_dma_mfld_ops;
} }
EXPORT_SYMBOL_GPL(dw_spi_dma_setup_mfld); EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_mfld, SPI_DW_CORE);
static const struct dw_spi_dma_ops dw_spi_dma_generic_ops = { static const struct dw_spi_dma_ops dw_spi_dma_generic_ops = {
.dma_init = dw_spi_dma_init_generic, .dma_init = dw_spi_dma_init_generic,
@ -653,4 +654,4 @@ void dw_spi_dma_setup_generic(struct dw_spi *dws)
{ {
dws->dma_ops = &dw_spi_dma_generic_ops; dws->dma_ops = &dw_spi_dma_generic_ops;
} }
EXPORT_SYMBOL_GPL(dw_spi_dma_setup_generic); EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_generic, SPI_DW_CORE);

View File

@ -196,18 +196,18 @@ static int dw_spi_alpine_init(struct platform_device *pdev,
return 0; return 0;
} }
static int dw_spi_dw_apb_init(struct platform_device *pdev, static int dw_spi_pssi_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio) struct dw_spi_mmio *dwsmmio)
{ {
dw_spi_dma_setup_generic(&dwsmmio->dws); dw_spi_dma_setup_generic(&dwsmmio->dws);
return 0; return 0;
} }
static int dw_spi_dwc_ssi_init(struct platform_device *pdev, static int dw_spi_hssi_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio) struct dw_spi_mmio *dwsmmio)
{ {
dwsmmio->dws.caps = DW_SPI_CAP_DWC_SSI; dwsmmio->dws.ip = DW_HSSI_ID;
dw_spi_dma_setup_generic(&dwsmmio->dws); dw_spi_dma_setup_generic(&dwsmmio->dws);
@ -217,7 +217,8 @@ static int dw_spi_dwc_ssi_init(struct platform_device *pdev,
static int dw_spi_keembay_init(struct platform_device *pdev, static int dw_spi_keembay_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio) struct dw_spi_mmio *dwsmmio)
{ {
dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST | DW_SPI_CAP_DWC_SSI; dwsmmio->dws.ip = DW_HSSI_ID;
dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST;
return 0; return 0;
} }
@ -342,12 +343,12 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
} }
static const struct of_device_id dw_spi_mmio_of_match[] = { static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "snps,dw-apb-ssi", .data = dw_spi_dw_apb_init}, { .compatible = "snps,dw-apb-ssi", .data = dw_spi_pssi_init},
{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init}, { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init}, { .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init}, { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init}, { .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init}, { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init}, { .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init}, { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
{ .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init}, { .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
@ -357,7 +358,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id dw_spi_mmio_acpi_match[] = { static const struct acpi_device_id dw_spi_mmio_acpi_match[] = {
{"HISI0173", (kernel_ulong_t)dw_spi_dw_apb_init}, {"HISI0173", (kernel_ulong_t)dw_spi_pssi_init},
{}, {},
}; };
MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match); MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
@ -377,3 +378,4 @@ module_platform_driver(dw_spi_mmio_driver);
MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>"); MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(SPI_DW_CORE);

View File

@ -24,14 +24,14 @@
#define CLK_SPI_CDIV_MASK 0x00000e00 #define CLK_SPI_CDIV_MASK 0x00000e00
#define CLK_SPI_DISABLE_OFFSET 8 #define CLK_SPI_DISABLE_OFFSET 8
struct spi_pci_desc { struct dw_spi_pci_desc {
int (*setup)(struct dw_spi *); int (*setup)(struct dw_spi *);
u16 num_cs; u16 num_cs;
u16 bus_num; u16 bus_num;
u32 max_freq; u32 max_freq;
}; };
static int spi_mid_init(struct dw_spi *dws) static int dw_spi_pci_mid_init(struct dw_spi *dws)
{ {
void __iomem *clk_reg; void __iomem *clk_reg;
u32 clk_cdiv; u32 clk_cdiv;
@ -53,36 +53,36 @@ static int spi_mid_init(struct dw_spi *dws)
return 0; return 0;
} }
static int spi_generic_init(struct dw_spi *dws) static int dw_spi_pci_generic_init(struct dw_spi *dws)
{ {
dw_spi_dma_setup_generic(dws); dw_spi_dma_setup_generic(dws);
return 0; return 0;
} }
static struct spi_pci_desc spi_pci_mid_desc_1 = { static struct dw_spi_pci_desc dw_spi_pci_mid_desc_1 = {
.setup = spi_mid_init, .setup = dw_spi_pci_mid_init,
.num_cs = 5, .num_cs = 5,
.bus_num = 0, .bus_num = 0,
}; };
static struct spi_pci_desc spi_pci_mid_desc_2 = { static struct dw_spi_pci_desc dw_spi_pci_mid_desc_2 = {
.setup = spi_mid_init, .setup = dw_spi_pci_mid_init,
.num_cs = 2, .num_cs = 2,
.bus_num = 1, .bus_num = 1,
}; };
static struct spi_pci_desc spi_pci_ehl_desc = { static struct dw_spi_pci_desc dw_spi_pci_ehl_desc = {
.setup = spi_generic_init, .setup = dw_spi_pci_generic_init,
.num_cs = 2, .num_cs = 2,
.bus_num = -1, .bus_num = -1,
.max_freq = 100000000, .max_freq = 100000000,
}; };
static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int dw_spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
struct dw_spi_pci_desc *desc = (struct dw_spi_pci_desc *)ent->driver_data;
struct dw_spi *dws; struct dw_spi *dws;
struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data;
int pci_bar = 0; int pci_bar = 0;
int ret; int ret;
@ -150,7 +150,7 @@ err_free_irq_vectors:
return ret; return ret;
} }
static void spi_pci_remove(struct pci_dev *pdev) static void dw_spi_pci_remove(struct pci_dev *pdev)
{ {
struct dw_spi *dws = pci_get_drvdata(pdev); struct dw_spi *dws = pci_get_drvdata(pdev);
@ -162,14 +162,14 @@ static void spi_pci_remove(struct pci_dev *pdev)
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int spi_suspend(struct device *dev) static int dw_spi_pci_suspend(struct device *dev)
{ {
struct dw_spi *dws = dev_get_drvdata(dev); struct dw_spi *dws = dev_get_drvdata(dev);
return dw_spi_suspend_host(dws); return dw_spi_suspend_host(dws);
} }
static int spi_resume(struct device *dev) static int dw_spi_pci_resume(struct device *dev)
{ {
struct dw_spi *dws = dev_get_drvdata(dev); struct dw_spi *dws = dev_get_drvdata(dev);
@ -177,39 +177,39 @@ static int spi_resume(struct device *dev)
} }
#endif #endif
static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); static SIMPLE_DEV_PM_OPS(dw_spi_pci_pm_ops, dw_spi_pci_suspend, dw_spi_pci_resume);
static const struct pci_device_id pci_ids[] = { static const struct pci_device_id dw_spi_pci_ids[] = {
/* Intel MID platform SPI controller 0 */ /* Intel MID platform SPI controller 0 */
/* /*
* The access to the device 8086:0801 is disabled by HW, since it's * The access to the device 8086:0801 is disabled by HW, since it's
* exclusively used by SCU to communicate with MSIC. * exclusively used by SCU to communicate with MSIC.
*/ */
/* Intel MID platform SPI controller 1 */ /* Intel MID platform SPI controller 1 */
{ PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1}, { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&dw_spi_pci_mid_desc_1},
/* Intel MID platform SPI controller 2 */ /* Intel MID platform SPI controller 2 */
{ PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2}, { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&dw_spi_pci_mid_desc_2},
/* Intel Elkhart Lake PSE SPI controllers */ /* Intel Elkhart Lake PSE SPI controllers */
{ PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&spi_pci_ehl_desc}, { PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&dw_spi_pci_ehl_desc},
{ PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&spi_pci_ehl_desc}, { PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&dw_spi_pci_ehl_desc},
{ PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&spi_pci_ehl_desc}, { PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&dw_spi_pci_ehl_desc},
{ PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&spi_pci_ehl_desc}, { PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&dw_spi_pci_ehl_desc},
{}, {},
}; };
MODULE_DEVICE_TABLE(pci, pci_ids); MODULE_DEVICE_TABLE(pci, dw_spi_pci_ids);
static struct pci_driver dw_spi_driver = { static struct pci_driver dw_spi_pci_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = pci_ids, .id_table = dw_spi_pci_ids,
.probe = spi_pci_probe, .probe = dw_spi_pci_probe,
.remove = spi_pci_remove, .remove = dw_spi_pci_remove,
.driver = { .driver = {
.pm = &dw_spi_pm_ops, .pm = &dw_spi_pci_pm_ops,
}, },
}; };
module_pci_driver(dw_spi_pci_driver);
module_pci_driver(dw_spi_driver);
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>"); MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
MODULE_DESCRIPTION("PCI interface driver for DW SPI Core"); MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(SPI_DW_CORE);

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
#ifndef DW_SPI_HEADER_H #ifndef __SPI_DW_H__
#define DW_SPI_HEADER_H #define __SPI_DW_H__
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/completion.h> #include <linux/completion.h>
@ -11,7 +11,30 @@
#include <linux/spi/spi-mem.h> #include <linux/spi/spi-mem.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
/* Register offsets */ /* Synopsys DW SSI IP-core virtual IDs */
#define DW_PSSI_ID 0
#define DW_HSSI_ID 1
/* Synopsys DW SSI component versions (FourCC sequence) */
#define DW_HSSI_102A 0x3130322a
/* DW SSI IP-core ID and version check helpers */
#define dw_spi_ip_is(_dws, _ip) \
((_dws)->ip == DW_ ## _ip ## _ID)
#define __dw_spi_ver_cmp(_dws, _ip, _ver, _op) \
(dw_spi_ip_is(_dws, _ip) && (_dws)->ver _op DW_ ## _ip ## _ver)
#define dw_spi_ver_is(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, ==)
#define dw_spi_ver_is_ge(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, >=)
/* DW SPI controller capabilities */
#define DW_SPI_CAP_CS_OVERRIDE BIT(0)
#define DW_SPI_CAP_KEEMBAY_MST BIT(1)
#define DW_SPI_CAP_DFS32 BIT(2)
/* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */
#define DW_SPI_CTRLR0 0x00 #define DW_SPI_CTRLR0 0x00
#define DW_SPI_CTRLR1 0x04 #define DW_SPI_CTRLR1 0x04
#define DW_SPI_SSIENR 0x08 #define DW_SPI_SSIENR 0x08
@ -40,92 +63,79 @@
#define DW_SPI_RX_SAMPLE_DLY 0xf0 #define DW_SPI_RX_SAMPLE_DLY 0xf0
#define DW_SPI_CS_OVERRIDE 0xf4 #define DW_SPI_CS_OVERRIDE 0xf4
/* Bit fields in CTRLR0 */ /* Bit fields in CTRLR0 (DWC APB SSI) */
#define SPI_DFS_OFFSET 0 #define DW_PSSI_CTRLR0_DFS_MASK GENMASK(3, 0)
#define SPI_DFS_MASK GENMASK(3, 0) #define DW_PSSI_CTRLR0_DFS32_MASK GENMASK(20, 16)
#define SPI_DFS32_OFFSET 16
#define SPI_FRF_OFFSET 4 #define DW_PSSI_CTRLR0_FRF_MASK GENMASK(5, 4)
#define SPI_FRF_SPI 0x0 #define DW_SPI_CTRLR0_FRF_MOTO_SPI 0x0
#define SPI_FRF_SSP 0x1 #define DW_SPI_CTRLR0_FRF_TI_SSP 0x1
#define SPI_FRF_MICROWIRE 0x2 #define DW_SPI_CTRLR0_FRF_NS_MICROWIRE 0x2
#define SPI_FRF_RESV 0x3 #define DW_SPI_CTRLR0_FRF_RESV 0x3
#define SPI_MODE_OFFSET 6 #define DW_PSSI_CTRLR0_MODE_MASK GENMASK(7, 6)
#define SPI_SCPH_OFFSET 6 #define DW_PSSI_CTRLR0_SCPHA BIT(6)
#define SPI_SCOL_OFFSET 7 #define DW_PSSI_CTRLR0_SCPOL BIT(7)
#define SPI_TMOD_OFFSET 8 #define DW_PSSI_CTRLR0_TMOD_MASK GENMASK(9, 8)
#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET) #define DW_SPI_CTRLR0_TMOD_TR 0x0 /* xmit & recv */
#define SPI_TMOD_TR 0x0 /* xmit & recv */ #define DW_SPI_CTRLR0_TMOD_TO 0x1 /* xmit only */
#define SPI_TMOD_TO 0x1 /* xmit only */ #define DW_SPI_CTRLR0_TMOD_RO 0x2 /* recv only */
#define SPI_TMOD_RO 0x2 /* recv only */ #define DW_SPI_CTRLR0_TMOD_EPROMREAD 0x3 /* eeprom read mode */
#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
#define SPI_SLVOE_OFFSET 10 #define DW_PSSI_CTRLR0_SLV_OE BIT(10)
#define SPI_SRL_OFFSET 11 #define DW_PSSI_CTRLR0_SRL BIT(11)
#define SPI_CFS_OFFSET 12 #define DW_PSSI_CTRLR0_CFS BIT(12)
/* Bit fields in CTRLR0 based on DWC_ssi_databook.pdf v1.01a */ /* Bit fields in CTRLR0 (DWC SSI with AHB interface) */
#define DWC_SSI_CTRLR0_SRL_OFFSET 13 #define DW_HSSI_CTRLR0_DFS_MASK GENMASK(4, 0)
#define DWC_SSI_CTRLR0_TMOD_OFFSET 10 #define DW_HSSI_CTRLR0_FRF_MASK GENMASK(7, 6)
#define DWC_SSI_CTRLR0_TMOD_MASK GENMASK(11, 10) #define DW_HSSI_CTRLR0_SCPHA BIT(8)
#define DWC_SSI_CTRLR0_SCPOL_OFFSET 9 #define DW_HSSI_CTRLR0_SCPOL BIT(9)
#define DWC_SSI_CTRLR0_SCPH_OFFSET 8 #define DW_HSSI_CTRLR0_TMOD_MASK GENMASK(11, 10)
#define DWC_SSI_CTRLR0_FRF_OFFSET 6 #define DW_HSSI_CTRLR0_SRL BIT(13)
#define DWC_SSI_CTRLR0_DFS_OFFSET 0
/* /*
* For Keem Bay, CTRLR0[31] is used to select controller mode. * For Keem Bay, CTRLR0[31] is used to select controller mode.
* 0: SSI is slave * 0: SSI is slave
* 1: SSI is master * 1: SSI is master
*/ */
#define DWC_SSI_CTRLR0_KEEMBAY_MST BIT(31) #define DW_HSSI_CTRLR0_KEEMBAY_MST BIT(31)
/* Bit fields in CTRLR1 */ /* Bit fields in CTRLR1 */
#define SPI_NDF_MASK GENMASK(15, 0) #define DW_SPI_NDF_MASK GENMASK(15, 0)
/* Bit fields in SR, 7 bits */ /* Bit fields in SR, 7 bits */
#define SR_MASK 0x7f /* cover 7 bits */ #define DW_SPI_SR_MASK GENMASK(6, 0)
#define SR_BUSY (1 << 0) #define DW_SPI_SR_BUSY BIT(0)
#define SR_TF_NOT_FULL (1 << 1) #define DW_SPI_SR_TF_NOT_FULL BIT(1)
#define SR_TF_EMPT (1 << 2) #define DW_SPI_SR_TF_EMPT BIT(2)
#define SR_RF_NOT_EMPT (1 << 3) #define DW_SPI_SR_RF_NOT_EMPT BIT(3)
#define SR_RF_FULL (1 << 4) #define DW_SPI_SR_RF_FULL BIT(4)
#define SR_TX_ERR (1 << 5) #define DW_SPI_SR_TX_ERR BIT(5)
#define SR_DCOL (1 << 6) #define DW_SPI_SR_DCOL BIT(6)
/* Bit fields in ISR, IMR, RISR, 7 bits */ /* Bit fields in ISR, IMR, RISR, 7 bits */
#define SPI_INT_TXEI (1 << 0) #define DW_SPI_INT_MASK GENMASK(5, 0)
#define SPI_INT_TXOI (1 << 1) #define DW_SPI_INT_TXEI BIT(0)
#define SPI_INT_RXUI (1 << 2) #define DW_SPI_INT_TXOI BIT(1)
#define SPI_INT_RXOI (1 << 3) #define DW_SPI_INT_RXUI BIT(2)
#define SPI_INT_RXFI (1 << 4) #define DW_SPI_INT_RXOI BIT(3)
#define SPI_INT_MSTI (1 << 5) #define DW_SPI_INT_RXFI BIT(4)
#define DW_SPI_INT_MSTI BIT(5)
/* Bit fields in DMACR */ /* Bit fields in DMACR */
#define SPI_DMA_RDMAE (1 << 0) #define DW_SPI_DMACR_RDMAE BIT(0)
#define SPI_DMA_TDMAE (1 << 1) #define DW_SPI_DMACR_TDMAE BIT(1)
#define SPI_WAIT_RETRIES 5 /* Mem/DMA operations helpers */
#define SPI_BUF_SIZE \ #define DW_SPI_WAIT_RETRIES 5
#define DW_SPI_BUF_SIZE \
(sizeof_field(struct spi_mem_op, cmd.opcode) + \ (sizeof_field(struct spi_mem_op, cmd.opcode) + \
sizeof_field(struct spi_mem_op, addr.val) + 256) sizeof_field(struct spi_mem_op, addr.val) + 256)
#define SPI_GET_BYTE(_val, _idx) \ #define DW_SPI_GET_BYTE(_val, _idx) \
((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff) ((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff)
enum dw_ssi_type {
SSI_MOTO_SPI = 0,
SSI_TI_SSP,
SSI_NS_MICROWIRE,
};
/* DW SPI capabilities */
#define DW_SPI_CAP_CS_OVERRIDE BIT(0)
#define DW_SPI_CAP_KEEMBAY_MST BIT(1)
#define DW_SPI_CAP_DWC_SSI BIT(2)
#define DW_SPI_CAP_DFS32 BIT(3)
/* Slave spi_transfer/spi_mem_op related */ /* Slave spi_transfer/spi_mem_op related */
struct dw_spi_cfg { struct dw_spi_cfg {
u8 tmode; u8 tmode;
@ -148,6 +158,10 @@ struct dw_spi_dma_ops {
struct dw_spi { struct dw_spi {
struct spi_controller *master; struct spi_controller *master;
u32 ip; /* Synopsys DW SSI IP-core ID */
u32 ver; /* Synopsys component version */
u32 caps; /* DW SPI capabilities */
void __iomem *regs; void __iomem *regs;
unsigned long paddr; unsigned long paddr;
int irq; int irq;
@ -156,8 +170,6 @@ struct dw_spi {
u32 max_mem_freq; /* max mem-ops bus freq */ u32 max_mem_freq; /* max mem-ops bus freq */
u32 max_freq; /* max bus freq supported */ u32 max_freq; /* max bus freq supported */
u32 caps; /* DW SPI capabilities */
u32 reg_io_width; /* DR I/O width in bytes */ u32 reg_io_width; /* DR I/O width in bytes */
u16 bus_num; u16 bus_num;
u16 num_cs; /* supported slave numbers */ u16 num_cs; /* supported slave numbers */
@ -168,7 +180,7 @@ struct dw_spi {
unsigned int tx_len; unsigned int tx_len;
void *rx; void *rx;
unsigned int rx_len; unsigned int rx_len;
u8 buf[SPI_BUF_SIZE]; u8 buf[DW_SPI_BUF_SIZE];
int dma_mapped; int dma_mapped;
u8 n_bytes; /* current is a 1/2 bytes op */ u8 n_bytes; /* current is a 1/2 bytes op */
irqreturn_t (*transfer_handler)(struct dw_spi *dws); irqreturn_t (*transfer_handler)(struct dw_spi *dws);
@ -230,18 +242,18 @@ static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val)
} }
} }
static inline void spi_enable_chip(struct dw_spi *dws, int enable) static inline void dw_spi_enable_chip(struct dw_spi *dws, int enable)
{ {
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0)); dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
} }
static inline void spi_set_clk(struct dw_spi *dws, u16 div) static inline void dw_spi_set_clk(struct dw_spi *dws, u16 div)
{ {
dw_writel(dws, DW_SPI_BAUDR, div); dw_writel(dws, DW_SPI_BAUDR, div);
} }
/* Disable IRQ bits */ /* Disable IRQ bits */
static inline void spi_mask_intr(struct dw_spi *dws, u32 mask) static inline void dw_spi_mask_intr(struct dw_spi *dws, u32 mask)
{ {
u32 new_mask; u32 new_mask;
@ -250,7 +262,7 @@ static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
} }
/* Enable IRQ bits */ /* Enable IRQ bits */
static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) static inline void dw_spi_umask_intr(struct dw_spi *dws, u32 mask)
{ {
u32 new_mask; u32 new_mask;
@ -263,19 +275,19 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
* and CS, then re-enables the controller back. Transmit and receive FIFO * and CS, then re-enables the controller back. Transmit and receive FIFO
* buffers are cleared when the device is disabled. * buffers are cleared when the device is disabled.
*/ */
static inline void spi_reset_chip(struct dw_spi *dws) static inline void dw_spi_reset_chip(struct dw_spi *dws)
{ {
spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
spi_mask_intr(dws, 0xff); dw_spi_mask_intr(dws, 0xff);
dw_readl(dws, DW_SPI_ICR); dw_readl(dws, DW_SPI_ICR);
dw_writel(dws, DW_SPI_SER, 0); dw_writel(dws, DW_SPI_SER, 0);
spi_enable_chip(dws, 1); dw_spi_enable_chip(dws, 1);
} }
static inline void spi_shutdown_chip(struct dw_spi *dws) static inline void dw_spi_shutdown_chip(struct dw_spi *dws)
{ {
spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
spi_set_clk(dws, 0); dw_spi_set_clk(dws, 0);
} }
extern void dw_spi_set_cs(struct spi_device *spi, bool enable); extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
@ -299,4 +311,4 @@ static inline void dw_spi_dma_setup_generic(struct dw_spi *dws) {}
#endif /* !CONFIG_SPI_DW_DMA */ #endif /* !CONFIG_SPI_DW_DMA */
#endif /* DW_SPI_HEADER_H */ #endif /* __SPI_DW_H__ */

View File

@ -913,7 +913,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
ret = devm_spi_register_controller(&pdev->dev, controller); ret = devm_spi_register_controller(&pdev->dev, controller);
if (ret < 0) { if (ret < 0) {
dev_err_probe(&pdev->dev, ret, "spi_register_controller error: %i\n", ret); dev_err_probe(&pdev->dev, ret, "spi_register_controller error: %i\n", ret);
goto out_pm_get; goto free_dma;
} }
pm_runtime_mark_last_busy(fsl_lpspi->dev); pm_runtime_mark_last_busy(fsl_lpspi->dev);
@ -921,6 +921,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
return 0; return 0;
free_dma:
fsl_lpspi_dma_exit(controller);
out_pm_get: out_pm_get:
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev); pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
pm_runtime_put_sync(fsl_lpspi->dev); pm_runtime_put_sync(fsl_lpspi->dev);
@ -937,6 +939,8 @@ static int fsl_lpspi_remove(struct platform_device *pdev)
struct fsl_lpspi_data *fsl_lpspi = struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller); spi_controller_get_devdata(controller);
fsl_lpspi_dma_exit(controller);
pm_runtime_disable(fsl_lpspi->dev); pm_runtime_disable(fsl_lpspi->dev);
return 0; return 0;
} }

View File

@ -71,10 +71,6 @@
#define GSI_CPHA BIT(4) #define GSI_CPHA BIT(4)
#define GSI_CPOL BIT(5) #define GSI_CPOL BIT(5)
#define MAX_TX_SG 3
#define NUM_SPI_XFER 8
#define SPI_XFER_TIMEOUT_MS 250
struct spi_geni_master { struct spi_geni_master {
struct geni_se se; struct geni_se se;
struct device *dev; struct device *dev;
@ -168,6 +164,30 @@ static void handle_fifo_timeout(struct spi_master *spi,
} }
} }
static void handle_gpi_timeout(struct spi_master *spi, struct spi_message *msg)
{
struct spi_geni_master *mas = spi_master_get_devdata(spi);
dmaengine_terminate_sync(mas->tx);
dmaengine_terminate_sync(mas->rx);
}
static void spi_geni_handle_err(struct spi_master *spi, struct spi_message *msg)
{
struct spi_geni_master *mas = spi_master_get_devdata(spi);
switch (mas->cur_xfer_mode) {
case GENI_SE_FIFO:
handle_fifo_timeout(spi, msg);
break;
case GENI_GPI_DMA:
handle_gpi_timeout(spi, msg);
break;
default:
dev_err(mas->dev, "Abort on Mode:%d not supported", mas->cur_xfer_mode);
}
}
static bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas) static bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas)
{ {
struct geni_se *se = &mas->se; struct geni_se *se = &mas->se;
@ -350,17 +370,21 @@ spi_gsi_callback_result(void *cb, const struct dmaengine_result *result)
{ {
struct spi_master *spi = cb; struct spi_master *spi = cb;
spi->cur_msg->status = -EIO;
if (result->result != DMA_TRANS_NOERROR) { if (result->result != DMA_TRANS_NOERROR) {
dev_err(&spi->dev, "DMA txn failed: %d\n", result->result); dev_err(&spi->dev, "DMA txn failed: %d\n", result->result);
spi_finalize_current_transfer(spi);
return; return;
} }
if (!result->residue) { if (!result->residue) {
spi->cur_msg->status = 0;
dev_dbg(&spi->dev, "DMA txn completed\n"); dev_dbg(&spi->dev, "DMA txn completed\n");
spi_finalize_current_transfer(spi);
} else { } else {
dev_err(&spi->dev, "DMA xfer has pending: %d\n", result->residue); dev_err(&spi->dev, "DMA xfer has pending: %d\n", result->residue);
} }
spi_finalize_current_transfer(spi);
} }
static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas, static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas,
@ -922,7 +946,7 @@ static int spi_geni_probe(struct platform_device *pdev)
spi->can_dma = geni_can_dma; spi->can_dma = geni_can_dma;
spi->dma_map_dev = dev->parent; spi->dma_map_dev = dev->parent;
spi->auto_runtime_pm = true; spi->auto_runtime_pm = true;
spi->handle_err = handle_fifo_timeout; spi->handle_err = spi_geni_handle_err;
spi->use_gpio_descriptors = true; spi->use_gpio_descriptors = true;
init_completion(&mas->cs_done); init_completion(&mas->cs_done);

View File

@ -127,7 +127,6 @@ struct hisi_spi {
void __iomem *regs; void __iomem *regs;
int irq; int irq;
u32 fifo_len; /* depth of the FIFO buffer */ u32 fifo_len; /* depth of the FIFO buffer */
u16 bus_num;
/* Current message transfer state info */ /* Current message transfer state info */
const void *tx; const void *tx;
@ -165,7 +164,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs)
{ {
char name[32]; char name[32];
snprintf(name, 32, "hisi_spi%d", hs->bus_num); struct spi_controller *master;
master = container_of(hs->dev, struct spi_controller, dev);
snprintf(name, 32, "hisi_spi%d", master->bus_num);
hs->debugfs = debugfs_create_dir(name, NULL); hs->debugfs = debugfs_create_dir(name, NULL);
if (!hs->debugfs) if (!hs->debugfs)
return -ENOMEM; return -ENOMEM;
@ -467,7 +469,6 @@ static int hisi_spi_probe(struct platform_device *pdev)
hs = spi_controller_get_devdata(master); hs = spi_controller_get_devdata(master);
hs->dev = dev; hs->dev = dev;
hs->irq = irq; hs->irq = irq;
hs->bus_num = pdev->id;
hs->regs = devm_platform_ioremap_resource(pdev, 0); hs->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hs->regs)) if (IS_ERR(hs->regs))
@ -490,7 +491,7 @@ static int hisi_spi_probe(struct platform_device *pdev)
master->use_gpio_descriptors = true; master->use_gpio_descriptors = true;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
master->bus_num = hs->bus_num; master->bus_num = pdev->id;
master->setup = hisi_spi_setup; master->setup = hisi_spi_setup;
master->cleanup = hisi_spi_cleanup; master->cleanup = hisi_spi_cleanup;
master->transfer_one = hisi_spi_transfer_one; master->transfer_one = hisi_spi_transfer_one;
@ -506,15 +507,15 @@ static int hisi_spi_probe(struct platform_device *pdev)
return ret; return ret;
} }
if (hisi_spi_debugfs_init(hs))
dev_info(dev, "failed to create debugfs dir\n");
ret = spi_register_controller(master); ret = spi_register_controller(master);
if (ret) { if (ret) {
dev_err(dev, "failed to register spi master, ret=%d\n", ret); dev_err(dev, "failed to register spi master, ret=%d\n", ret);
return ret; return ret;
} }
if (hisi_spi_debugfs_init(hs))
dev_info(dev, "failed to create debugfs dir\n");
dev_info(dev, "hw version:0x%x max-freq:%u kHz\n", dev_info(dev, "hw version:0x%x max-freq:%u kHz\n",
readl(hs->regs + HISI_SPI_VERSION), readl(hs->regs + HISI_SPI_VERSION),
master->max_speed_hz / 1000); master->max_speed_hz / 1000);

View File

@ -349,6 +349,7 @@ static int meson_spifc_probe(struct platform_device *pdev)
return 0; return 0;
out_clk: out_clk:
clk_disable_unprepare(spifc->clk); clk_disable_unprepare(spifc->clk);
pm_runtime_disable(spifc->dev);
out_err: out_err:
spi_master_put(master); spi_master_put(master);
return ret; return ret;

View File

@ -427,7 +427,6 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
static void cs_assert(struct spi_device *spi) static void cs_assert(struct spi_device *spi)
{ {
struct chip_data *chip = spi_get_ctldata(spi);
struct driver_data *drv_data = struct driver_data *drv_data =
spi_controller_get_devdata(spi->controller); spi_controller_get_devdata(spi->controller);
@ -436,18 +435,12 @@ static void cs_assert(struct spi_device *spi)
return; return;
} }
if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_ASSERT);
return;
}
if (is_lpss_ssp(drv_data)) if (is_lpss_ssp(drv_data))
lpss_ssp_cs_control(spi, true); lpss_ssp_cs_control(spi, true);
} }
static void cs_deassert(struct spi_device *spi) static void cs_deassert(struct spi_device *spi)
{ {
struct chip_data *chip = spi_get_ctldata(spi);
struct driver_data *drv_data = struct driver_data *drv_data =
spi_controller_get_devdata(spi->controller); spi_controller_get_devdata(spi->controller);
unsigned long timeout; unsigned long timeout;
@ -461,11 +454,6 @@ static void cs_deassert(struct spi_device *spi)
!time_after(jiffies, timeout)) !time_after(jiffies, timeout))
cpu_relax(); cpu_relax();
if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_DEASSERT);
return;
}
if (is_lpss_ssp(drv_data)) if (is_lpss_ssp(drv_data))
lpss_ssp_cs_control(spi, false); lpss_ssp_cs_control(spi, false);
} }
@ -994,13 +982,10 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
dev_err(&spi->dev, "Flush failed\n"); dev_err(&spi->dev, "Flush failed\n");
return -EIO; return -EIO;
} }
drv_data->n_bytes = chip->n_bytes;
drv_data->tx = (void *)transfer->tx_buf; drv_data->tx = (void *)transfer->tx_buf;
drv_data->tx_end = drv_data->tx + transfer->len; drv_data->tx_end = drv_data->tx + transfer->len;
drv_data->rx = transfer->rx_buf; drv_data->rx = transfer->rx_buf;
drv_data->rx_end = drv_data->rx + transfer->len; drv_data->rx_end = drv_data->rx + transfer->len;
drv_data->write = drv_data->tx ? chip->write : null_writer;
drv_data->read = drv_data->rx ? chip->read : null_reader;
/* Change speed and bit per word on a per transfer */ /* Change speed and bit per word on a per transfer */
bits = transfer->bits_per_word; bits = transfer->bits_per_word;
@ -1010,22 +995,16 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
if (bits <= 8) { if (bits <= 8) {
drv_data->n_bytes = 1; drv_data->n_bytes = 1;
drv_data->read = drv_data->read != null_reader ? drv_data->read = drv_data->rx ? u8_reader : null_reader;
u8_reader : null_reader; drv_data->write = drv_data->tx ? u8_writer : null_writer;
drv_data->write = drv_data->write != null_writer ?
u8_writer : null_writer;
} else if (bits <= 16) { } else if (bits <= 16) {
drv_data->n_bytes = 2; drv_data->n_bytes = 2;
drv_data->read = drv_data->read != null_reader ? drv_data->read = drv_data->rx ? u16_reader : null_reader;
u16_reader : null_reader; drv_data->write = drv_data->tx ? u16_writer : null_writer;
drv_data->write = drv_data->write != null_writer ?
u16_writer : null_writer;
} else if (bits <= 32) { } else if (bits <= 32) {
drv_data->n_bytes = 4; drv_data->n_bytes = 4;
drv_data->read = drv_data->read != null_reader ? drv_data->read = drv_data->rx ? u32_reader : null_reader;
u32_reader : null_reader; drv_data->write = drv_data->tx ? u32_writer : null_writer;
drv_data->write = drv_data->write != null_writer ?
u32_writer : null_writer;
} }
/* /*
* If bits per word is changed in DMA mode, then must check * If bits per word is changed in DMA mode, then must check
@ -1213,12 +1192,6 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
*/ */
cleanup_cs(spi); cleanup_cs(spi);
/* If ->cs_control() is provided, ignore GPIO chip select */
if (chip_info->cs_control) {
chip->cs_control = chip_info->cs_control;
return 0;
}
if (gpio_is_valid(chip_info->gpio_cs)) { if (gpio_is_valid(chip_info->gpio_cs)) {
int gpio = chip_info->gpio_cs; int gpio = chip_info->gpio_cs;
int err; int err;
@ -1316,7 +1289,6 @@ static int setup(struct spi_device *spi)
chip_info = spi->controller_data; chip_info = spi->controller_data;
/* chip_info isn't always needed */ /* chip_info isn't always needed */
chip->cr1 = 0;
if (chip_info) { if (chip_info) {
if (chip_info->timeout) if (chip_info->timeout)
chip->timeout = chip_info->timeout; chip->timeout = chip_info->timeout;
@ -1327,9 +1299,9 @@ static int setup(struct spi_device *spi)
if (chip_info->rx_threshold) if (chip_info->rx_threshold)
rx_thres = chip_info->rx_threshold; rx_thres = chip_info->rx_threshold;
chip->dma_threshold = 0; chip->dma_threshold = 0;
if (chip_info->enable_loopback)
chip->cr1 = SSCR1_LBM;
} }
chip->cr1 = 0;
if (spi_controller_is_slave(drv_data->controller)) { if (spi_controller_is_slave(drv_data->controller)) {
chip->cr1 |= SSCR1_SCFR; chip->cr1 |= SSCR1_SCFR;
chip->cr1 |= SSCR1_SCLKDIR; chip->cr1 |= SSCR1_SCLKDIR;
@ -1391,20 +1363,6 @@ static int setup(struct spi_device *spi)
if (spi->mode & SPI_LOOP) if (spi->mode & SPI_LOOP)
chip->cr1 |= SSCR1_LBM; chip->cr1 |= SSCR1_LBM;
if (spi->bits_per_word <= 8) {
chip->n_bytes = 1;
chip->read = u8_reader;
chip->write = u8_writer;
} else if (spi->bits_per_word <= 16) {
chip->n_bytes = 2;
chip->read = u16_reader;
chip->write = u16_writer;
} else if (spi->bits_per_word <= 32) {
chip->n_bytes = 4;
chip->read = u32_reader;
chip->write = u32_writer;
}
spi_set_ctldata(spi, chip); spi_set_ctldata(spi, chip);
if (drv_data->ssp_type == CE4100_SSP) if (drv_data->ssp_type == CE4100_SSP)
@ -1706,8 +1664,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->controller_info = platform_info; drv_data->controller_info = platform_info;
drv_data->ssp = ssp; drv_data->ssp = ssp;
controller->dev.of_node = dev->of_node; device_set_node(&controller->dev, dev_fwnode(dev));
controller->dev.fwnode = dev->fwnode;
/* The spi->mode bits understood by this driver: */ /* The spi->mode bits understood by this driver: */
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;

View File

@ -49,7 +49,6 @@ struct driver_data {
int (*write)(struct driver_data *drv_data); int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data); int (*read)(struct driver_data *drv_data);
irqreturn_t (*transfer_handler)(struct driver_data *drv_data); irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
void (*cs_control)(u32 command);
void __iomem *lpss_base; void __iomem *lpss_base;
@ -61,18 +60,12 @@ struct chip_data {
u32 cr1; u32 cr1;
u32 dds_rate; u32 dds_rate;
u32 timeout; u32 timeout;
u8 n_bytes;
u8 enable_dma; u8 enable_dma;
u32 dma_burst_size; u32 dma_burst_size;
u32 dma_threshold; u32 dma_threshold;
u32 threshold; u32 threshold;
u16 lpss_rx_threshold; u16 lpss_rx_threshold;
u16 lpss_tx_threshold; u16 lpss_tx_threshold;
int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data);
void (*cs_control)(u32 command);
}; };
static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg) static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg)

View File

@ -21,6 +21,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/sh_dma.h> #include <linux/sh_dma.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/rspi.h> #include <linux/spi/rspi.h>
@ -834,7 +835,7 @@ static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
int ret; int ret;
if (rspi->ctlr->can_dma && __rspi_can_dma(rspi, xfer)) { if (rspi->ctlr->can_dma && __rspi_can_dma(rspi, xfer)) {
int ret = rspi_dma_transfer(rspi, NULL, &xfer->rx_sg); ret = rspi_dma_transfer(rspi, NULL, &xfer->rx_sg);
if (ret != -EAGAIN) if (ret != -EAGAIN)
return ret; return ret;
} }
@ -1225,8 +1226,14 @@ static const struct of_device_id rspi_of_match[] = {
MODULE_DEVICE_TABLE(of, rspi_of_match); MODULE_DEVICE_TABLE(of, rspi_of_match);
static void rspi_reset_control_assert(void *data)
{
reset_control_assert(data);
}
static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr) static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr)
{ {
struct reset_control *rstc;
u32 num_cs; u32 num_cs;
int error; int error;
@ -1238,6 +1245,24 @@ static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr)
} }
ctlr->num_chipselect = num_cs; ctlr->num_chipselect = num_cs;
rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(rstc))
return dev_err_probe(dev, PTR_ERR(rstc),
"failed to get reset ctrl\n");
error = reset_control_deassert(rstc);
if (error) {
dev_err(dev, "failed to deassert reset %d\n", error);
return error;
}
error = devm_add_action_or_reset(dev, rspi_reset_control_assert, rstc);
if (error) {
dev_err(dev, "failed to register assert devm action, %d\n", error);
return error;
}
return 0; return 0;
} }
#else #else

View File

@ -877,7 +877,7 @@ static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_devic
struct tegra_qspi_client_data *cdata; struct tegra_qspi_client_data *cdata;
struct device_node *slave_np = spi->dev.of_node; struct device_node *slave_np = spi->dev.of_node;
cdata = kzalloc(sizeof(*cdata), GFP_KERNEL); cdata = devm_kzalloc(&spi->dev, sizeof(*cdata), GFP_KERNEL);
if (!cdata) if (!cdata)
return NULL; return NULL;
@ -888,14 +888,6 @@ static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_devic
return cdata; return cdata;
} }
static void tegra_qspi_cleanup(struct spi_device *spi)
{
struct tegra_qspi_client_data *cdata = spi->controller_data;
spi->controller_data = NULL;
kfree(cdata);
}
static int tegra_qspi_setup(struct spi_device *spi) static int tegra_qspi_setup(struct spi_device *spi)
{ {
struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master); struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
@ -1229,7 +1221,6 @@ static int tegra_qspi_probe(struct platform_device *pdev)
SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD; SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8); master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
master->setup = tegra_qspi_setup; master->setup = tegra_qspi_setup;
master->cleanup = tegra_qspi_cleanup;
master->transfer_one_message = tegra_qspi_transfer_one_message; master->transfer_one_message = tegra_qspi_transfer_one_message;
master->num_chipselect = 1; master->num_chipselect = 1;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;

View File

@ -767,12 +767,13 @@ out_master_put:
static int uniphier_spi_remove(struct platform_device *pdev) static int uniphier_spi_remove(struct platform_device *pdev)
{ {
struct uniphier_spi_priv *priv = platform_get_drvdata(pdev); struct spi_master *master = platform_get_drvdata(pdev);
struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
if (priv->master->dma_tx) if (master->dma_tx)
dma_release_channel(priv->master->dma_tx); dma_release_channel(master->dma_tx);
if (priv->master->dma_rx) if (master->dma_rx)
dma_release_channel(priv->master->dma_rx); dma_release_channel(master->dma_rx);
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);

View File

@ -9,7 +9,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
/* SPI Configuration Register */ /* SPI Configuration Register */
@ -436,17 +435,10 @@ static const struct acpi_device_id xlp_spi_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match); MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match);
#endif #endif
static const struct of_device_id xlp_spi_dt_id[] = {
{ .compatible = "netlogic,xlp832-spi" },
{ },
};
MODULE_DEVICE_TABLE(of, xlp_spi_dt_id);
static struct platform_driver xlp_spi_driver = { static struct platform_driver xlp_spi_driver = {
.probe = xlp_spi_probe, .probe = xlp_spi_probe,
.driver = { .driver = {
.name = "xlp-spi", .name = "xlp-spi",
.of_match_table = xlp_spi_dt_id,
.acpi_match_table = ACPI_PTR(xlp_spi_acpi_match), .acpi_match_table = ACPI_PTR(xlp_spi_acpi_match),
}, },
}; };

View File

@ -33,6 +33,7 @@
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/platform_data/x86/apple.h> #include <linux/platform_data/x86/apple.h>
#include <linux/ptp_clock_kernel.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/spi.h> #include <trace/events/spi.h>
@ -311,15 +312,14 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
spin_unlock_irqrestore(&stats->lock, flags); spin_unlock_irqrestore(&stats->lock, flags);
} }
/* modalias support makes "modprobe $MODALIAS" new-style hotplug work, /*
* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
* and the sysfs version makes coldplug work too. * and the sysfs version makes coldplug work too.
*/ */
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, const char *name)
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,
const struct spi_device *sdev)
{ {
while (id->name[0]) { while (id->name[0]) {
if (!strcmp(sdev->modalias, id->name)) if (!strcmp(name, id->name))
return id; return id;
id++; id++;
} }
@ -330,7 +330,7 @@ const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev)
{ {
const struct spi_driver *sdrv = to_spi_driver(sdev->dev.driver); const struct spi_driver *sdrv = to_spi_driver(sdev->dev.driver);
return spi_match_id(sdrv->id_table, sdev); return spi_match_id(sdrv->id_table, sdev->modalias);
} }
EXPORT_SYMBOL_GPL(spi_get_device_id); EXPORT_SYMBOL_GPL(spi_get_device_id);
@ -352,7 +352,7 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
return 1; return 1;
if (sdrv->id_table) if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi); return !!spi_match_id(sdrv->id_table, spi->modalias);
return strcmp(spi->modalias, drv->name) == 0; return strcmp(spi->modalias, drv->name) == 0;
} }
@ -474,12 +474,8 @@ int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
if (sdrv->id_table) { if (sdrv->id_table) {
const struct spi_device_id *spi_id; const struct spi_device_id *spi_id;
for (spi_id = sdrv->id_table; spi_id->name[0]; spi_id = spi_match_id(sdrv->id_table, of_name);
spi_id++) if (spi_id)
if (strcmp(spi_id->name, of_name) == 0)
break;
if (spi_id->name[0])
continue; continue;
} else { } else {
if (strcmp(sdrv->driver.name, of_name) == 0) if (strcmp(sdrv->driver.name, of_name) == 0)
@ -497,7 +493,8 @@ EXPORT_SYMBOL_GPL(__spi_register_driver);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* SPI devices should normally not be created by SPI device drivers; that /*
* SPI devices should normally not be created by SPI device drivers; that
* would make them board-specific. Similarly with SPI controller drivers. * would make them board-specific. Similarly with SPI controller drivers.
* Device registration normally goes into like arch/.../mach.../board-YYY.c * Device registration normally goes into like arch/.../mach.../board-YYY.c
* with other readonly (flashable) information about mainboard devices. * with other readonly (flashable) information about mainboard devices.
@ -513,8 +510,8 @@ static LIST_HEAD(spi_controller_list);
/* /*
* Used to protect add/del operation for board_info list and * Used to protect add/del operation for board_info list and
* spi_controller list, and their matching process * spi_controller list, and their matching process also used
* also used to protect object of type struct idr * to protect object of type struct idr.
*/ */
static DEFINE_MUTEX(board_lock); static DEFINE_MUTEX(board_lock);
@ -621,7 +618,8 @@ static int __spi_add_device(struct spi_device *spi)
else if (ctlr->cs_gpios) else if (ctlr->cs_gpios)
spi->cs_gpio = ctlr->cs_gpios[spi->chip_select]; spi->cs_gpio = ctlr->cs_gpios[spi->chip_select];
/* Drivers may modify this initial i/o setup, but will /*
* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices * normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise... * using SPI_CS_HIGH can't coexist well otherwise...
*/ */
@ -715,7 +713,8 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
struct spi_device *proxy; struct spi_device *proxy;
int status; int status;
/* NOTE: caller did any chip->bus_num checks necessary. /*
* NOTE: caller did any chip->bus_num checks necessary.
* *
* Also, unless we change the return value convention to use * Also, unless we change the return value convention to use
* error-or-pointer (not NULL-or-pointer), troubleshootability * error-or-pointer (not NULL-or-pointer), troubleshootability
@ -883,7 +882,6 @@ static void *spi_res_alloc(struct spi_device *spi, spi_res_release_t release,
/** /**
* spi_res_free - free an spi resource * spi_res_free - free an spi resource
* @res: pointer to the custom data of a resource * @res: pointer to the custom data of a resource
*
*/ */
static void spi_res_free(void *res) static void spi_res_free(void *res)
{ {
@ -947,12 +945,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
spi->controller->last_cs_enable = enable; spi->controller->last_cs_enable = enable;
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH; spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) || if ((spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) ||
!spi->controller->set_cs_timing) { !spi->controller->set_cs_timing) && !activate) {
if (activate) spi_delay_exec(&spi->cs_hold, NULL);
spi_delay_exec(&spi->cs_setup, NULL);
else
spi_delay_exec(&spi->cs_hold, NULL);
} }
if (spi->mode & SPI_CS_HIGH) if (spi->mode & SPI_CS_HIGH)
@ -978,7 +973,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
gpiod_set_value_cansleep(spi->cs_gpiod, activate); gpiod_set_value_cansleep(spi->cs_gpiod, activate);
} else { } else {
/* /*
* invert the enable line, as active low is * Invert the enable line, as active low is
* default for SPI. * default for SPI.
*/ */
gpio_set_value_cansleep(spi->cs_gpio, !enable); gpio_set_value_cansleep(spi->cs_gpio, !enable);
@ -994,7 +989,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) || if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) ||
!spi->controller->set_cs_timing) { !spi->controller->set_cs_timing) {
if (!activate) if (activate)
spi_delay_exec(&spi->cs_setup, NULL);
else
spi_delay_exec(&spi->cs_inactive, NULL); spi_delay_exec(&spi->cs_inactive, NULL);
} }
} }
@ -1227,11 +1224,10 @@ static int spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
if (max_tx) { if (max_tx) {
tmp = krealloc(ctlr->dummy_tx, max_tx, tmp = krealloc(ctlr->dummy_tx, max_tx,
GFP_KERNEL | GFP_DMA); GFP_KERNEL | GFP_DMA | __GFP_ZERO);
if (!tmp) if (!tmp)
return -ENOMEM; return -ENOMEM;
ctlr->dummy_tx = tmp; ctlr->dummy_tx = tmp;
memset(tmp, 0, max_tx);
} }
if (max_rx) { if (max_rx) {
@ -1717,16 +1713,7 @@ static void spi_pump_messages(struct kthread_work *work)
} }
/** /**
* spi_take_timestamp_pre - helper for drivers to collect the beginning of the * spi_take_timestamp_pre - helper to collect the beginning of the TX timestamp
* TX timestamp for the requested byte from the SPI
* transfer. The frequency with which this function
* must be called (once per word, once for the whole
* transfer, once per batch of words etc) is arbitrary
* as long as the @tx buffer offset is greater than or
* equal to the requested byte at the time of the
* call. The timestamp is only taken once, at the
* first such call. It is assumed that the driver
* advances its @tx buffer pointer monotonically.
* @ctlr: Pointer to the spi_controller structure of the driver * @ctlr: Pointer to the spi_controller structure of the driver
* @xfer: Pointer to the transfer being timestamped * @xfer: Pointer to the transfer being timestamped
* @progress: How many words (not bytes) have been transferred so far * @progress: How many words (not bytes) have been transferred so far
@ -1736,6 +1723,14 @@ static void spi_pump_messages(struct kthread_work *work)
* spi_take_timestamp_post or otherwise system will crash. * spi_take_timestamp_post or otherwise system will crash.
* WARNING: for fully predictable results, the CPU frequency must * WARNING: for fully predictable results, the CPU frequency must
* also be under control (governor). * also be under control (governor).
*
* This is a helper for drivers to collect the beginning of the TX timestamp
* for the requested byte from the SPI transfer. The frequency with which this
* function must be called (once per word, once for the whole transfer, once
* per batch of words etc) is arbitrary as long as the @tx buffer offset is
* greater than or equal to the requested byte at the time of the call. The
* timestamp is only taken once, at the first such call. It is assumed that
* the driver advances its @tx buffer pointer monotonically.
*/ */
void spi_take_timestamp_pre(struct spi_controller *ctlr, void spi_take_timestamp_pre(struct spi_controller *ctlr,
struct spi_transfer *xfer, struct spi_transfer *xfer,
@ -1763,16 +1758,16 @@ void spi_take_timestamp_pre(struct spi_controller *ctlr,
EXPORT_SYMBOL_GPL(spi_take_timestamp_pre); EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
/** /**
* spi_take_timestamp_post - helper for drivers to collect the end of the * spi_take_timestamp_post - helper to collect the end of the TX timestamp
* TX timestamp for the requested byte from the SPI
* transfer. Can be called with an arbitrary
* frequency: only the first call where @tx exceeds
* or is equal to the requested word will be
* timestamped.
* @ctlr: Pointer to the spi_controller structure of the driver * @ctlr: Pointer to the spi_controller structure of the driver
* @xfer: Pointer to the transfer being timestamped * @xfer: Pointer to the transfer being timestamped
* @progress: How many words (not bytes) have been transferred so far * @progress: How many words (not bytes) have been transferred so far
* @irqs_off: If true, will re-enable IRQs and preemption for the local CPU. * @irqs_off: If true, will re-enable IRQs and preemption for the local CPU.
*
* This is a helper for drivers to collect the end of the TX timestamp for
* the requested byte from the SPI transfer. Can be called with an arbitrary
* frequency: only the first call where @tx exceeds or is equal to the
* requested word will be timestamped.
*/ */
void spi_take_timestamp_post(struct spi_controller *ctlr, void spi_take_timestamp_post(struct spi_controller *ctlr,
struct spi_transfer *xfer, struct spi_transfer *xfer,
@ -1905,10 +1900,12 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
spi_unmap_msg(ctlr, mesg); spi_unmap_msg(ctlr, mesg);
/* In the prepare_messages callback the spi bus has the opportunity to /*
* split a transfer to smaller chunks. * In the prepare_messages callback the SPI bus has the opportunity
* Release splited transfers here since spi_map_msg is done on the * to split a transfer to smaller chunks.
* splited transfers. *
* Release the split transfers here since spi_map_msg() is done on
* the split transfers.
*/ */
spi_res_release(ctlr, mesg); spi_res_release(ctlr, mesg);
@ -2950,8 +2947,9 @@ int spi_register_controller(struct spi_controller *ctlr)
if (!ctlr->max_dma_len) if (!ctlr->max_dma_len)
ctlr->max_dma_len = INT_MAX; ctlr->max_dma_len = INT_MAX;
/* register the device, then userspace will see it. /*
* registration fails if the bus ID is in use. * Register the device, then userspace will see it.
* Registration fails if the bus ID is in use.
*/ */
dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num); dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
@ -3217,16 +3215,18 @@ static struct spi_replaced_transfers *spi_replace_transfers(
/* init the replaced_transfers list */ /* init the replaced_transfers list */
INIT_LIST_HEAD(&rxfer->replaced_transfers); INIT_LIST_HEAD(&rxfer->replaced_transfers);
/* assign the list_entry after which we should reinsert /*
* Assign the list_entry after which we should reinsert
* the @replaced_transfers - it may be spi_message.messages! * the @replaced_transfers - it may be spi_message.messages!
*/ */
rxfer->replaced_after = xfer_first->transfer_list.prev; rxfer->replaced_after = xfer_first->transfer_list.prev;
/* remove the requested number of transfers */ /* remove the requested number of transfers */
for (i = 0; i < remove; i++) { for (i = 0; i < remove; i++) {
/* if the entry after replaced_after it is msg->transfers /*
* If the entry after replaced_after it is msg->transfers
* then we have been requested to remove more transfers * then we have been requested to remove more transfers
* than are in the list * than are in the list.
*/ */
if (rxfer->replaced_after->next == &msg->transfers) { if (rxfer->replaced_after->next == &msg->transfers) {
dev_err(&msg->spi->dev, dev_err(&msg->spi->dev,
@ -3242,15 +3242,17 @@ static struct spi_replaced_transfers *spi_replace_transfers(
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
/* remove the entry after replaced_after from list of /*
* transfers and add it to list of replaced_transfers * Remove the entry after replaced_after from list of
* transfers and add it to list of replaced_transfers.
*/ */
list_move_tail(rxfer->replaced_after->next, list_move_tail(rxfer->replaced_after->next,
&rxfer->replaced_transfers); &rxfer->replaced_transfers);
} }
/* create copy of the given xfer with identical settings /*
* based on the first transfer to get removed * Create copy of the given xfer with identical settings
* based on the first transfer to get removed.
*/ */
for (i = 0; i < insert; i++) { for (i = 0; i < insert; i++) {
/* we need to run in reverse order */ /* we need to run in reverse order */
@ -3298,18 +3300,20 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
return PTR_ERR(srt); return PTR_ERR(srt);
xfers = srt->inserted_transfers; xfers = srt->inserted_transfers;
/* now handle each of those newly inserted spi_transfers /*
* note that the replacements spi_transfers all are preset * Now handle each of those newly inserted spi_transfers.
* Note that the replacements spi_transfers all are preset
* to the same values as *xferp, so tx_buf, rx_buf and len * to the same values as *xferp, so tx_buf, rx_buf and len
* are all identical (as well as most others) * are all identical (as well as most others)
* so we just have to fix up len and the pointers. * so we just have to fix up len and the pointers.
* *
* this also includes support for the depreciated * This also includes support for the depreciated
* spi_message.is_dma_mapped interface * spi_message.is_dma_mapped interface.
*/ */
/* the first transfer just needs the length modified, so we /*
* run it outside the loop * The first transfer just needs the length modified, so we
* run it outside the loop.
*/ */
xfers[0].len = min_t(size_t, maxsize, xfer[0].len); xfers[0].len = min_t(size_t, maxsize, xfer[0].len);
@ -3329,8 +3333,9 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
xfers[i].len = min(maxsize, xfers[i].len - offset); xfers[i].len = min(maxsize, xfers[i].len - offset);
} }
/* we set up xferp to the last entry we have inserted, /*
* so that we skip those already split transfers * We set up xferp to the last entry we have inserted,
* so that we skip those already split transfers.
*/ */
*xferp = &xfers[count - 1]; *xferp = &xfers[count - 1];
@ -3362,11 +3367,12 @@ int spi_split_transfers_maxsize(struct spi_controller *ctlr,
struct spi_transfer *xfer; struct spi_transfer *xfer;
int ret; int ret;
/* iterate over the transfer_list, /*
* Iterate over the transfer_list,
* but note that xfer is advanced to the last transfer inserted * but note that xfer is advanced to the last transfer inserted
* to avoid checking sizes again unnecessarily (also xfer does * to avoid checking sizes again unnecessarily (also xfer does
* potentiall belong to a different list by the time the * potentially belong to a different list by the time the
* replacement has happened * replacement has happened).
*/ */
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (xfer->len > maxsize) { if (xfer->len > maxsize) {
@ -3427,8 +3433,8 @@ int spi_setup(struct spi_device *spi)
int status; int status;
/* /*
* check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO * Check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO
* are set at the same time * are set at the same time.
*/ */
if ((hweight_long(spi->mode & if ((hweight_long(spi->mode &
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_NO_TX)) > 1) || (SPI_TX_DUAL | SPI_TX_QUAD | SPI_NO_TX)) > 1) ||
@ -3438,20 +3444,21 @@ int spi_setup(struct spi_device *spi)
"setup: can not select any two of dual, quad and no-rx/tx at the same time\n"); "setup: can not select any two of dual, quad and no-rx/tx at the same time\n");
return -EINVAL; return -EINVAL;
} }
/* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden /* If it is SPI_3WIRE mode, DUAL and QUAD should be forbidden */
*/
if ((spi->mode & SPI_3WIRE) && (spi->mode & if ((spi->mode & SPI_3WIRE) && (spi->mode &
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL))) SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
return -EINVAL; return -EINVAL;
/* help drivers fail *cleanly* when they need options /*
* that aren't supported with their current controller * Help drivers fail *cleanly* when they need options
* that aren't supported with their current controller.
* SPI_CS_WORD has a fallback software implementation, * SPI_CS_WORD has a fallback software implementation,
* so it is ignored here. * so it is ignored here.
*/ */
bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD | bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD |
SPI_NO_TX | SPI_NO_RX); SPI_NO_TX | SPI_NO_RX);
/* nothing prevents from working with active-high CS in case if it /*
* Nothing prevents from working with active-high CS in case if it
* is driven by GPIO. * is driven by GPIO.
*/ */
if (gpio_is_valid(spi->cs_gpio)) if (gpio_is_valid(spi->cs_gpio))
@ -3573,7 +3580,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
if (list_empty(&message->transfers)) if (list_empty(&message->transfers))
return -EINVAL; return -EINVAL;
/* If an SPI controller does not support toggling the CS line on each /*
* If an SPI controller does not support toggling the CS line on each
* transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
* for the CS line, we can emulate the CS-per-word hardware function by * for the CS line, we can emulate the CS-per-word hardware function by
* splitting transfers into one-word transfers and ensuring that * splitting transfers into one-word transfers and ensuring that
@ -3603,7 +3611,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
} }
} }
/* Half-duplex links include original MicroWire, and ones with /*
* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where * only one data pin like SPI_3WIRE (switches direction) or where
* either MOSI or MISO is missing. They can also be caused by * either MOSI or MISO is missing. They can also be caused by
* software limitations. * software limitations.
@ -3622,7 +3631,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
} }
} }
/** /*
* Set transfer bits_per_word and max speed as spi device default if * Set transfer bits_per_word and max speed as spi device default if
* it is not set for this transfer. * it is not set for this transfer.
* Set transfer tx_nbits and rx_nbits as single transfer default * Set transfer tx_nbits and rx_nbits as single transfer default
@ -3648,7 +3657,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
/* /*
* SPI transfer length should be multiple of SPI word size * SPI transfer length should be multiple of SPI word size
* where SPI word size should be power-of-two multiple * where SPI word size should be power-of-two multiple.
*/ */
if (xfer->bits_per_word <= 8) if (xfer->bits_per_word <= 8)
w_size = 1; w_size = 1;
@ -3669,7 +3678,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
xfer->tx_nbits = SPI_NBITS_SINGLE; xfer->tx_nbits = SPI_NBITS_SINGLE;
if (xfer->rx_buf && !xfer->rx_nbits) if (xfer->rx_buf && !xfer->rx_nbits)
xfer->rx_nbits = SPI_NBITS_SINGLE; xfer->rx_nbits = SPI_NBITS_SINGLE;
/* check transfer tx/rx_nbits: /*
* Check transfer tx/rx_nbits:
* 1. check the value matches one of single, dual and quad * 1. check the value matches one of single, dual and quad
* 2. check tx/rx_nbits match the mode in spi_device * 2. check tx/rx_nbits match the mode in spi_device
*/ */
@ -3848,7 +3858,8 @@ static int spi_async_locked(struct spi_device *spi, struct spi_message *message)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* Utility methods for SPI protocol drivers, layered on /*
* Utility methods for SPI protocol drivers, layered on
* top of the core. Some other utility methods are defined as * top of the core. Some other utility methods are defined as
* inline functions. * inline functions.
*/ */
@ -3876,7 +3887,8 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync); SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync); SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
/* If we're not using the legacy transfer method then we will /*
* If we're not using the legacy transfer method then we will
* try to transfer in the calling context so special case. * try to transfer in the calling context so special case.
* This code would be less tricky if we could remove the * This code would be less tricky if we could remove the
* support for driver implemented message queues. * support for driver implemented message queues.
@ -3894,9 +3906,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
} }
if (status == 0) { if (status == 0) {
/* Push out the messages in the calling context if we /* Push out the messages in the calling context if we can */
* can.
*/
if (ctlr->transfer == spi_queued_transfer) { if (ctlr->transfer == spi_queued_transfer) {
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
spi_sync_immediate); spi_sync_immediate);
@ -4057,7 +4067,8 @@ int spi_write_then_read(struct spi_device *spi,
struct spi_transfer x[2]; struct spi_transfer x[2];
u8 *local_buf; u8 *local_buf;
/* Use preallocated DMA-safe buffer if we can. We can't avoid /*
* Use preallocated DMA-safe buffer if we can. We can't avoid
* copying here, (as a pure convenience thing), but we can * copying here, (as a pure convenience thing), but we can
* keep heap costs out of the hot path unless someone else is * keep heap costs out of the hot path unless someone else is
* using the pre-allocated buffer or the transfer is too large. * using the pre-allocated buffer or the transfer is too large.
@ -4293,11 +4304,12 @@ err0:
return status; return status;
} }
/* board_info is normally registered in arch_initcall(), /*
* but even essential drivers wait till later * A board_info is normally registered in arch_initcall(),
* but even essential drivers wait till later.
* *
* REVISIT only boardinfo really needs static linking. the rest (device and * REVISIT only boardinfo really needs static linking. The rest (device and
* driver registration) _could_ be dynamically linked (modular) ... costs * driver registration) _could_ be dynamically linked (modular) ... Costs
* include needing to have boardinfo data structures be much more public. * include needing to have boardinfo data structures be much more public.
*/ */
postcore_initcall(spi_init); postcore_initcall(spi_init);

View File

@ -415,7 +415,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
tmp |= SPI_CS_HIGH; tmp |= SPI_CS_HIGH;
tmp |= spi->mode & ~SPI_MODE_MASK; tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = (u16)tmp; spi->mode = tmp & SPI_MODE_USER_MASK;
retval = spi_setup(spi); retval = spi_setup(spi);
if (retval < 0) if (retval < 0)
spi->mode = save; spi->mode = save;
@ -751,9 +751,10 @@ static int spidev_probe(struct spi_device *spi)
* compatible string, it is a Linux implementation thing * compatible string, it is a Linux implementation thing
* rather than a description of the hardware. * rather than a description of the hardware.
*/ */
WARN(spi->dev.of_node && if (spi->dev.of_node && of_device_is_compatible(spi->dev.of_node, "spidev")) {
of_device_is_compatible(spi->dev.of_node, "spidev"), dev_err(&spi->dev, "spidev listed directly in DT is not supported\n");
"%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node); return -EINVAL;
}
spidev_probe_acpi(spi); spidev_probe_acpi(spi);

View File

@ -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

View File

@ -9,9 +9,6 @@
#include <linux/pxa2xx_ssp.h> #include <linux/pxa2xx_ssp.h>
#define PXA2XX_CS_ASSERT (0x01)
#define PXA2XX_CS_DEASSERT (0x02)
struct dma_chan; struct dma_chan;
/* /*
@ -45,9 +42,7 @@ struct pxa2xx_spi_chip {
u8 rx_threshold; u8 rx_threshold;
u8 dma_burst_size; u8 dma_burst_size;
u32 timeout; u32 timeout;
u8 enable_loopback;
int gpio_cs; int gpio_cs;
void (*cs_control)(u32 command);
}; };
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)

View File

@ -14,12 +14,12 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/ptp_clock_kernel.h>
#include <uapi/linux/spi/spi.h> #include <uapi/linux/spi/spi.h>
struct dma_chan; struct dma_chan;
struct software_node; struct software_node;
struct ptp_system_timestamp;
struct spi_controller; struct spi_controller;
struct spi_transfer; struct spi_transfer;
struct spi_controller_mem_ops; struct spi_controller_mem_ops;