Commit e23dd95c authored by Linus Torvalds's avatar Linus Torvalds

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

Pull spi updates from Mark Brown:
 "There's some quite exciting core work in this release, we've got the
  beginnings of support for hardware initiated transfers which is itself
  independently useful for optimising fast paths in existing drivers.

  We also have a rework of the DMA mapping which allows finer grained
  decisions about DMA mapping messages and also helps remove some bodges
  that we'd had.

  Otherwise it's a fairly quiet release, a few new drivers and features
  for existing drivers, together with various cleanups and DT binding
  conversions.

  One regmap SPI fix made it's way in here too which I should probably
  have sent as a regmap fix instead.

  Summary:

   - Support for pre-optimising messages, reducing the overhead for
     messages that are repeatedly used (eg, reading the interrupt status
     from a device). This will also be used for hardware initiated
     transfers in future.

   - A reworking of how DMA mapping is done, introducing a new helper
     and allowing the DMA mapping decision to be done per transfer
     instead of per message.

   - Support for Atmel SAMA7D64, Freescale LX2160A DSPI and WCH CH341A"

* tag 'spi-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (72 commits)
  spi: dt-bindings: at91: Add sama7d65 compatible string
  spi: add ch341a usb2spi driver
  spi: dt-bindings: fsl-dspi: add compatible string 'fsl,lx2160a-dspi'
  spi: dt-bindings: fsl-dspi: add dmas and dma-names properties
  spi: spi: Remove unnecessary ‘0’ values from status
  spi: spi: Remove unnecessary ‘0’ values from rc
  spi: xcomm: fix coding style
  spi: xcomm: remove i2c_set_clientdata()
  spi: xcomm: make use of devm_spi_alloc_host()
  spi: xcomm: add gpiochip support
  spi: dt-bindings: snps,dw-apb-ssi.yaml: update compatible property
  spi: dt-bindings: fsl-dspi: Convert to yaml format
  spi: fsl-dspi: use common proptery 'spi-cs-setup(hold)-delay-ns'
  spi: axi-spi-engine: remove platform_set_drvdata()
  spi: spi-fsl-lpspi: Pass pm_ptr()
  spi: spi-imx: Pass pm_ptr()
  spi: spi-fsl-lpspi: Switch to SYSTEM_SLEEP_PM_OPS()
  spi: spi-imx: Switch to RUNTIME_PM_OPS/SYSTEM_SLEEP_PM_OPS()
  spi: add EXPORT_SYMBOL_GPL(devm_spi_optimize_message)
  spi: add devm_spi_optimize_message() helper
  ...
parents 584aeccc 3048dc8b
Device tree bindings for Marvell PXA SSP ports
Required properties:
- compatible: Must be one of
mrvl,pxa25x-ssp
mvrl,pxa25x-nssp
mrvl,pxa27x-ssp
mrvl,pxa3xx-ssp
mvrl,pxa168-ssp
mrvl,pxa910-ssp
mrvl,ce4100-ssp
- reg: The memory base
- dmas: Two dma phandles, one for rx, one for tx
- dma-names: Must be "rx", "tx"
Example for PXA3xx:
ssp0: ssp@41000000 {
compatible = "mrvl,pxa3xx-ssp";
reg = <0x41000000 0x40>;
ssp-id = <1>;
interrupts = <24>;
clock-names = "pxa27x-ssp.0";
dmas = <&dma 13
&dma 14>;
dma-names = "rx", "tx";
};
ssp1: ssp@41700000 {
compatible = "mrvl,pxa3xx-ssp";
reg = <0x41700000 0x40>;
ssp-id = <2>;
interrupts = <16>;
clock-names = "pxa27x-ssp.1";
dmas = <&dma 15
&dma 16>;
dma-names = "rx", "tx";
};
ssp2: ssp@41900000 {
compatibl3 = "mrvl,pxa3xx-ssp";
reg = <0x41900000 0x40>;
ssp-id = <3>;
interrupts = <0>;
clock-names = "pxa27x-ssp.2";
dmas = <&dma 66
&dma 67>;
dma-names = "rx", "tx";
};
ssp3: ssp@41a00000 {
compatible = "mrvl,pxa3xx-ssp";
reg = <0x41a00000 0x40>;
ssp-id = <4>;
interrupts = <13>;
clock-names = "pxa27x-ssp.3";
dmas = <&dma 2
&dma 3>;
dma-names = "rx", "tx";
};
...@@ -23,6 +23,9 @@ properties: ...@@ -23,6 +23,9 @@ properties:
clocks: clocks:
maxItems: 1 maxItems: 1
power-domains:
maxItems: 1
required: required:
- compatible - compatible
- reg - reg
......
...@@ -18,10 +18,10 @@ properties: ...@@ -18,10 +18,10 @@ properties:
oneOf: oneOf:
- const: atmel,at91rm9200-spi - const: atmel,at91rm9200-spi
- items: - items:
- const: microchip,sam9x60-spi - enum:
- const: atmel,at91rm9200-spi - microchip,sam9x60-spi
- items: - microchip,sam9x7-spi
- const: microchip,sam9x7-spi - microchip,sama7d65-spi
- const: atmel,at91rm9200-spi - const: atmel,at91rm9200-spi
reg: reg:
......
Broadcom BCM2835 SPI0 controller
The BCM2835 contains two forms of SPI master controller, one known simply as
SPI0, and the other known as the "Universal SPI Master"; part of the
auxiliary block. This binding applies to the SPI0 controller.
Required properties:
- compatible: Should be one of "brcm,bcm2835-spi" for BCM2835/2836/2837 or
"brcm,bcm2711-spi" for BCM2711 or "brcm,bcm7211-spi" for BCM7211.
- reg: Should contain register location and length.
- interrupts: Should contain interrupt.
- clocks: The clock feeding the SPI controller.
Example:
spi@20204000 {
compatible = "brcm,bcm2835-spi";
reg = <0x7e204000 0x1000>;
interrupts = <2 22>;
clocks = <&clk_spi>;
#address-cells = <1>;
#size-cells = <0>;
};
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/brcm,bcm2835-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom BCM2835 SPI0 controller
maintainers:
- Florian Fainelli <florian.fainelli@broadcom.com>
- Kanak Shilledar <kanakshilledar111@protonmail.com>
- Stefan Wahren <wahrenst@gmx.net>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
enum:
- brcm,bcm2835-spi
- brcm,bcm2711-spi
- brcm,bcm7211-spi
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
spi@20204000 {
compatible = "brcm,bcm2835-spi";
reg = <0x7e204000 0x1000>;
interrupts = <2 22>;
clocks = <&clk_spi>;
#address-cells = <1>;
#size-cells = <0>;
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/fsl,dspi-peripheral-props.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Peripheral-specific properties for Freescale DSPI controller
maintainers:
- Vladimir Oltean <olteanv@gmail.com>
description:
See spi-peripheral-props.yaml for more info.
properties:
fsl,spi-cs-sck-delay:
deprecated: true
description:
Delay in nanoseconds between activating chip select and the start of
clock signal, at the start of a transfer.
$ref: /schemas/types.yaml#/definitions/uint32
fsl,spi-sck-cs-delay:
deprecated: true
description:
Delay in nanoseconds between stopping the clock signal and
deactivating chip select, at the end of a transfer.
$ref: /schemas/types.yaml#/definitions/uint32
additionalProperties: true
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/fsl,dspi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ARM Freescale DSPI controller
maintainers:
- Frank Li <Frank.Li@nxp.com>
properties:
compatible:
oneOf:
- enum:
- fsl,vf610-dspi
- fsl,ls1021a-v1.0-dspi
- fsl,ls1012a-dspi
- fsl,ls1028a-dspi
- fsl,ls1043a-dspi
- fsl,ls1046a-dspi
- fsl,ls1088a-dspi
- fsl,ls2080a-dspi
- fsl,ls2085a-dspi
- fsl,lx2160a-dspi
- items:
- enum:
- fsl,ls1012a-dspi
- fsl,ls1028a-dspi
- fsl,ls1043a-dspi
- fsl,ls1046a-dspi
- fsl,ls1088a-dspi
- const: fsl,ls1021a-v1.0-dspi
- items:
- const: fsl,ls2080a-dspi
- const: fsl,ls2085a-dspi
- items:
- const: fsl,lx2160a-dspi
- const: fsl,ls2085a-dspi
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: dspi
dmas:
items:
- description: DMA controller phandle and request line for TX
- description: DMA controller phandle and request line for RX
dma-names:
items:
- const: tx
- const: rx
spi-num-chipselects:
$ref: /schemas/types.yaml#/definitions/uint32
description:
The number of the chip native chipselect signals.
cs-gpios don't count against this number.
big-endian: true
bus-num:
$ref: /schemas/types.yaml#/definitions/uint32
description: SoC-specific identifier for the SPI controller.
required:
- compatible
- reg
- clocks
- clock-names
- spi-num-chipselects
allOf:
- $ref: spi-controller.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/vf610-clock.h>
spi@4002c000 {
compatible = "fsl,vf610-dspi";
reg = <0x4002c000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks VF610_CLK_DSPI0>;
clock-names = "dspi";
spi-num-chipselects = <5>;
bus-num = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dspi0_1>;
big-endian;
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <16000000>;
spi-cpol;
spi-cpha;
spi-cs-setup-delay-ns = <100>;
spi-cs-hold-delay-ns = <50>;
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/ibm,spi-fsi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: IBM FSI-attached SPI Controller
maintainers:
- Eddie James <eajames@linux.ibm.com>
description:
A SPI controller found on IBM Power processors, accessed over FSI from a
service processor. This node will always be a child node of an ibm,fsi2spi
node.
properties:
compatible:
enum:
- ibm,spi-fsi
reg:
maxItems: 1
required:
- compatible
- reg
allOf:
- $ref: spi-controller.yaml#
unevaluatedProperties: false
examples:
- |
fsi {
#address-cells = <1>;
#size-cells = <0>;
spi@0 {
compatible = "ibm,spi-fsi";
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
eeprom@0 {
compatible = "atmel,at25";
reg = <0>;
size = <0x80000>;
address-width = <24>;
pagesize = <256>;
spi-max-frequency = <1000000>;
};
};
};
...@@ -10,12 +10,17 @@ title: PXA2xx SSP SPI Controller ...@@ -10,12 +10,17 @@ title: PXA2xx SSP SPI Controller
maintainers: maintainers:
- Lubomir Rintel <lkundrak@v3.sk> - Lubomir Rintel <lkundrak@v3.sk>
allOf:
- $ref: spi-controller.yaml#
properties: properties:
compatible: compatible:
const: marvell,mmp2-ssp enum:
- marvell,mmp2-ssp
- mrvl,ce4100-ssp
- mvrl,pxa168-ssp
- mrvl,pxa25x-ssp
- mvrl,pxa25x-nssp
- mrvl,pxa27x-ssp
- mrvl,pxa3xx-ssp
- mrvl,pxa910-ssp
interrupts: interrupts:
maxItems: 1 maxItems: 1
...@@ -26,6 +31,16 @@ properties: ...@@ -26,6 +31,16 @@ properties:
clocks: clocks:
maxItems: 1 maxItems: 1
dmas:
items:
- description: Receive DMA
- description: Transmit DMA
dma-names:
items:
- const: rx
- const: tx
ready-gpios: ready-gpios:
description: | description: |
GPIO used to signal a SPI master that the FIFO is filled and we're GPIO used to signal a SPI master that the FIFO is filled and we're
...@@ -41,6 +56,18 @@ required: ...@@ -41,6 +56,18 @@ required:
dependencies: dependencies:
ready-gpios: [ spi-slave ] ready-gpios: [ spi-slave ]
allOf:
- $ref: spi-controller.yaml#
- if:
properties:
compatible:
contains:
const: marvell,mmp2-ssp
then:
properties:
dmas: false
dma-names: false
unevaluatedProperties: false unevaluatedProperties: false
examples: examples:
......
...@@ -13,9 +13,6 @@ description: ...@@ -13,9 +13,6 @@ description:
maintainers: maintainers:
- Conor Dooley <conor.dooley@microchip.com> - Conor Dooley <conor.dooley@microchip.com>
allOf:
- $ref: spi-controller.yaml#
properties: properties:
compatible: compatible:
oneOf: oneOf:
...@@ -43,6 +40,32 @@ required: ...@@ -43,6 +40,32 @@ required:
- interrupts - interrupts
- clocks - clocks
allOf:
- $ref: spi-controller.yaml#
- if:
properties:
compatible:
contains:
const: microchip,mpfs-spi
then:
properties:
num-cs:
default: 1
- if:
properties:
compatible:
contains:
const: microchip,mpfs-spi
not:
required:
- cs-gpios
then:
properties:
num-cs:
maximum: 1
unevaluatedProperties: false unevaluatedProperties: false
examples: examples:
......
...@@ -88,6 +88,10 @@ properties: ...@@ -88,6 +88,10 @@ properties:
- renesas,r9a06g032-spi # RZ/N1D - renesas,r9a06g032-spi # RZ/N1D
- renesas,r9a06g033-spi # RZ/N1S - renesas,r9a06g033-spi # RZ/N1S
- const: renesas,rzn1-spi # RZ/N1 - const: renesas,rzn1-spi # RZ/N1
- description: T-HEAD TH1520 SoC SPI Controller
items:
- const: thead,th1520-spi
- const: snps,dw-apb-ssi
reg: reg:
minItems: 1 minItems: 1
......
...@@ -55,6 +55,13 @@ properties: ...@@ -55,6 +55,13 @@ properties:
label: label:
description: Descriptive name of the SPI controller. description: Descriptive name of the SPI controller.
resets:
maxItems: 1
reset-names:
items:
- const: spi
required: required:
- compatible - compatible
- reg - reg
......
ARM Freescale DSPI controller
Required properties:
- compatible : must be one of:
"fsl,vf610-dspi",
"fsl,ls1021a-v1.0-dspi",
"fsl,ls1012a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"),
"fsl,ls1028a-dspi",
"fsl,ls1043a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"),
"fsl,ls1046a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"),
"fsl,ls1088a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"),
"fsl,ls2080a-dspi" (optionally followed by "fsl,ls2085a-dspi"),
"fsl,ls2085a-dspi",
"fsl,lx2160a-dspi",
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt
- clocks: from common clock binding: handle to dspi clock.
- clock-names: from common clock binding: Shall be "dspi".
- pinctrl-0: pin control group to be used for this controller.
- pinctrl-names: must contain a "default" entry.
- spi-num-chipselects : the number of the chipselect signals.
Optional property:
- big-endian: If present the dspi device's registers are implemented
in big endian mode.
- bus-num : the slave chip chipselect signal number.
Optional SPI slave node properties:
- fsl,spi-cs-sck-delay: a delay in nanoseconds between activating chip
select and the start of clock signal, at the start of a transfer.
- fsl,spi-sck-cs-delay: a delay in nanoseconds between stopping the clock
signal and deactivating chip select, at the end of a transfer.
Example:
dspi0@4002c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,vf610-dspi";
reg = <0x4002c000 0x1000>;
interrupts = <0 67 0x04>;
clocks = <&clks VF610_CLK_DSPI0>;
clock-names = "dspi";
spi-num-chipselects = <5>;
bus-num = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dspi0_1>;
big-endian;
sflash: at26df081a@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atmel,at26df081a";
spi-max-frequency = <16000000>;
spi-cpol;
spi-cpha;
reg = <0>;
linux,modalias = "m25p80";
modal = "at26df081a";
fsl,spi-cs-sck-delay = <100>;
fsl,spi-sck-cs-delay = <50>;
};
};
...@@ -122,6 +122,7 @@ properties: ...@@ -122,6 +122,7 @@ properties:
allOf: allOf:
- $ref: arm,pl022-peripheral-props.yaml# - $ref: arm,pl022-peripheral-props.yaml#
- $ref: cdns,qspi-nor-peripheral-props.yaml# - $ref: cdns,qspi-nor-peripheral-props.yaml#
- $ref: fsl,dspi-peripheral-props.yaml#
- $ref: samsung,spi-peripheral-props.yaml# - $ref: samsung,spi-peripheral-props.yaml#
- $ref: nvidia,tegra210-quad-peripheral-props.yaml# - $ref: nvidia,tegra210-quad-peripheral-props.yaml#
......
...@@ -464,7 +464,10 @@ SLAVE DMA ENGINE ...@@ -464,7 +464,10 @@ SLAVE DMA ENGINE
SPI SPI
devm_spi_alloc_master() devm_spi_alloc_master()
devm_spi_alloc_slave() devm_spi_alloc_slave()
devm_spi_optimize_message()
devm_spi_register_controller() devm_spi_register_controller()
devm_spi_register_host()
devm_spi_register_target()
WATCHDOG WATCHDOG
devm_watchdog_register_device() devm_watchdog_register_device()
...@@ -8725,7 +8725,7 @@ FREESCALE DSPI DRIVER ...@@ -8725,7 +8725,7 @@ FREESCALE DSPI DRIVER
M: Vladimir Oltean <olteanv@gmail.com> M: Vladimir Oltean <olteanv@gmail.com>
L: linux-spi@vger.kernel.org L: linux-spi@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt F: Documentation/devicetree/bindings/spi/fsl,dspi*.yaml
F: drivers/spi/spi-fsl-dspi.c F: drivers/spi/spi-fsl-dspi.c
F: include/linux/spi/spi-fsl-dspi.h F: include/linux/spi/spi-fsl-dspi.h
......
...@@ -122,8 +122,7 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi, ...@@ -122,8 +122,7 @@ static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
max_msg_size = spi_max_message_size(spi); max_msg_size = spi_max_message_size(spi);
reg_reserve_size = config->reg_bits / BITS_PER_BYTE reg_reserve_size = (config->reg_bits + config->pad_bits) / BITS_PER_BYTE;
+ config->pad_bits / BITS_PER_BYTE;
if (max_size + reg_reserve_size > max_msg_size) if (max_size + reg_reserve_size > max_msg_size)
max_size -= reg_reserve_size; max_size -= reg_reserve_size;
......
...@@ -277,6 +277,12 @@ config SPI_CADENCE_XSPI ...@@ -277,6 +277,12 @@ config SPI_CADENCE_XSPI
device with a Cadence XSPI controller and want to access the device with a Cadence XSPI controller and want to access the
Flash as an MTD device. Flash as an MTD device.
config SPI_CH341
tristate "CH341 USB2SPI adapter"
depends on SPI_MASTER && USB
help
Enables the SPI controller on the CH341a USB to serial chip
config SPI_CLPS711X config SPI_CLPS711X
tristate "CLPS711X host SPI controller" tristate "CLPS711X host SPI controller"
depends on ARCH_CLPS711X || COMPILE_TEST depends on ARCH_CLPS711X || COMPILE_TEST
......
...@@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o ...@@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o
obj-$(CONFIG_SPI_CADENCE_XSPI) += spi-cadence-xspi.o obj-$(CONFIG_SPI_CADENCE_XSPI) += spi-cadence-xspi.o
obj-$(CONFIG_SPI_CH341) += spi-ch341.o
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
obj-$(CONFIG_SPI_CS42L43) += spi-cs42l43.o obj-$(CONFIG_SPI_CS42L43) += spi-cs42l43.o
...@@ -107,7 +108,8 @@ obj-$(CONFIG_SPI_PIC32) += spi-pic32.o ...@@ -107,7 +108,8 @@ obj-$(CONFIG_SPI_PIC32) += spi-pic32.o
obj-$(CONFIG_SPI_PIC32_SQI) += spi-pic32-sqi.o obj-$(CONFIG_SPI_PIC32_SQI) += spi-pic32-sqi.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-core.o
spi-pxa2xx-core-y := spi-pxa2xx.o spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o
......
...@@ -756,8 +756,15 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev) ...@@ -756,8 +756,15 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
int ret; int ret;
clk_prepare(aq->pclk); ret = clk_prepare(aq->pclk);
clk_prepare(aq->qspick); if (ret)
return ret;
ret = clk_prepare(aq->qspick);
if (ret) {
clk_unprepare(aq->pclk);
return ret;
}
ret = pm_runtime_force_resume(dev); ret = pm_runtime_force_resume(dev);
if (ret < 0) if (ret < 0)
......
...@@ -40,4 +40,12 @@ static inline void spi_unmap_buf(struct spi_controller *ctlr, ...@@ -40,4 +40,12 @@ static inline void spi_unmap_buf(struct spi_controller *ctlr,
} }
#endif /* CONFIG_HAS_DMA */ #endif /* CONFIG_HAS_DMA */
static inline bool spi_xfer_is_dma_mapped(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer)
{
return ctlr->can_dma && ctlr->can_dma(ctlr, spi, xfer) &&
(xfer->tx_sg_mapped || xfer->rx_sg_mapped);
}
#endif /* __LINUX_SPI_INTERNALS_H */ #endif /* __LINUX_SPI_INTERNALS_H */
...@@ -219,4 +219,5 @@ void altera_spi_init_host(struct spi_controller *host) ...@@ -219,4 +219,5 @@ void altera_spi_init_host(struct spi_controller *host)
} }
EXPORT_SYMBOL_GPL(altera_spi_init_host); EXPORT_SYMBOL_GPL(altera_spi_init_host);
MODULE_DESCRIPTION("Altera SPI Controller driver core");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define SPI_ENGINE_INST_ASSERT 0x1 #define SPI_ENGINE_INST_ASSERT 0x1
#define SPI_ENGINE_INST_WRITE 0x2 #define SPI_ENGINE_INST_WRITE 0x2
#define SPI_ENGINE_INST_MISC 0x3 #define SPI_ENGINE_INST_MISC 0x3
#define SPI_ENGINE_INST_CS_INV 0x4
#define SPI_ENGINE_CMD_REG_CLK_DIV 0x0 #define SPI_ENGINE_CMD_REG_CLK_DIV 0x0
#define SPI_ENGINE_CMD_REG_CONFIG 0x1 #define SPI_ENGINE_CMD_REG_CONFIG 0x1
...@@ -73,6 +74,8 @@ ...@@ -73,6 +74,8 @@
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SLEEP, (delay)) SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SLEEP, (delay))
#define SPI_ENGINE_CMD_SYNC(id) \ #define SPI_ENGINE_CMD_SYNC(id) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SYNC, (id)) SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SYNC, (id))
#define SPI_ENGINE_CMD_CS_INV(flags) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_CS_INV, 0, (flags))
struct spi_engine_program { struct spi_engine_program {
unsigned int length; unsigned int length;
...@@ -111,6 +114,8 @@ struct spi_engine { ...@@ -111,6 +114,8 @@ struct spi_engine {
struct spi_engine_message_state msg_state; struct spi_engine_message_state msg_state;
struct completion msg_complete; struct completion msg_complete;
unsigned int int_enable; unsigned int int_enable;
/* shadows hardware CS inversion flag state */
u8 cs_inv;
}; };
static void spi_engine_program_add_cmd(struct spi_engine_program *p, static void spi_engine_program_add_cmd(struct spi_engine_program *p,
...@@ -540,6 +545,29 @@ static int spi_engine_unoptimize_message(struct spi_message *msg) ...@@ -540,6 +545,29 @@ static int spi_engine_unoptimize_message(struct spi_message *msg)
return 0; return 0;
} }
static int spi_engine_setup(struct spi_device *device)
{
struct spi_controller *host = device->controller;
struct spi_engine *spi_engine = spi_controller_get_devdata(host);
if (device->mode & SPI_CS_HIGH)
spi_engine->cs_inv |= BIT(spi_get_chipselect(device, 0));
else
spi_engine->cs_inv &= ~BIT(spi_get_chipselect(device, 0));
writel_relaxed(SPI_ENGINE_CMD_CS_INV(spi_engine->cs_inv),
spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
/*
* In addition to setting the flags, we have to do a CS assert command
* to make the new setting actually take effect.
*/
writel_relaxed(SPI_ENGINE_CMD_ASSERT(0, 0xff),
spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
return 0;
}
static int spi_engine_transfer_one_message(struct spi_controller *host, static int spi_engine_transfer_one_message(struct spi_controller *host,
struct spi_message *msg) struct spi_message *msg)
{ {
...@@ -663,16 +691,16 @@ static int spi_engine_probe(struct platform_device *pdev) ...@@ -663,16 +691,16 @@ static int spi_engine_probe(struct platform_device *pdev)
host->unoptimize_message = spi_engine_unoptimize_message; host->unoptimize_message = spi_engine_unoptimize_message;
host->num_chipselect = 8; host->num_chipselect = 8;
/* Some features depend of the IP core version. */
if (ADI_AXI_PCORE_VER_MINOR(version) >= 2) {
host->mode_bits |= SPI_CS_HIGH;
host->setup = spi_engine_setup;
}
if (host->max_speed_hz == 0) if (host->max_speed_hz == 0)
return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0"); return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0");
ret = devm_spi_register_controller(&pdev->dev, host); return devm_spi_register_controller(&pdev->dev, host);
if (ret)
return ret;
platform_set_drvdata(pdev, host);
return 0;
} }
static const struct of_device_id spi_engine_match_table[] = { static const struct of_device_id spi_engine_match_table[] = {
......
...@@ -38,33 +38,24 @@ ...@@ -38,33 +38,24 @@
* working quickly, or testing for differences that aren't speed related. * working quickly, or testing for differences that aren't speed related.
*/ */
typedef unsigned int (*spi_bb_txrx_bufs_fn)(struct spi_device *, spi_bb_txrx_word_fn,
unsigned int, struct spi_transfer *,
unsigned int);
struct spi_bitbang_cs { struct spi_bitbang_cs {
unsigned nsecs; /* (clock cycle time)/2 */ unsigned int nsecs; /* (clock cycle time) / 2 */
u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs, spi_bb_txrx_word_fn txrx_word;
u32 word, u8 bits, unsigned flags); spi_bb_txrx_bufs_fn txrx_bufs;
unsigned (*txrx_bufs)(struct spi_device *,
u32 (*txrx_word)(
struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits,
unsigned flags),
unsigned, struct spi_transfer *,
unsigned);
}; };
static unsigned bitbang_txrx_8( static unsigned int bitbang_txrx_8(struct spi_device *spi,
struct spi_device *spi, spi_bb_txrx_word_fn txrx_word,
u32 (*txrx_word)(struct spi_device *spi, unsigned int ns,
unsigned nsecs,
u32 word, u8 bits,
unsigned flags),
unsigned ns,
struct spi_transfer *t, struct spi_transfer *t,
unsigned flags unsigned int flags)
)
{ {
unsigned bits = t->bits_per_word; unsigned int bits = t->bits_per_word;
unsigned count = t->len; unsigned int count = t->len;
const u8 *tx = t->tx_buf; const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf; u8 *rx = t->rx_buf;
...@@ -81,19 +72,14 @@ static unsigned bitbang_txrx_8( ...@@ -81,19 +72,14 @@ static unsigned bitbang_txrx_8(
return t->len - count; return t->len - count;
} }
static unsigned bitbang_txrx_16( static unsigned int bitbang_txrx_16(struct spi_device *spi,
struct spi_device *spi, spi_bb_txrx_word_fn txrx_word,
u32 (*txrx_word)(struct spi_device *spi, unsigned int ns,
unsigned nsecs,
u32 word, u8 bits,
unsigned flags),
unsigned ns,
struct spi_transfer *t, struct spi_transfer *t,
unsigned flags unsigned int flags)
)
{ {
unsigned bits = t->bits_per_word; unsigned int bits = t->bits_per_word;
unsigned count = t->len; unsigned int count = t->len;
const u16 *tx = t->tx_buf; const u16 *tx = t->tx_buf;
u16 *rx = t->rx_buf; u16 *rx = t->rx_buf;
...@@ -110,19 +96,14 @@ static unsigned bitbang_txrx_16( ...@@ -110,19 +96,14 @@ static unsigned bitbang_txrx_16(
return t->len - count; return t->len - count;
} }
static unsigned bitbang_txrx_32( static unsigned int bitbang_txrx_32(struct spi_device *spi,
struct spi_device *spi, spi_bb_txrx_word_fn txrx_word,
u32 (*txrx_word)(struct spi_device *spi, unsigned int ns,
unsigned nsecs,
u32 word, u8 bits,
unsigned flags),
unsigned ns,
struct spi_transfer *t, struct spi_transfer *t,
unsigned flags unsigned int flags)
)
{ {
unsigned bits = t->bits_per_word; unsigned int bits = t->bits_per_word;
unsigned count = t->len; unsigned int count = t->len;
const u32 *tx = t->tx_buf; const u32 *tx = t->tx_buf;
u32 *rx = t->rx_buf; u32 *rx = t->rx_buf;
...@@ -234,7 +215,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_cleanup); ...@@ -234,7 +215,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
{ {
struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang_cs *cs = spi->controller_state;
unsigned nsecs = cs->nsecs; unsigned int nsecs = cs->nsecs;
struct spi_bitbang *bitbang; struct spi_bitbang *bitbang;
bitbang = spi_controller_get_devdata(spi->controller); bitbang = spi_controller_get_devdata(spi->controller);
...@@ -247,7 +228,7 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) ...@@ -247,7 +228,7 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
} }
if (spi->mode & SPI_3WIRE) { if (spi->mode & SPI_3WIRE) {
unsigned flags; unsigned int flags;
flags = t->tx_buf ? SPI_CONTROLLER_NO_RX : SPI_CONTROLLER_NO_TX; flags = t->tx_buf ? SPI_CONTROLLER_NO_RX : SPI_CONTROLLER_NO_TX;
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, flags); return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, flags);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
/* Name of this driver */ /* Name of this driver */
...@@ -111,6 +112,7 @@ ...@@ -111,6 +112,7 @@
* @dev_busy: Device busy flag * @dev_busy: Device busy flag
* @is_decoded_cs: Flag for decoder property set or not * @is_decoded_cs: Flag for decoder property set or not
* @tx_fifo_depth: Depth of the TX FIFO * @tx_fifo_depth: Depth of the TX FIFO
* @rstc: Optional reset control for SPI controller
*/ */
struct cdns_spi { struct cdns_spi {
void __iomem *regs; void __iomem *regs;
...@@ -125,6 +127,7 @@ struct cdns_spi { ...@@ -125,6 +127,7 @@ struct cdns_spi {
u8 dev_busy; u8 dev_busy;
u32 is_decoded_cs; u32 is_decoded_cs;
unsigned int tx_fifo_depth; unsigned int tx_fifo_depth;
struct reset_control *rstc;
}; };
/* Macros for the SPI controller read/write */ /* Macros for the SPI controller read/write */
...@@ -588,14 +591,24 @@ static int cdns_spi_probe(struct platform_device *pdev) ...@@ -588,14 +591,24 @@ static int cdns_spi_probe(struct platform_device *pdev)
goto remove_ctlr; goto remove_ctlr;
} }
if (!spi_controller_is_target(ctlr)) { xspi->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, "spi");
xspi->ref_clk = devm_clk_get_enabled(&pdev->dev, "ref_clk"); if (IS_ERR(xspi->rstc)) {
if (IS_ERR(xspi->ref_clk)) { ret = dev_err_probe(&pdev->dev, PTR_ERR(xspi->rstc),
dev_err(&pdev->dev, "ref_clk clock not found.\n"); "Cannot get SPI reset.\n");
ret = PTR_ERR(xspi->ref_clk); goto remove_ctlr;
goto remove_ctlr; }
}
reset_control_assert(xspi->rstc);
reset_control_deassert(xspi->rstc);
xspi->ref_clk = devm_clk_get_enabled(&pdev->dev, "ref_clk");
if (IS_ERR(xspi->ref_clk)) {
dev_err(&pdev->dev, "ref_clk clock not found.\n");
ret = PTR_ERR(xspi->ref_clk);
goto remove_ctlr;
}
if (!spi_controller_is_target(ctlr)) {
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_get_noresume(&pdev->dev); pm_runtime_get_noresume(&pdev->dev);
......
// SPDX-License-Identifier: GPL-2.0
//
// QiHeng Electronics ch341a USB-to-SPI adapter driver
//
// Copyright (C) 2024 Johannes Thumshirn <jth@kernel.org>
//
// Based on ch341a_spi.c from the flashrom project.
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/spi/spi.h>
#define CH341_PACKET_LENGTH 32
#define CH341_DEFAULT_TIMEOUT 1000
#define CH341A_CMD_UIO_STREAM 0xab
#define CH341A_CMD_UIO_STM_END 0x20
#define CH341A_CMD_UIO_STM_DIR 0x40
#define CH341A_CMD_UIO_STM_OUT 0x80
#define CH341A_CMD_I2C_STREAM 0xaa
#define CH341A_CMD_I2C_STM_SET 0x60
#define CH341A_CMD_I2C_STM_END 0x00
#define CH341A_CMD_SPI_STREAM 0xa8
#define CH341A_STM_I2C_100K 0x01
struct ch341_spi_dev {
struct spi_controller *ctrl;
struct usb_device *udev;
unsigned int write_pipe;
unsigned int read_pipe;
int rx_len;
void *rx_buf;
u8 *tx_buf;
struct urb *rx_urb;
struct spi_device *spidev;
};
static void ch341_set_cs(struct spi_device *spi, bool is_high)
{
struct ch341_spi_dev *ch341 =
spi_controller_get_devdata(spi->controller);
int err;
memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
ch341->tx_buf[0] = CH341A_CMD_UIO_STREAM;
ch341->tx_buf[1] = CH341A_CMD_UIO_STM_OUT | (is_high ? 0x36 : 0x37);
if (is_high) {
ch341->tx_buf[2] = CH341A_CMD_UIO_STM_DIR | 0x3f;
ch341->tx_buf[3] = CH341A_CMD_UIO_STM_END;
} else {
ch341->tx_buf[2] = CH341A_CMD_UIO_STM_END;
}
err = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf,
(is_high ? 4 : 3), NULL, CH341_DEFAULT_TIMEOUT);
if (err)
dev_err(&spi->dev,
"error sending USB message for setting CS (%d)\n", err);
}
static int ch341_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *trans)
{
struct ch341_spi_dev *ch341 =
spi_controller_get_devdata(spi->controller);
int len;
int ret;
len = min(CH341_PACKET_LENGTH, trans->len + 1);
memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
ch341->tx_buf[0] = CH341A_CMD_SPI_STREAM;
memcpy(ch341->tx_buf + 1, trans->tx_buf, len);
ret = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, len,
NULL, CH341_DEFAULT_TIMEOUT);
if (ret)
return ret;
return usb_bulk_msg(ch341->udev, ch341->read_pipe, trans->rx_buf,
len - 1, NULL, CH341_DEFAULT_TIMEOUT);
}
static void ch341_recv(struct urb *urb)
{
struct ch341_spi_dev *ch341 = urb->context;
struct usb_device *udev = ch341->udev;
switch (urb->status) {
case 0:
/* success */
break;
case -ENOENT:
case -ECONNRESET:
case -EPIPE:
case -ESHUTDOWN:
dev_dbg(&udev->dev, "rx urb terminated with status: %d\n",
urb->status);
return;
default:
dev_dbg(&udev->dev, "rx urb error: %d\n", urb->status);
break;
}
}
static int ch341_config_stream(struct ch341_spi_dev *ch341)
{
memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
ch341->tx_buf[0] = CH341A_CMD_I2C_STREAM;
ch341->tx_buf[1] = CH341A_CMD_I2C_STM_SET | CH341A_STM_I2C_100K;
ch341->tx_buf[2] = CH341A_CMD_I2C_STM_END;
return usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, 3,
NULL, CH341_DEFAULT_TIMEOUT);
}
static int ch341_enable_pins(struct ch341_spi_dev *ch341, bool enable)
{
memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
ch341->tx_buf[0] = CH341A_CMD_UIO_STREAM;
ch341->tx_buf[1] = CH341A_CMD_UIO_STM_OUT | 0x37;
ch341->tx_buf[2] = CH341A_CMD_UIO_STM_DIR | (enable ? 0x3f : 0x00);
ch341->tx_buf[3] = CH341A_CMD_UIO_STM_END;
return usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, 4,
NULL, CH341_DEFAULT_TIMEOUT);
}
static struct spi_board_info chip = {
.modalias = "spi-ch341a",
};
static int ch341_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *in, *out;
struct ch341_spi_dev *ch341;
struct spi_controller *ctrl;
int ret;
ret = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL,
NULL);
if (ret)
return ret;
ctrl = devm_spi_alloc_master(&udev->dev, sizeof(struct ch341_spi_dev));
if (!ctrl)
return -ENOMEM;
ch341 = spi_controller_get_devdata(ctrl);
ch341->ctrl = ctrl;
ch341->udev = udev;
ch341->write_pipe = usb_sndbulkpipe(udev, usb_endpoint_num(out));
ch341->read_pipe = usb_rcvbulkpipe(udev, usb_endpoint_num(in));
ch341->rx_len = usb_endpoint_maxp(in);
ch341->rx_buf = devm_kzalloc(&udev->dev, ch341->rx_len, GFP_KERNEL);
if (!ch341->rx_buf)
return -ENOMEM;
ch341->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ch341->rx_urb)
return -ENOMEM;
ch341->tx_buf =
devm_kzalloc(&udev->dev, CH341_PACKET_LENGTH, GFP_KERNEL);
if (!ch341->tx_buf)
return -ENOMEM;
usb_fill_bulk_urb(ch341->rx_urb, udev, ch341->read_pipe, ch341->rx_buf,
ch341->rx_len, ch341_recv, ch341);
ret = usb_submit_urb(ch341->rx_urb, GFP_KERNEL);
if (ret) {
usb_free_urb(ch341->rx_urb);
return -ENOMEM;
}
ctrl->bus_num = -1;
ctrl->mode_bits = SPI_CPHA;
ctrl->transfer_one = ch341_transfer_one;
ctrl->set_cs = ch341_set_cs;
ctrl->auto_runtime_pm = false;
usb_set_intfdata(intf, ch341);
ret = ch341_config_stream(ch341);
if (ret)
return ret;
ret = ch341_enable_pins(ch341, true);
if (ret)
return ret;
ret = spi_register_controller(ctrl);
if (ret)
return ret;
ch341->spidev = spi_new_device(ctrl, &chip);
if (!ch341->spidev)
return -ENOMEM;
return 0;
}
static void ch341_disconnect(struct usb_interface *intf)
{
struct ch341_spi_dev *ch341 = usb_get_intfdata(intf);
spi_unregister_device(ch341->spidev);
spi_unregister_controller(ch341->ctrl);
ch341_enable_pins(ch341, false);
usb_free_urb(ch341->rx_urb);
}
static const struct usb_device_id ch341_id_table[] = {
{ USB_DEVICE(0x1a86, 0x5512) },
{ }
};
MODULE_DEVICE_TABLE(usb, ch341_id_table);
static struct usb_driver ch341a_usb_driver = {
.name = "spi-ch341",
.probe = ch341_probe,
.disconnect = ch341_disconnect,
.id_table = ch341_id_table,
};
module_usb_driver(ch341a_usb_driver);
MODULE_AUTHOR("Johannes Thumshirn <jth@kernel.org>");
MODULE_DESCRIPTION("QiHeng Electronics ch341 USB2SPI");
MODULE_LICENSE("GPL v2");
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/array_size.h> #include <linux/array_size.h>
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
...@@ -44,28 +45,10 @@ static const unsigned int cs42l43_clock_divs[] = { ...@@ -44,28 +45,10 @@ static const unsigned int cs42l43_clock_divs[] = {
2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
}; };
static const struct software_node ampl = { static struct spi_board_info amp_info_template = {
.name = "cs35l56-left",
};
static const struct software_node ampr = {
.name = "cs35l56-right",
};
static struct spi_board_info ampl_info = {
.modalias = "cs35l56",
.max_speed_hz = 11 * HZ_PER_MHZ,
.chip_select = 0,
.mode = SPI_MODE_0,
.swnode = &ampl,
};
static struct spi_board_info ampr_info = {
.modalias = "cs35l56", .modalias = "cs35l56",
.max_speed_hz = 11 * HZ_PER_MHZ, .max_speed_hz = 11 * HZ_PER_MHZ,
.chip_select = 1,
.mode = SPI_MODE_0, .mode = SPI_MODE_0,
.swnode = &ampr,
}; };
static const struct software_node cs42l43_gpiochip_swnode = { static const struct software_node cs42l43_gpiochip_swnode = {
...@@ -246,11 +229,10 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi) ...@@ -246,11 +229,10 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi)
return CS42L43_SPI_MAX_LENGTH; return CS42L43_SPI_MAX_LENGTH;
} }
static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode) static struct fwnode_handle *cs42l43_find_xu_node(struct fwnode_handle *fwnode)
{ {
static const u32 func_smart_amp = 0x1; static const u32 func_smart_amp = 0x1;
struct fwnode_handle *child_fwnode, *ext_fwnode; struct fwnode_handle *child_fwnode, *ext_fwnode;
unsigned int val;
u32 function; u32 function;
int ret; int ret;
...@@ -266,21 +248,45 @@ static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode) ...@@ -266,21 +248,45 @@ static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode)
if (!ext_fwnode) if (!ext_fwnode)
continue; continue;
ret = fwnode_property_read_u32(ext_fwnode, fwnode_handle_put(child_fwnode);
"01fa-sidecar-instances",
&val);
fwnode_handle_put(ext_fwnode); return ext_fwnode;
}
if (ret) return NULL;
continue; }
fwnode_handle_put(child_fwnode); static struct spi_board_info *cs42l43_create_bridge_amp(struct cs42l43_spi *priv,
const char * const name,
int cs, int spkid)
{
struct property_entry *props = NULL;
struct software_node *swnode;
struct spi_board_info *info;
return !!val; if (spkid >= 0) {
props = devm_kmalloc(priv->dev, sizeof(*props), GFP_KERNEL);
if (!props)
return NULL;
*props = PROPERTY_ENTRY_U32("cirrus,speaker-id", spkid);
} }
return false; swnode = devm_kmalloc(priv->dev, sizeof(*swnode), GFP_KERNEL);
if (!swnode)
return NULL;
*swnode = SOFTWARE_NODE(name, props, NULL);
info = devm_kmemdup(priv->dev, &amp_info_template,
sizeof(amp_info_template), GFP_KERNEL);
if (!info)
return NULL;
info->chip_select = cs;
info->swnode = swnode;
return info;
} }
static void cs42l43_release_of_node(void *data) static void cs42l43_release_of_node(void *data)
...@@ -298,7 +304,8 @@ static int cs42l43_spi_probe(struct platform_device *pdev) ...@@ -298,7 +304,8 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent); struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
struct cs42l43_spi *priv; struct cs42l43_spi *priv;
struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev); struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev);
bool has_sidecar = cs42l43_has_sidecar(fwnode); struct fwnode_handle *xu_fwnode __free(fwnode_handle) = cs42l43_find_xu_node(fwnode);
int nsidecars = 0;
int ret; int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
...@@ -350,7 +357,9 @@ static int cs42l43_spi_probe(struct platform_device *pdev) ...@@ -350,7 +357,9 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
return ret; return ret;
} }
if (has_sidecar) { fwnode_property_read_u32(xu_fwnode, "01fa-sidecar-instances", &nsidecars);
if (nsidecars) {
ret = software_node_register(&cs42l43_gpiochip_swnode); ret = software_node_register(&cs42l43_gpiochip_swnode);
if (ret) if (ret)
return dev_err_probe(priv->dev, ret, return dev_err_probe(priv->dev, ret,
...@@ -373,12 +382,28 @@ static int cs42l43_spi_probe(struct platform_device *pdev) ...@@ -373,12 +382,28 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
return dev_err_probe(priv->dev, ret, return dev_err_probe(priv->dev, ret,
"Failed to register SPI controller\n"); "Failed to register SPI controller\n");
if (has_sidecar) { if (nsidecars) {
if (!spi_new_device(priv->ctlr, &ampl_info)) struct spi_board_info *ampl_info;
struct spi_board_info *ampr_info;
int spkid = -EINVAL;
fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid);
dev_dbg(priv->dev, "Found speaker ID %d\n", spkid);
ampl_info = cs42l43_create_bridge_amp(priv, "cs35l56-left", 0, spkid);
if (!ampl_info)
return -ENOMEM;
ampr_info = cs42l43_create_bridge_amp(priv, "cs35l56-right", 1, spkid);
if (!ampr_info)
return -ENOMEM;
if (!spi_new_device(priv->ctlr, ampl_info))
return dev_err_probe(priv->dev, -ENODEV, return dev_err_probe(priv->dev, -ENODEV,
"Failed to create left amp slave\n"); "Failed to create left amp slave\n");
if (!spi_new_device(priv->ctlr, &ampr_info)) if (!spi_new_device(priv->ctlr, ampr_info))
return dev_err_probe(priv->dev, -ENODEV, return dev_err_probe(priv->dev, -ENODEV,
"Failed to create right amp slave\n"); "Failed to create right amp slave\n");
} }
......
...@@ -55,13 +55,15 @@ static int dw_spi_bt1_dirmap_create(struct spi_mem_dirmap_desc *desc) ...@@ -55,13 +55,15 @@ static int dw_spi_bt1_dirmap_create(struct spi_mem_dirmap_desc *desc)
!dwsbt1->dws.mem_ops.supports_op(desc->mem, &desc->info.op_tmpl)) !dwsbt1->dws.mem_ops.supports_op(desc->mem, &desc->info.op_tmpl))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
return -EOPNOTSUPP;
/* /*
* Make sure the requested region doesn't go out of the physically * Make sure the requested region doesn't go out of the physically
* mapped flash memory bounds and the operation is read-only. * mapped flash memory bounds.
*/ */
if (desc->info.offset + desc->info.length > dwsbt1->map_len || if (desc->info.offset + desc->info.length > dwsbt1->map_len)
desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) return -EINVAL;
return -EOPNOTSUPP;
return 0; return 0;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/of.h> #include <linux/of.h>
#include "internals.h"
#include "spi-dw.h" #include "spi-dw.h"
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
...@@ -438,8 +439,7 @@ static int dw_spi_transfer_one(struct spi_controller *host, ...@@ -438,8 +439,7 @@ static int dw_spi_transfer_one(struct spi_controller *host,
transfer->effective_speed_hz = dws->current_freq; transfer->effective_speed_hz = dws->current_freq;
/* Check if current transfer is a DMA transaction */ /* Check if current transfer is a DMA transaction */
if (host->can_dma && host->can_dma(host, spi, transfer)) dws->dma_mapped = spi_xfer_is_dma_mapped(host, spi, transfer);
dws->dma_mapped = host->cur_msg_mapped;
/* For poll mode just disable all interrupts */ /* For poll mode just disable all interrupts */
dw_spi_mask_intr(dws, 0xff); dw_spi_mask_intr(dws, 0xff);
......
...@@ -415,4 +415,5 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) ...@@ -415,4 +415,5 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
} }
EXPORT_SYMBOL_GPL(fsl_spi_cpm_free); EXPORT_SYMBOL_GPL(fsl_spi_cpm_free);
MODULE_DESCRIPTION("Freescale SPI controller driver CPM functions");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -1006,6 +1006,7 @@ static int dspi_setup(struct spi_device *spi) ...@@ -1006,6 +1006,7 @@ static int dspi_setup(struct spi_device *spi)
struct chip_data *chip; struct chip_data *chip;
unsigned long clkrate; unsigned long clkrate;
bool cs = true; bool cs = true;
int val;
/* Only alloc on first setup */ /* Only alloc on first setup */
chip = spi_get_ctldata(spi); chip = spi_get_ctldata(spi);
...@@ -1018,11 +1019,19 @@ static int dspi_setup(struct spi_device *spi) ...@@ -1018,11 +1019,19 @@ static int dspi_setup(struct spi_device *spi)
pdata = dev_get_platdata(&dspi->pdev->dev); pdata = dev_get_platdata(&dspi->pdev->dev);
if (!pdata) { if (!pdata) {
of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay", val = spi_delay_to_ns(&spi->cs_setup, NULL);
&cs_sck_delay); cs_sck_delay = val >= 0 ? val : 0;
if (!cs_sck_delay)
of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay", of_property_read_u32(spi->dev.of_node,
&sck_cs_delay); "fsl,spi-cs-sck-delay",
&cs_sck_delay);
val = spi_delay_to_ns(&spi->cs_hold, NULL);
sck_cs_delay = val >= 0 ? val : 0;
if (!sck_cs_delay)
of_property_read_u32(spi->dev.of_node,
"fsl,spi-sck-cs-delay",
&sck_cs_delay);
} else { } else {
cs_sck_delay = pdata->cs_sck_delay; cs_sck_delay = pdata->cs_sck_delay;
sck_cs_delay = pdata->sck_cs_delay; sck_cs_delay = pdata->sck_cs_delay;
......
...@@ -158,4 +158,5 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) ...@@ -158,4 +158,5 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
} }
EXPORT_SYMBOL_GPL(of_mpc8xxx_spi_probe); EXPORT_SYMBOL_GPL(of_mpc8xxx_spi_probe);
MODULE_DESCRIPTION("Freescale SPI/eSPI controller driver library");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -960,13 +960,13 @@ static void fsl_lpspi_remove(struct platform_device *pdev) ...@@ -960,13 +960,13 @@ static void fsl_lpspi_remove(struct platform_device *pdev)
pm_runtime_disable(fsl_lpspi->dev); pm_runtime_disable(fsl_lpspi->dev);
} }
static int __maybe_unused fsl_lpspi_suspend(struct device *dev) static int fsl_lpspi_suspend(struct device *dev)
{ {
pinctrl_pm_select_sleep_state(dev); pinctrl_pm_select_sleep_state(dev);
return pm_runtime_force_suspend(dev); return pm_runtime_force_suspend(dev);
} }
static int __maybe_unused fsl_lpspi_resume(struct device *dev) static int fsl_lpspi_resume(struct device *dev)
{ {
int ret; int ret;
...@@ -984,14 +984,14 @@ static int __maybe_unused fsl_lpspi_resume(struct device *dev) ...@@ -984,14 +984,14 @@ static int __maybe_unused fsl_lpspi_resume(struct device *dev)
static const struct dev_pm_ops fsl_lpspi_pm_ops = { static const struct dev_pm_ops fsl_lpspi_pm_ops = {
SET_RUNTIME_PM_OPS(fsl_lpspi_runtime_suspend, SET_RUNTIME_PM_OPS(fsl_lpspi_runtime_suspend,
fsl_lpspi_runtime_resume, NULL) fsl_lpspi_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume) SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume)
}; };
static struct platform_driver fsl_lpspi_driver = { static struct platform_driver fsl_lpspi_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = fsl_lpspi_dt_ids, .of_match_table = fsl_lpspi_dt_ids,
.pm = &fsl_lpspi_pm_ops, .pm = pm_ptr(&fsl_lpspi_pm_ops),
}, },
.probe = fsl_lpspi_probe, .probe = fsl_lpspi_probe,
.remove_new = fsl_lpspi_remove, .remove_new = fsl_lpspi_remove,
......
...@@ -5,17 +5,17 @@ ...@@ -5,17 +5,17 @@
* Copyright (C) 2006,2008 David Brownell * Copyright (C) 2006,2008 David Brownell
* Copyright (C) 2017 Linus Walleij * Copyright (C) 2017 Linus Walleij
*/ */
#include <linux/gpio/consumer.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio/consumer.h> #include <linux/property.h>
#include <linux/of.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_bitbang.h>
#include <linux/spi/spi_gpio.h> #include <linux/spi/spi_gpio.h>
/* /*
* This bitbanging SPI host driver should help make systems usable * This bitbanging SPI host driver should help make systems usable
* when a native hardware SPI engine is not available, perhaps because * when a native hardware SPI engine is not available, perhaps because
...@@ -239,8 +239,8 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active) ...@@ -239,8 +239,8 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
static int spi_gpio_setup(struct spi_device *spi) static int spi_gpio_setup(struct spi_device *spi)
{ {
struct gpio_desc *cs; struct gpio_desc *cs;
int status = 0;
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
int ret;
/* /*
* The CS GPIOs have already been * The CS GPIOs have already been
...@@ -248,15 +248,14 @@ static int spi_gpio_setup(struct spi_device *spi) ...@@ -248,15 +248,14 @@ static int spi_gpio_setup(struct spi_device *spi)
*/ */
if (spi_gpio->cs_gpios) { if (spi_gpio->cs_gpios) {
cs = spi_gpio->cs_gpios[spi_get_chipselect(spi, 0)]; cs = spi_gpio->cs_gpios[spi_get_chipselect(spi, 0)];
if (!spi->controller_state && cs) if (!spi->controller_state && cs) {
status = gpiod_direction_output(cs, ret = gpiod_direction_output(cs, !(spi->mode & SPI_CS_HIGH));
!(spi->mode & SPI_CS_HIGH)); if (ret)
return ret;
}
} }
if (!status) return spi_bitbang_setup(spi);
status = spi_bitbang_setup(spi);
return status;
} }
static int spi_gpio_set_direction(struct spi_device *spi, bool output) static int spi_gpio_set_direction(struct spi_device *spi, bool output)
...@@ -326,29 +325,6 @@ static int spi_gpio_request(struct device *dev, struct spi_gpio *spi_gpio) ...@@ -326,29 +325,6 @@ static int spi_gpio_request(struct device *dev, struct spi_gpio *spi_gpio)
return PTR_ERR_OR_ZERO(spi_gpio->sck); return PTR_ERR_OR_ZERO(spi_gpio->sck);
} }
#ifdef CONFIG_OF
static const struct of_device_id spi_gpio_dt_ids[] = {
{ .compatible = "spi-gpio" },
{}
};
MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids);
static int spi_gpio_probe_dt(struct platform_device *pdev,
struct spi_controller *host)
{
host->dev.of_node = pdev->dev.of_node;
host->use_gpio_descriptors = true;
return 0;
}
#else
static inline int spi_gpio_probe_dt(struct platform_device *pdev,
struct spi_controller *host)
{
return 0;
}
#endif
static int spi_gpio_probe_pdata(struct platform_device *pdev, static int spi_gpio_probe_pdata(struct platform_device *pdev,
struct spi_controller *host) struct spi_controller *host)
{ {
...@@ -389,19 +365,21 @@ static int spi_gpio_probe(struct platform_device *pdev) ...@@ -389,19 +365,21 @@ static int spi_gpio_probe(struct platform_device *pdev)
struct spi_controller *host; struct spi_controller *host;
struct spi_gpio *spi_gpio; struct spi_gpio *spi_gpio;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct spi_bitbang *bb; struct spi_bitbang *bb;
host = devm_spi_alloc_host(dev, sizeof(*spi_gpio)); host = devm_spi_alloc_host(dev, sizeof(*spi_gpio));
if (!host) if (!host)
return -ENOMEM; return -ENOMEM;
if (pdev->dev.of_node) if (fwnode) {
status = spi_gpio_probe_dt(pdev, host); device_set_node(&host->dev, fwnode);
else host->use_gpio_descriptors = true;
} else {
status = spi_gpio_probe_pdata(pdev, host); status = spi_gpio_probe_pdata(pdev, host);
if (status)
if (status) return status;
return status; }
spi_gpio = spi_controller_get_devdata(host); spi_gpio = spi_controller_get_devdata(host);
...@@ -459,10 +437,16 @@ static int spi_gpio_probe(struct platform_device *pdev) ...@@ -459,10 +437,16 @@ static int spi_gpio_probe(struct platform_device *pdev)
MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_ALIAS("platform:" DRIVER_NAME);
static const struct of_device_id spi_gpio_dt_ids[] = {
{ .compatible = "spi-gpio" },
{}
};
MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids);
static struct platform_driver spi_gpio_driver = { static struct platform_driver spi_gpio_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = of_match_ptr(spi_gpio_dt_ids), .of_match_table = spi_gpio_dt_ids,
}, },
.probe = spi_gpio_probe, .probe = spi_gpio_probe,
}; };
......
...@@ -1656,10 +1656,6 @@ static int spi_imx_setup(struct spi_device *spi) ...@@ -1656,10 +1656,6 @@ static int spi_imx_setup(struct spi_device *spi)
return 0; return 0;
} }
static void spi_imx_cleanup(struct spi_device *spi)
{
}
static int static int
spi_imx_prepare_message(struct spi_controller *controller, struct spi_message *msg) spi_imx_prepare_message(struct spi_controller *controller, struct spi_message *msg)
{ {
...@@ -1756,7 +1752,6 @@ static int spi_imx_probe(struct platform_device *pdev) ...@@ -1756,7 +1752,6 @@ static int spi_imx_probe(struct platform_device *pdev)
controller->transfer_one = spi_imx_transfer_one; controller->transfer_one = spi_imx_transfer_one;
controller->setup = spi_imx_setup; controller->setup = spi_imx_setup;
controller->cleanup = spi_imx_cleanup;
controller->prepare_message = spi_imx_prepare_message; controller->prepare_message = spi_imx_prepare_message;
controller->unprepare_message = spi_imx_unprepare_message; controller->unprepare_message = spi_imx_unprepare_message;
controller->target_abort = spi_imx_target_abort; controller->target_abort = spi_imx_target_abort;
...@@ -1903,7 +1898,7 @@ static void spi_imx_remove(struct platform_device *pdev) ...@@ -1903,7 +1898,7 @@ static void spi_imx_remove(struct platform_device *pdev)
spi_imx_sdma_exit(spi_imx); spi_imx_sdma_exit(spi_imx);
} }
static int __maybe_unused spi_imx_runtime_resume(struct device *dev) static int spi_imx_runtime_resume(struct device *dev)
{ {
struct spi_controller *controller = dev_get_drvdata(dev); struct spi_controller *controller = dev_get_drvdata(dev);
struct spi_imx_data *spi_imx; struct spi_imx_data *spi_imx;
...@@ -1924,7 +1919,7 @@ static int __maybe_unused spi_imx_runtime_resume(struct device *dev) ...@@ -1924,7 +1919,7 @@ static int __maybe_unused spi_imx_runtime_resume(struct device *dev)
return 0; return 0;
} }
static int __maybe_unused spi_imx_runtime_suspend(struct device *dev) static int spi_imx_runtime_suspend(struct device *dev)
{ {
struct spi_controller *controller = dev_get_drvdata(dev); struct spi_controller *controller = dev_get_drvdata(dev);
struct spi_imx_data *spi_imx; struct spi_imx_data *spi_imx;
...@@ -1937,29 +1932,28 @@ static int __maybe_unused spi_imx_runtime_suspend(struct device *dev) ...@@ -1937,29 +1932,28 @@ static int __maybe_unused spi_imx_runtime_suspend(struct device *dev)
return 0; return 0;
} }
static int __maybe_unused spi_imx_suspend(struct device *dev) static int spi_imx_suspend(struct device *dev)
{ {
pinctrl_pm_select_sleep_state(dev); pinctrl_pm_select_sleep_state(dev);
return 0; return 0;
} }
static int __maybe_unused spi_imx_resume(struct device *dev) static int spi_imx_resume(struct device *dev)
{ {
pinctrl_pm_select_default_state(dev); pinctrl_pm_select_default_state(dev);
return 0; return 0;
} }
static const struct dev_pm_ops imx_spi_pm = { static const struct dev_pm_ops imx_spi_pm = {
SET_RUNTIME_PM_OPS(spi_imx_runtime_suspend, RUNTIME_PM_OPS(spi_imx_runtime_suspend, spi_imx_runtime_resume, NULL)
spi_imx_runtime_resume, NULL) SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume)
SET_SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume)
}; };
static struct platform_driver spi_imx_driver = { static struct platform_driver spi_imx_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = spi_imx_dt_ids, .of_match_table = spi_imx_dt_ids,
.pm = &imx_spi_pm, .pm = pm_ptr(&imx_spi_pm),
}, },
.probe = spi_imx_probe, .probe = spi_imx_probe,
.remove_new = spi_imx_remove, .remove_new = spi_imx_remove,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include "internals.h"
#define REG_SSIDR 0x0 #define REG_SSIDR 0x0
#define REG_SSICR0 0x4 #define REG_SSICR0 0x4
...@@ -242,11 +243,10 @@ static int spi_ingenic_transfer_one(struct spi_controller *ctlr, ...@@ -242,11 +243,10 @@ static int spi_ingenic_transfer_one(struct spi_controller *ctlr,
{ {
struct ingenic_spi *priv = spi_controller_get_devdata(ctlr); struct ingenic_spi *priv = spi_controller_get_devdata(ctlr);
unsigned int bits = xfer->bits_per_word ?: spi->bits_per_word; unsigned int bits = xfer->bits_per_word ?: spi->bits_per_word;
bool can_dma = ctlr->can_dma && ctlr->can_dma(ctlr, spi, xfer);
spi_ingenic_prepare_transfer(priv, spi, xfer); spi_ingenic_prepare_transfer(priv, spi, xfer);
if (ctlr->cur_msg_mapped && can_dma) if (spi_xfer_is_dma_mapped(ctlr, spi, xfer))
return spi_ingenic_dma_tx(ctlr, xfer, bits); return spi_ingenic_dma_tx(ctlr, xfer, bits);
if (bits > 16) if (bits > 16)
......
...@@ -514,7 +514,9 @@ static int meson_spicc_prepare_message(struct spi_controller *host, ...@@ -514,7 +514,9 @@ static int meson_spicc_prepare_message(struct spi_controller *host,
/* Setup no wait cycles by default */ /* Setup no wait cycles by default */
writel_relaxed(0, spicc->base + SPICC_PERIODREG); writel_relaxed(0, spicc->base + SPICC_PERIODREG);
writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG); writel_bits_relaxed(SPICC_LBC_W1,
spi->mode & SPI_LOOP ? SPICC_LBC_W1 : 0,
spicc->base + SPICC_TESTREG);
return 0; return 0;
} }
...@@ -644,11 +646,13 @@ static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc) ...@@ -644,11 +646,13 @@ static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc)
snprintf(name, sizeof(name), "%s#pow2_fixed_div", dev_name(dev)); snprintf(name, sizeof(name), "%s#pow2_fixed_div", dev_name(dev));
init.name = name; init.name = name;
init.ops = &clk_fixed_factor_ops; init.ops = &clk_fixed_factor_ops;
init.flags = 0; if (spicc->data->has_pclk) {
if (spicc->data->has_pclk) init.flags = CLK_SET_RATE_PARENT;
parent_data[0].hw = __clk_get_hw(spicc->pclk); parent_data[0].hw = __clk_get_hw(spicc->pclk);
else } else {
init.flags = 0;
parent_data[0].hw = __clk_get_hw(spicc->core); parent_data[0].hw = __clk_get_hw(spicc->core);
}
init.num_parents = 1; init.num_parents = 1;
pow2_fixed_div->mult = 1, pow2_fixed_div->mult = 1,
...@@ -708,11 +712,13 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc) ...@@ -708,11 +712,13 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
snprintf(name, sizeof(name), "%s#enh_fixed_div", dev_name(dev)); snprintf(name, sizeof(name), "%s#enh_fixed_div", dev_name(dev));
init.name = name; init.name = name;
init.ops = &clk_fixed_factor_ops; init.ops = &clk_fixed_factor_ops;
init.flags = 0; if (spicc->data->has_pclk) {
if (spicc->data->has_pclk) init.flags = CLK_SET_RATE_PARENT;
parent_data[0].hw = __clk_get_hw(spicc->pclk); parent_data[0].hw = __clk_get_hw(spicc->pclk);
else } else {
init.flags = 0;
parent_data[0].hw = __clk_get_hw(spicc->core); parent_data[0].hw = __clk_get_hw(spicc->core);
}
init.num_parents = 1; init.num_parents = 1;
enh_fixed_div->mult = 1, enh_fixed_div->mult = 1,
...@@ -846,7 +852,7 @@ static int meson_spicc_probe(struct platform_device *pdev) ...@@ -846,7 +852,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
host->num_chipselect = 4; host->num_chipselect = 4;
host->dev.of_node = pdev->dev.of_node; host->dev.of_node = pdev->dev.of_node;
host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH; host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LOOP;
host->bits_per_word_mask = SPI_BPW_MASK(32) | host->bits_per_word_mask = SPI_BPW_MASK(32) |
SPI_BPW_MASK(24) | SPI_BPW_MASK(24) |
SPI_BPW_MASK(16) | SPI_BPW_MASK(16) |
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#define MAX_LEN (0xffff) #define MAX_LEN (0xffff)
#define MAX_CS (8) #define MAX_CS (1)
#define DEFAULT_FRAMESIZE (8) #define DEFAULT_FRAMESIZE (8)
#define FIFO_DEPTH (32) #define FIFO_DEPTH (32)
#define CLK_GEN_MODE1_MAX (255) #define CLK_GEN_MODE1_MAX (255)
...@@ -258,6 +258,9 @@ static int mchp_corespi_setup(struct spi_device *spi) ...@@ -258,6 +258,9 @@ static int mchp_corespi_setup(struct spi_device *spi)
struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller);
u32 reg; u32 reg;
if (spi_is_csgpiod(spi))
return 0;
/* /*
* Active high targets need to be specifically set to their inactive * Active high targets need to be specifically set to their inactive
* states during probe by adding them to the "control group" & thus * states during probe by adding them to the "control group" & thus
...@@ -516,6 +519,7 @@ static int mchp_corespi_probe(struct platform_device *pdev) ...@@ -516,6 +519,7 @@ static int mchp_corespi_probe(struct platform_device *pdev)
host->num_chipselect = num_cs; host->num_chipselect = num_cs;
host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
host->use_gpio_descriptors = true;
host->setup = mchp_corespi_setup; host->setup = mchp_corespi_setup;
host->bits_per_word_mask = SPI_BPW_MASK(8); host->bits_per_word_mask = SPI_BPW_MASK(8);
host->transfer_one = mchp_corespi_transfer_one; host->transfer_one = mchp_corespi_transfer_one;
......
...@@ -496,7 +496,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) ...@@ -496,7 +496,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller); struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
if (!mxic->linear.map) if (!mxic->linear.map)
return -EINVAL; return -EOPNOTSUPP;
if (desc->info.offset + desc->info.length > U32_MAX) if (desc->info.offset + desc->info.length > U32_MAX)
return -EINVAL; return -EINVAL;
......
...@@ -541,5 +541,6 @@ static void __exit omap_uwire_exit(void) ...@@ -541,5 +541,6 @@ static void __exit omap_uwire_exit(void)
subsys_initcall(omap_uwire_init); subsys_initcall(omap_uwire_init);
module_exit(omap_uwire_exit); module_exit(omap_uwire_exit);
MODULE_DESCRIPTION("MicroWire interface driver for OMAP");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include "internals.h"
#include <linux/platform_data/spi-omap2-mcspi.h> #include <linux/platform_data/spi-omap2-mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000 #define OMAP2_MCSPI_MAX_FREQ 48000000
...@@ -1208,8 +1210,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, ...@@ -1208,8 +1210,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr,
unsigned count; unsigned count;
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
ctlr->cur_msg_mapped && spi_xfer_is_dma_mapped(ctlr, spi, t))
ctlr->can_dma(ctlr, spi, t))
omap2_mcspi_set_fifo(spi, t, 1); omap2_mcspi_set_fifo(spi, t, 1);
omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 1);
...@@ -1220,8 +1221,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, ...@@ -1220,8 +1221,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr,
+ OMAP2_MCSPI_TX0); + OMAP2_MCSPI_TX0);
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
ctlr->cur_msg_mapped && spi_xfer_is_dma_mapped(ctlr, spi, t))
ctlr->can_dma(ctlr, spi, t))
count = omap2_mcspi_txrx_dma(spi, t); count = omap2_mcspi_txrx_dma(spi, t);
else else
count = omap2_mcspi_txrx_pio(spi, t); count = omap2_mcspi_txrx_pio(spi, t);
...@@ -1658,4 +1658,5 @@ static struct platform_driver omap2_mcspi_driver = { ...@@ -1658,4 +1658,5 @@ static struct platform_driver omap2_mcspi_driver = {
}; };
module_platform_driver(omap2_mcspi_driver); module_platform_driver(omap2_mcspi_driver);
MODULE_DESCRIPTION("OMAP2 McSPI controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -15,7 +16,7 @@ ...@@ -15,7 +16,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/delay.h> #include "internals.h"
#define DRV_NAME "spi-pci1xxxx" #define DRV_NAME "spi-pci1xxxx"
...@@ -567,7 +568,7 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr, ...@@ -567,7 +568,7 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr,
static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr, static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
struct spi_device *spi, struct spi_transfer *xfer) struct spi_device *spi, struct spi_transfer *xfer)
{ {
if (spi_ctlr->can_dma(spi_ctlr, spi, xfer) && spi_ctlr->cur_msg_mapped) if (spi_xfer_is_dma_mapped(spi_ctlr, spi, xfer))
return pci1xxxx_spi_transfer_with_dma(spi_ctlr, spi, xfer); return pci1xxxx_spi_transfer_with_dma(spi_ctlr, spi, xfer);
else else
return pci1xxxx_spi_transfer_with_io(spi_ctlr, spi, xfer); return pci1xxxx_spi_transfer_with_io(spi_ctlr, spi, xfer);
......
...@@ -10,8 +10,7 @@ ...@@ -10,8 +10,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/pm.h>
#include <linux/property.h>
#include <linux/sprintf.h> #include <linux/sprintf.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -265,10 +264,8 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -265,10 +264,8 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
const struct pxa_spi_info *info; const struct pxa_spi_info *info;
struct platform_device_info pi;
int ret; int ret;
struct platform_device *pdev; struct pxa2xx_spi_controller *pdata;
struct pxa2xx_spi_controller spi_pdata;
struct ssp_device *ssp; struct ssp_device *ssp;
ret = pcim_enable_device(dev); ret = pcim_enable_device(dev);
...@@ -279,15 +276,17 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -279,15 +276,17 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
if (ret) if (ret)
return ret; return ret;
memset(&spi_pdata, 0, sizeof(spi_pdata)); pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
ssp = &spi_pdata.ssp; ssp = &pdata->ssp;
ssp->dev = &dev->dev; ssp->dev = &dev->dev;
ssp->phys_base = pci_resource_start(dev, 0); ssp->phys_base = pci_resource_start(dev, 0);
ssp->mmio_base = pcim_iomap_table(dev)[0]; ssp->mmio_base = pcim_iomap_table(dev)[0];
info = (struct pxa_spi_info *)ent->driver_data; info = (struct pxa_spi_info *)ent->driver_data;
ret = info->setup(dev, &spi_pdata); ret = info->setup(dev, pdata);
if (ret) if (ret)
return ret; return ret;
...@@ -298,28 +297,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ...@@ -298,28 +297,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
return ret; return ret;
ssp->irq = pci_irq_vector(dev, 0); ssp->irq = pci_irq_vector(dev, 0);
memset(&pi, 0, sizeof(pi)); return pxa2xx_spi_probe(&dev->dev, ssp);
pi.fwnode = dev_fwnode(&dev->dev);
pi.parent = &dev->dev;
pi.name = "pxa2xx-spi";
pi.id = ssp->port_id;
pi.data = &spi_pdata;
pi.size_data = sizeof(spi_pdata);
pdev = platform_device_register_full(&pi);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
pci_set_drvdata(dev, pdev);
return 0;
} }
static void pxa2xx_spi_pci_remove(struct pci_dev *dev) static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
{ {
struct platform_device *pdev = pci_get_drvdata(dev); pxa2xx_spi_remove(&dev->dev);
platform_device_unregister(pdev);
} }
static const struct pci_device_id pxa2xx_spi_pci_devices[] = { static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
...@@ -341,6 +324,9 @@ MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices); ...@@ -341,6 +324,9 @@ MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices);
static struct pci_driver pxa2xx_spi_pci_driver = { static struct pci_driver pxa2xx_spi_pci_driver = {
.name = "pxa2xx_spi_pci", .name = "pxa2xx_spi_pci",
.id_table = pxa2xx_spi_pci_devices, .id_table = pxa2xx_spi_pci_devices,
.driver = {
.pm = pm_ptr(&pxa2xx_spi_pm_ops),
},
.probe = pxa2xx_spi_pci_probe, .probe = pxa2xx_spi_pci_probe,
.remove = pxa2xx_spi_pci_remove, .remove = pxa2xx_spi_pci_remove,
}; };
...@@ -349,4 +335,5 @@ module_pci_driver(pxa2xx_spi_pci_driver); ...@@ -349,4 +335,5 @@ module_pci_driver(pxa2xx_spi_pci_driver);
MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver"); MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(SPI_PXA2xx);
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
#include "spi-pxa2xx.h"
static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
{
return param == chan->device->dev;
}
static int
pxa2xx_spi_init_ssp(struct platform_device *pdev, struct ssp_device *ssp, enum pxa_ssp_type type)
{
struct device *dev = &pdev->dev;
struct resource *res;
int status;
u64 uid;
ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(ssp->mmio_base))
return PTR_ERR(ssp->mmio_base);
ssp->phys_base = res->start;
ssp->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ssp->clk))
return PTR_ERR(ssp->clk);
ssp->irq = platform_get_irq(pdev, 0);
if (ssp->irq < 0)
return ssp->irq;
ssp->type = type;
ssp->dev = dev;
status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid);
if (status)
ssp->port_id = -1;
else
ssp->port_id = uid;
return 0;
}
static void pxa2xx_spi_ssp_release(void *ssp)
{
pxa_ssp_free(ssp);
}
static struct ssp_device *pxa2xx_spi_ssp_request(struct platform_device *pdev)
{
struct ssp_device *ssp;
int status;
ssp = pxa_ssp_request(pdev->id, pdev->name);
if (!ssp)
return ssp;
status = devm_add_action_or_reset(&pdev->dev, pxa2xx_spi_ssp_release, ssp);
if (status)
return ERR_PTR(status);
return ssp;
}
static struct pxa2xx_spi_controller *
pxa2xx_spi_init_pdata(struct platform_device *pdev)
{
struct pxa2xx_spi_controller *pdata;
struct device *dev = &pdev->dev;
struct device *parent = dev->parent;
const void *match = device_get_match_data(dev);
enum pxa_ssp_type type = SSP_UNDEFINED;
struct ssp_device *ssp;
bool is_lpss_priv;
u32 num_cs = 1;
int status;
ssp = pxa2xx_spi_ssp_request(pdev);
if (IS_ERR(ssp))
return ERR_CAST(ssp);
if (ssp) {
type = ssp->type;
} else if (match) {
type = (enum pxa_ssp_type)(uintptr_t)match;
} else {
u32 value;
status = device_property_read_u32(dev, "intel,spi-pxa2xx-type", &value);
if (status)
return ERR_PTR(status);
type = (enum pxa_ssp_type)value;
}
/* Validate the SSP type correctness */
if (!(type > SSP_UNDEFINED && type < SSP_MAX))
return ERR_PTR(-EINVAL);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
/* Platforms with iDMA 64-bit */
is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv");
if (is_lpss_priv) {
pdata->tx_param = parent;
pdata->rx_param = parent;
pdata->dma_filter = pxa2xx_spi_idma_filter;
}
/* Read number of chip select pins, if provided */
device_property_read_u32(dev, "num-cs", &num_cs);
pdata->num_chipselect = num_cs;
pdata->is_target = device_property_read_bool(dev, "spi-slave");
pdata->enable_dma = true;
pdata->dma_burst_size = 1;
/* If SSP has been already enumerated, use it */
if (ssp)
return pdata;
status = pxa2xx_spi_init_ssp(pdev, &pdata->ssp, type);
if (status)
return ERR_PTR(status);
return pdata;
}
static int pxa2xx_spi_platform_probe(struct platform_device *pdev)
{
struct pxa2xx_spi_controller *platform_info;
struct device *dev = &pdev->dev;
struct ssp_device *ssp;
platform_info = dev_get_platdata(dev);
if (!platform_info) {
platform_info = pxa2xx_spi_init_pdata(pdev);
if (IS_ERR(platform_info))
return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n");
dev->platform_data = platform_info;
}
ssp = pxa2xx_spi_ssp_request(pdev);
if (IS_ERR(ssp))
return PTR_ERR(ssp);
if (!ssp)
ssp = &platform_info->ssp;
return pxa2xx_spi_probe(dev, ssp);
}
static void pxa2xx_spi_platform_remove(struct platform_device *pdev)
{
pxa2xx_spi_remove(&pdev->dev);
}
static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "80860F0E" },
{ "8086228E" },
{ "INT33C0" },
{ "INT33C1" },
{ "INT3430" },
{ "INT3431" },
{}
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
static const struct of_device_id pxa2xx_spi_of_match[] = {
{ .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP },
{}
};
MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
static struct platform_driver driver = {
.driver = {
.name = "pxa2xx-spi",
.pm = pm_ptr(&pxa2xx_spi_pm_ops),
.acpi_match_table = pxa2xx_spi_acpi_match,
.of_match_table = pxa2xx_spi_of_match,
},
.probe = pxa2xx_spi_platform_probe,
.remove_new = pxa2xx_spi_platform_remove,
};
static int __init pxa2xx_spi_init(void)
{
return platform_driver_register(&driver);
}
subsys_initcall(pxa2xx_spi_init);
static void __exit pxa2xx_spi_exit(void)
{
platform_driver_unregister(&driver);
}
module_exit(pxa2xx_spi_exit);
MODULE_AUTHOR("Stephen Street");
MODULE_DESCRIPTION("PXA2xx SSP SPI Controller platform driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(SPI_PXA2xx);
MODULE_ALIAS("platform:pxa2xx-spi");
MODULE_SOFTDEP("pre: dw_dmac");
This diff is collapsed.
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/pxa2xx_ssp.h> #include <linux/pxa2xx_ssp.h>
struct device;
struct gpio_desc; struct gpio_desc;
/* /*
...@@ -131,4 +132,9 @@ extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data); ...@@ -131,4 +132,9 @@ extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data);
extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data); extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data);
extern void pxa2xx_spi_dma_release(struct driver_data *drv_data); extern void pxa2xx_spi_dma_release(struct driver_data *drv_data);
int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp);
void pxa2xx_spi_remove(struct device *dev);
extern const struct dev_pm_ops pxa2xx_spi_pm_ops;
#endif /* SPI_PXA2XX_H */ #endif /* SPI_PXA2XX_H */
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/interconnect.h> #include <linux/interconnect.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -16,8 +18,7 @@ ...@@ -16,8 +18,7 @@
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/dmaengine.h> #include "internals.h"
#include <linux/dma-mapping.h>
#define QUP_CONFIG 0x0000 #define QUP_CONFIG 0x0000
#define QUP_STATE 0x0004 #define QUP_STATE 0x0004
...@@ -709,9 +710,7 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -709,9 +710,7 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32))) if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32)))
controller->mode = QUP_IO_M_MODE_FIFO; controller->mode = QUP_IO_M_MODE_FIFO;
else if (spi->controller->can_dma && else if (spi_xfer_is_dma_mapped(spi->controller, spi, xfer))
spi->controller->can_dma(spi->controller, spi, xfer) &&
spi->controller->cur_msg_mapped)
controller->mode = QUP_IO_M_MODE_BAM; controller->mode = QUP_IO_M_MODE_BAM;
else else
controller->mode = QUP_IO_M_MODE_BLOCK; controller->mode = QUP_IO_M_MODE_BLOCK;
...@@ -1369,5 +1368,6 @@ static struct platform_driver spi_qup_driver = { ...@@ -1369,5 +1368,6 @@ static struct platform_driver spi_qup_driver = {
}; };
module_platform_driver(spi_qup_driver); module_platform_driver(spi_qup_driver);
MODULE_DESCRIPTION("Qualcomm SPI controller with QUP interface");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:spi_qup"); MODULE_ALIAS("platform:spi_qup");
...@@ -95,16 +95,16 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) ...@@ -95,16 +95,16 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
spi_controller_get_devdata(desc->mem->spi->controller); spi_controller_get_devdata(desc->mem->spi->controller);
if (desc->info.offset + desc->info.length > U32_MAX) if (desc->info.offset + desc->info.length > U32_MAX)
return -ENOTSUPP; return -EINVAL;
if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
return -ENOTSUPP; return -EOPNOTSUPP;
if (!rpc->dirmap && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) if (!rpc->dirmap)
return -ENOTSUPP; return -EOPNOTSUPP;
if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
return -ENOTSUPP; return -EOPNOTSUPP;
return 0; return 0;
} }
......
...@@ -378,7 +378,7 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) ...@@ -378,7 +378,7 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
int cs = spi_get_chipselect(desc->mem->spi, 0); int cs = spi_get_chipselect(desc->mem->spi, 0);
if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
return -ENOTSUPP; return -EOPNOTSUPP;
/* /*
* Unfortunately, FIU only supports a 16 MiB direct mapping window (per * Unfortunately, FIU only supports a 16 MiB direct mapping window (per
...@@ -387,11 +387,11 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) ...@@ -387,11 +387,11 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
* flashes that are bigger than 16 MiB. * flashes that are bigger than 16 MiB.
*/ */
if (desc->info.offset + desc->info.length > MAX_MEMORY_SIZE_PER_CS) if (desc->info.offset + desc->info.length > MAX_MEMORY_SIZE_PER_CS)
return -ENOTSUPP; return -EINVAL;
/* Don't read past the memory window */ /* Don't read past the memory window */
if (cs * MAX_MEMORY_SIZE_PER_CS + desc->info.offset + desc->info.length > fiu->memory_size) if (cs * MAX_MEMORY_SIZE_PER_CS + desc->info.offset + desc->info.length > fiu->memory_size)
return -ENOTSUPP; return -EINVAL;
return 0; return 0;
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/gpio/driver.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -26,24 +27,63 @@ ...@@ -26,24 +27,63 @@
#define SPI_XCOMM_CMD_UPDATE_CONFIG 0x03 #define SPI_XCOMM_CMD_UPDATE_CONFIG 0x03
#define SPI_XCOMM_CMD_WRITE 0x04 #define SPI_XCOMM_CMD_WRITE 0x04
#define SPI_XCOMM_CMD_GPIO_SET 0x05
#define SPI_XCOMM_CLOCK 48000000 #define SPI_XCOMM_CLOCK 48000000
struct spi_xcomm { struct spi_xcomm {
struct i2c_client *i2c; struct i2c_client *i2c;
uint16_t settings; struct gpio_chip gc;
uint16_t chipselect;
u16 settings;
u16 chipselect;
unsigned int current_speed; unsigned int current_speed;
uint8_t buf[63]; u8 buf[63];
}; };
static void spi_xcomm_gpio_set_value(struct gpio_chip *chip,
unsigned int offset, int val)
{
struct spi_xcomm *spi_xcomm = gpiochip_get_data(chip);
unsigned char buf[2];
buf[0] = SPI_XCOMM_CMD_GPIO_SET;
buf[1] = !!val;
i2c_master_send(spi_xcomm->i2c, buf, 2);
}
static int spi_xcomm_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
return GPIO_LINE_DIRECTION_OUT;
}
static int spi_xcomm_gpio_add(struct spi_xcomm *spi_xcomm)
{
struct device *dev = &spi_xcomm->i2c->dev;
if (!IS_ENABLED(CONFIG_GPIOLIB))
return 0;
spi_xcomm->gc.get_direction = spi_xcomm_gpio_get_direction;
spi_xcomm->gc.set = spi_xcomm_gpio_set_value;
spi_xcomm->gc.can_sleep = 1;
spi_xcomm->gc.base = -1;
spi_xcomm->gc.ngpio = 1;
spi_xcomm->gc.label = spi_xcomm->i2c->name;
spi_xcomm->gc.owner = THIS_MODULE;
return devm_gpiochip_add_data(dev, &spi_xcomm->gc, spi_xcomm);
}
static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len) static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)
{ {
uint16_t settings; u16 settings;
uint8_t *buf = spi_xcomm->buf; u8 *buf = spi_xcomm->buf;
settings = spi_xcomm->settings; settings = spi_xcomm->settings;
settings |= len << SPI_XCOMM_SETTINGS_LEN_OFFSET; settings |= len << SPI_XCOMM_SETTINGS_LEN_OFFSET;
...@@ -56,10 +96,10 @@ static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len) ...@@ -56,10 +96,10 @@ static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)
} }
static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
struct spi_device *spi, int is_active) struct spi_device *spi, int is_active)
{ {
unsigned long cs = spi_get_chipselect(spi, 0); unsigned long cs = spi_get_chipselect(spi, 0);
uint16_t chipselect = spi_xcomm->chipselect; u16 chipselect = spi_xcomm->chipselect;
if (is_active) if (is_active)
chipselect |= BIT(cs); chipselect |= BIT(cs);
...@@ -70,7 +110,8 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, ...@@ -70,7 +110,8 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
} }
static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
struct spi_device *spi, struct spi_transfer *t, unsigned int *settings) struct spi_device *spi, struct spi_transfer *t,
unsigned int *settings)
{ {
if (t->len > 62) if (t->len > 62)
return -EINVAL; return -EINVAL;
...@@ -108,7 +149,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, ...@@ -108,7 +149,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
} }
static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm, static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm,
struct spi_device *spi, struct spi_transfer *t) struct spi_device *spi, struct spi_transfer *t)
{ {
int ret; int ret;
...@@ -119,13 +160,13 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm, ...@@ -119,13 +160,13 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm,
ret = i2c_master_send(spi_xcomm->i2c, spi_xcomm->buf, t->len + 1); ret = i2c_master_send(spi_xcomm->i2c, spi_xcomm->buf, t->len + 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
else if (ret != t->len + 1) if (ret != t->len + 1)
return -EIO; return -EIO;
} else if (t->rx_buf) { } else if (t->rx_buf) {
ret = i2c_master_recv(spi_xcomm->i2c, t->rx_buf, t->len); ret = i2c_master_recv(spi_xcomm->i2c, t->rx_buf, t->len);
if (ret < 0) if (ret < 0)
return ret; return ret;
else if (ret != t->len) if (ret != t->len)
return -EIO; return -EIO;
} }
...@@ -133,12 +174,12 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm, ...@@ -133,12 +174,12 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm,
} }
static int spi_xcomm_transfer_one(struct spi_controller *host, static int spi_xcomm_transfer_one(struct spi_controller *host,
struct spi_message *msg) struct spi_message *msg)
{ {
struct spi_xcomm *spi_xcomm = spi_controller_get_devdata(host); struct spi_xcomm *spi_xcomm = spi_controller_get_devdata(host);
unsigned int settings = spi_xcomm->settings; unsigned int settings = spi_xcomm->settings;
struct spi_device *spi = msg->spi; struct spi_device *spi = msg->spi;
unsigned cs_change = 0; unsigned int cs_change = 0;
struct spi_transfer *t; struct spi_transfer *t;
bool is_first = true; bool is_first = true;
int status = 0; int status = 0;
...@@ -147,7 +188,6 @@ static int spi_xcomm_transfer_one(struct spi_controller *host, ...@@ -147,7 +188,6 @@ static int spi_xcomm_transfer_one(struct spi_controller *host,
spi_xcomm_chipselect(spi_xcomm, spi, true); spi_xcomm_chipselect(spi_xcomm, spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) { list_for_each_entry(t, &msg->transfers, transfer_list) {
if (!t->tx_buf && !t->rx_buf && t->len) { if (!t->tx_buf && !t->rx_buf && t->len) {
status = -EINVAL; status = -EINVAL;
break; break;
...@@ -208,7 +248,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c) ...@@ -208,7 +248,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c)
struct spi_controller *host; struct spi_controller *host;
int ret; int ret;
host = spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm)); host = devm_spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm));
if (!host) if (!host)
return -ENOMEM; return -ENOMEM;
...@@ -221,13 +261,12 @@ static int spi_xcomm_probe(struct i2c_client *i2c) ...@@ -221,13 +261,12 @@ static int spi_xcomm_probe(struct i2c_client *i2c)
host->flags = SPI_CONTROLLER_HALF_DUPLEX; host->flags = SPI_CONTROLLER_HALF_DUPLEX;
host->transfer_one_message = spi_xcomm_transfer_one; host->transfer_one_message = spi_xcomm_transfer_one;
host->dev.of_node = i2c->dev.of_node; host->dev.of_node = i2c->dev.of_node;
i2c_set_clientdata(i2c, host);
ret = devm_spi_register_controller(&i2c->dev, host); ret = devm_spi_register_controller(&i2c->dev, host);
if (ret < 0) if (ret < 0)
spi_controller_put(host); return ret;
return ret; return spi_xcomm_gpio_add(spi_xcomm);
} }
static const struct i2c_device_id spi_xcomm_ids[] = { static const struct i2c_device_id spi_xcomm_ids[] = {
......
...@@ -1222,11 +1222,6 @@ void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, ...@@ -1222,11 +1222,6 @@ void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
spi_unmap_buf_attrs(ctlr, dev, sgt, dir, 0); spi_unmap_buf_attrs(ctlr, dev, sgt, dir, 0);
} }
/* Dummy SG for unidirect transfers */
static struct scatterlist dummy_sg = {
.page_link = SG_END,
};
static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
{ {
struct device *tx_dev, *rx_dev; struct device *tx_dev, *rx_dev;
...@@ -1265,8 +1260,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) ...@@ -1265,8 +1260,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
attrs); attrs);
if (ret != 0) if (ret != 0)
return ret; return ret;
} else {
xfer->tx_sg.sgl = &dummy_sg; xfer->tx_sg_mapped = true;
} }
if (xfer->rx_buf != NULL) { if (xfer->rx_buf != NULL) {
...@@ -1280,8 +1275,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) ...@@ -1280,8 +1275,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
return ret; return ret;
} }
} else {
xfer->rx_sg.sgl = &dummy_sg; xfer->rx_sg_mapped = true;
} }
} }
/* No transfer has been mapped, bail out with success */ /* No transfer has been mapped, bail out with success */
...@@ -1290,7 +1285,6 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) ...@@ -1290,7 +1285,6 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
ctlr->cur_rx_dma_dev = rx_dev; ctlr->cur_rx_dma_dev = rx_dev;
ctlr->cur_tx_dma_dev = tx_dev; ctlr->cur_tx_dma_dev = tx_dev;
ctlr->cur_msg_mapped = true;
return 0; return 0;
} }
...@@ -1301,57 +1295,46 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) ...@@ -1301,57 +1295,46 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg)
struct device *tx_dev = ctlr->cur_tx_dma_dev; struct device *tx_dev = ctlr->cur_tx_dma_dev;
struct spi_transfer *xfer; struct spi_transfer *xfer;
if (!ctlr->cur_msg_mapped || !ctlr->can_dma)
return 0;
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
/* The sync has already been done after each transfer. */ /* The sync has already been done after each transfer. */
unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC; unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC;
if (!ctlr->can_dma(ctlr, msg->spi, xfer)) if (xfer->rx_sg_mapped)
continue; spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg,
DMA_FROM_DEVICE, attrs);
xfer->rx_sg_mapped = false;
spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, if (xfer->tx_sg_mapped)
DMA_FROM_DEVICE, attrs); spi_unmap_buf_attrs(ctlr, tx_dev, &xfer->tx_sg,
spi_unmap_buf_attrs(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE, attrs);
DMA_TO_DEVICE, attrs); xfer->tx_sg_mapped = false;
} }
ctlr->cur_msg_mapped = false;
return 0; return 0;
} }
static void spi_dma_sync_for_device(struct spi_controller *ctlr, struct spi_message *msg, static void spi_dma_sync_for_device(struct spi_controller *ctlr,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct device *rx_dev = ctlr->cur_rx_dma_dev; struct device *rx_dev = ctlr->cur_rx_dma_dev;
struct device *tx_dev = ctlr->cur_tx_dma_dev; struct device *tx_dev = ctlr->cur_tx_dma_dev;
if (!ctlr->cur_msg_mapped) if (xfer->tx_sg_mapped)
return; dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
if (xfer->rx_sg_mapped)
if (!ctlr->can_dma(ctlr, msg->spi, xfer)) dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
return;
dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
} }
static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, struct spi_message *msg, static void spi_dma_sync_for_cpu(struct spi_controller *ctlr,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct device *rx_dev = ctlr->cur_rx_dma_dev; struct device *rx_dev = ctlr->cur_rx_dma_dev;
struct device *tx_dev = ctlr->cur_tx_dma_dev; struct device *tx_dev = ctlr->cur_tx_dma_dev;
if (!ctlr->cur_msg_mapped) if (xfer->rx_sg_mapped)
return; dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
if (xfer->tx_sg_mapped)
if (!ctlr->can_dma(ctlr, msg->spi, xfer)) dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
return;
dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
} }
#else /* !CONFIG_HAS_DMA */ #else /* !CONFIG_HAS_DMA */
static inline int __spi_map_msg(struct spi_controller *ctlr, static inline int __spi_map_msg(struct spi_controller *ctlr,
...@@ -1367,13 +1350,11 @@ static inline int __spi_unmap_msg(struct spi_controller *ctlr, ...@@ -1367,13 +1350,11 @@ static inline int __spi_unmap_msg(struct spi_controller *ctlr,
} }
static void spi_dma_sync_for_device(struct spi_controller *ctrl, static void spi_dma_sync_for_device(struct spi_controller *ctrl,
struct spi_message *msg,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
} }
static void spi_dma_sync_for_cpu(struct spi_controller *ctrl, static void spi_dma_sync_for_cpu(struct spi_controller *ctrl,
struct spi_message *msg,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
} }
...@@ -1645,13 +1626,13 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, ...@@ -1645,13 +1626,13 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
reinit_completion(&ctlr->xfer_completion); reinit_completion(&ctlr->xfer_completion);
fallback_pio: fallback_pio:
spi_dma_sync_for_device(ctlr, msg, xfer); spi_dma_sync_for_device(ctlr, xfer);
ret = ctlr->transfer_one(ctlr, msg->spi, xfer); ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
if (ret < 0) { if (ret < 0) {
spi_dma_sync_for_cpu(ctlr, msg, xfer); spi_dma_sync_for_cpu(ctlr, xfer);
if (ctlr->cur_msg_mapped && if ((xfer->tx_sg_mapped || xfer->rx_sg_mapped) &&
(xfer->error & SPI_TRANS_FAIL_NO_START)) { (xfer->error & SPI_TRANS_FAIL_NO_START)) {
__spi_unmap_msg(ctlr, msg); __spi_unmap_msg(ctlr, msg);
ctlr->fallback = true; ctlr->fallback = true;
xfer->error &= ~SPI_TRANS_FAIL_NO_START; xfer->error &= ~SPI_TRANS_FAIL_NO_START;
...@@ -1673,7 +1654,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, ...@@ -1673,7 +1654,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
msg->status = ret; msg->status = ret;
} }
spi_dma_sync_for_cpu(ctlr, msg, xfer); spi_dma_sync_for_cpu(ctlr, xfer);
} else { } else {
if (xfer->len) if (xfer->len)
dev_err(&msg->spi->dev, dev_err(&msg->spi->dev,
...@@ -2231,11 +2212,8 @@ static int spi_start_queue(struct spi_controller *ctlr) ...@@ -2231,11 +2212,8 @@ static int spi_start_queue(struct spi_controller *ctlr)
static int spi_stop_queue(struct spi_controller *ctlr) static int spi_stop_queue(struct spi_controller *ctlr)
{ {
unsigned int limit = 500;
unsigned long flags; unsigned long flags;
unsigned limit = 500;
int ret = 0;
spin_lock_irqsave(&ctlr->queue_lock, flags);
/* /*
* This is a bit lame, but is optimized for the common execution path. * This is a bit lame, but is optimized for the common execution path.
...@@ -2243,20 +2221,18 @@ static int spi_stop_queue(struct spi_controller *ctlr) ...@@ -2243,20 +2221,18 @@ static int spi_stop_queue(struct spi_controller *ctlr)
* execution path (pump_messages) would be required to call wake_up or * execution path (pump_messages) would be required to call wake_up or
* friends on every SPI message. Do this instead. * friends on every SPI message. Do this instead.
*/ */
while ((!list_empty(&ctlr->queue) || ctlr->busy) && limit--) { do {
spin_lock_irqsave(&ctlr->queue_lock, flags);
if (list_empty(&ctlr->queue) && !ctlr->busy) {
ctlr->running = false;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return 0;
}
spin_unlock_irqrestore(&ctlr->queue_lock, flags); spin_unlock_irqrestore(&ctlr->queue_lock, flags);
usleep_range(10000, 11000); usleep_range(10000, 11000);
spin_lock_irqsave(&ctlr->queue_lock, flags); } while (--limit);
}
if (!list_empty(&ctlr->queue) || ctlr->busy)
ret = -EBUSY;
else
ctlr->running = false;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return ret; return -EBUSY;
} }
static int spi_destroy_queue(struct spi_controller *ctlr) static int spi_destroy_queue(struct spi_controller *ctlr)
...@@ -2595,7 +2571,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi, ...@@ -2595,7 +2571,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
{ {
struct spi_controller *ctlr = spi->controller; struct spi_controller *ctlr = spi->controller;
struct spi_device *ancillary; struct spi_device *ancillary;
int rc = 0; int rc;
/* Alloc an spi_device */ /* Alloc an spi_device */
ancillary = spi_alloc_device(ctlr); ancillary = spi_alloc_device(ctlr);
...@@ -2741,7 +2717,7 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) ...@@ -2741,7 +2717,7 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
return -ENODEV; return -ENODEV;
if (ctlr) { if (ctlr) {
if (ACPI_HANDLE(ctlr->dev.parent) != parent_handle) if (!device_match_acpi_handle(ctlr->dev.parent, parent_handle))
return -ENODEV; return -ENODEV;
} else { } else {
struct acpi_device *adev; struct acpi_device *adev;
...@@ -2840,7 +2816,7 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, ...@@ -2840,7 +2816,7 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
if (!lookup.max_speed_hz && if (!lookup.max_speed_hz &&
ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) && ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) &&
ACPI_HANDLE(lookup.ctlr->dev.parent) == parent_handle) { device_match_acpi_handle(lookup.ctlr->dev.parent, parent_handle)) {
/* Apple does not use _CRS but nested devices for SPI slaves */ /* Apple does not use _CRS but nested devices for SPI slaves */
acpi_spi_parse_apple_properties(adev, &lookup); acpi_spi_parse_apple_properties(adev, &lookup);
} }
...@@ -3926,7 +3902,7 @@ static int spi_set_cs_timing(struct spi_device *spi) ...@@ -3926,7 +3902,7 @@ static int spi_set_cs_timing(struct spi_device *spi)
int spi_setup(struct spi_device *spi) int spi_setup(struct spi_device *spi)
{ {
unsigned bad_bits, ugly_bits; unsigned bad_bits, ugly_bits;
int status = 0; 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
...@@ -4398,6 +4374,34 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) ...@@ -4398,6 +4374,34 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
return ctlr->transfer(spi, message); return ctlr->transfer(spi, message);
} }
static void devm_spi_unoptimize_message(void *msg)
{
spi_unoptimize_message(msg);
}
/**
* devm_spi_optimize_message - managed version of spi_optimize_message()
* @dev: the device that manages @msg (usually @spi->dev)
* @spi: the device that will be used for the message
* @msg: the message to optimize
* Return: zero on success, else a negative error code
*
* spi_unoptimize_message() will automatically be called when the device is
* removed.
*/
int devm_spi_optimize_message(struct device *dev, struct spi_device *spi,
struct spi_message *msg)
{
int ret;
ret = spi_optimize_message(spi, msg);
if (ret)
return ret;
return devm_add_action_or_reset(dev, devm_spi_unoptimize_message, msg);
}
EXPORT_SYMBOL_GPL(devm_spi_optimize_message);
/** /**
* spi_async - asynchronous SPI transfer * spi_async - asynchronous SPI transfer
* @spi: device with which data will be exchanged * @spi: device with which data will be exchanged
......
...@@ -447,7 +447,6 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch ...@@ -447,7 +447,6 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
* @cur_msg_need_completion: Flag used internally to opportunistically skip * @cur_msg_need_completion: Flag used internally to opportunistically skip
* the @cur_msg_completion. This flag is used to signal the context that * the @cur_msg_completion. This flag is used to signal the context that
* is running spi_finalize_current_message() that it needs to complete() * is running spi_finalize_current_message() that it needs to complete()
* @cur_msg_mapped: message has been mapped for DMA
* @fallback: fallback to PIO if DMA transfer return failure with * @fallback: fallback to PIO if DMA transfer return failure with
* SPI_TRANS_FAIL_NO_START. * SPI_TRANS_FAIL_NO_START.
* @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs. * @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs.
...@@ -711,7 +710,6 @@ struct spi_controller { ...@@ -711,7 +710,6 @@ struct spi_controller {
bool running; bool running;
bool rt; bool rt;
bool auto_runtime_pm; bool auto_runtime_pm;
bool cur_msg_mapped;
bool fallback; bool fallback;
bool last_cs_mode_high; bool last_cs_mode_high;
s8 last_cs[SPI_CS_CNT_MAX]; s8 last_cs[SPI_CS_CNT_MAX];
...@@ -985,6 +983,8 @@ struct spi_res { ...@@ -985,6 +983,8 @@ struct spi_res {
* transfer this transfer. Set to 0 if the SPI bus driver does * transfer this transfer. Set to 0 if the SPI bus driver does
* not support it. * not support it.
* @transfer_list: transfers are sequenced through @spi_message.transfers * @transfer_list: transfers are sequenced through @spi_message.transfers
* @tx_sg_mapped: If true, the @tx_sg is mapped for DMA
* @rx_sg_mapped: If true, the @rx_sg is mapped for DMA
* @tx_sg: Scatterlist for transmit, currently not for client use * @tx_sg: Scatterlist for transmit, currently not for client use
* @rx_sg: Scatterlist for receive, currently not for client use * @rx_sg: Scatterlist for receive, currently not for client use
* @ptp_sts_word_pre: The word (subject to bits_per_word semantics) offset * @ptp_sts_word_pre: The word (subject to bits_per_word semantics) offset
...@@ -1081,10 +1081,13 @@ struct spi_transfer { ...@@ -1081,10 +1081,13 @@ struct spi_transfer {
#define SPI_TRANS_FAIL_IO BIT(1) #define SPI_TRANS_FAIL_IO BIT(1)
u16 error; u16 error;
dma_addr_t tx_dma; bool tx_sg_mapped;
dma_addr_t rx_dma; bool rx_sg_mapped;
struct sg_table tx_sg; struct sg_table tx_sg;
struct sg_table rx_sg; struct sg_table rx_sg;
dma_addr_t tx_dma;
dma_addr_t rx_dma;
unsigned dummy_data:1; unsigned dummy_data:1;
unsigned cs_off:1; unsigned cs_off:1;
...@@ -1273,6 +1276,8 @@ static inline void spi_message_free(struct spi_message *m) ...@@ -1273,6 +1276,8 @@ static inline void spi_message_free(struct spi_message *m)
extern int spi_optimize_message(struct spi_device *spi, struct spi_message *msg); extern int spi_optimize_message(struct spi_device *spi, struct spi_message *msg);
extern void spi_unoptimize_message(struct spi_message *msg); extern void spi_unoptimize_message(struct spi_message *msg);
extern int devm_spi_optimize_message(struct device *dev, struct spi_device *spi,
struct spi_message *msg);
extern int spi_setup(struct spi_device *spi); extern int spi_setup(struct spi_device *spi);
extern int spi_async(struct spi_device *spi, struct spi_message *message); extern int spi_async(struct spi_device *spi, struct spi_message *message);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
typedef u32 (*spi_bb_txrx_word_fn)(struct spi_device *, unsigned int, u32, u8, unsigned int);
struct spi_bitbang { struct spi_bitbang {
struct mutex lock; struct mutex lock;
u8 busy; u8 busy;
...@@ -28,9 +30,8 @@ struct spi_bitbang { ...@@ -28,9 +30,8 @@ struct spi_bitbang {
int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
/* txrx_word[SPI_MODE_*]() just looks like a shift register */ /* txrx_word[SPI_MODE_*]() just looks like a shift register */
u32 (*txrx_word[4])(struct spi_device *spi, spi_bb_txrx_word_fn txrx_word[SPI_MODE_X_MASK + 1];
unsigned nsecs,
u32 word, u8 bits, unsigned flags);
int (*set_line_direction)(struct spi_device *spi, bool output); int (*set_line_direction)(struct spi_device *spi, bool output);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment