Commit 84fccbba authored by Linus Torvalds's avatar Linus Torvalds

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

Pull spi updates from Mark Brown:
 "One small core feature this time around but mostly driver improvements
  and additions for SPI:

   - Add support for controlling the idle state of MOSI, some systems
     can support this and depending on the system integration may need
     it to avoid glitching in some situations

   - Support for polling mode in the S3C64xx driver and DMA on the
     Qualcomm QSPI driver

   - Support for several Allwinner SoCs, AMD Pensando Elba, Intel Mount
     Evans, Renesas RZ/V2M, and ST STM32H7"

* tag 'spi-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (66 commits)
  spi: dt-bindings: atmel,at91rm9200-spi: fix broken sam9x7 compatible
  spi: dt-bindings: atmel,at91rm9200-spi: add sam9x7 compatible
  spi: Add support for Renesas CSI
  spi: dt-bindings: Add bindings for RZ/V2M CSI
  spi: sun6i: Use the new helper to derive the xfer timeout value
  spi: atmel: Prevent false timeouts on long transfers
  spi: dt-bindings: stm32: do not disable spi-slave property for stm32f4-f7
  spi: Create a helper to derive adaptive timeouts
  spi: spi-geni-qcom: correctly handle -EPROBE_DEFER from dma_request_chan()
  spi: stm32: disable spi-slave property for stm32f4-f7
  spi: stm32: introduction of stm32h7 SPI device mode support
  spi: stm32: use dmaengine_terminate_{a}sync instead of _all
  spi: stm32: renaming of spi_master into spi_controller
  spi: dw: Remove misleading comment for Mount Evans SoC
  spi: dt-bindings: snps,dw-apb-ssi: Add compatible for Intel Mount Evans SoC
  spi: dw: Add compatible for Intel Mount Evans SoC
  spi: s3c64xx: Use dev_err_probe()
  spi: s3c64xx: Use the managed spi master allocation function
  spi: spl022: Probe defer is no error
  spi: spi-imx: fix mixing of native and gpio chipselects for imx51/imx53/imx6 variants
  ...
parents 362067b6 e884a133
...@@ -14,9 +14,6 @@ maintainers: ...@@ -14,9 +14,6 @@ maintainers:
- Maxime Ripard <mripard@kernel.org> - Maxime Ripard <mripard@kernel.org>
properties: properties:
"#address-cells": true
"#size-cells": true
compatible: compatible:
const: allwinner,sun4i-a10-spi const: allwinner,sun4i-a10-spi
...@@ -46,12 +43,9 @@ properties: ...@@ -46,12 +43,9 @@ properties:
- const: rx - const: rx
- const: tx - const: tx
num-cs: true
patternProperties: patternProperties:
"^.*@[0-9a-f]+": "^.*@[0-9a-f]+":
type: object type: object
additionalProperties: true
properties: properties:
reg: reg:
items: items:
...@@ -71,7 +65,7 @@ required: ...@@ -71,7 +65,7 @@ required:
- clocks - clocks
- clock-names - clock-names
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |
......
...@@ -14,11 +14,9 @@ maintainers: ...@@ -14,11 +14,9 @@ maintainers:
- Maxime Ripard <mripard@kernel.org> - Maxime Ripard <mripard@kernel.org>
properties: properties:
"#address-cells": true
"#size-cells": true
compatible: compatible:
oneOf: oneOf:
- const: allwinner,sun50i-r329-spi
- const: allwinner,sun6i-a31-spi - const: allwinner,sun6i-a31-spi
- const: allwinner,sun8i-h3-spi - const: allwinner,sun8i-h3-spi
- items: - items:
...@@ -28,6 +26,15 @@ properties: ...@@ -28,6 +26,15 @@ properties:
- allwinner,sun50i-h616-spi - allwinner,sun50i-h616-spi
- allwinner,suniv-f1c100s-spi - allwinner,suniv-f1c100s-spi
- const: allwinner,sun8i-h3-spi - const: allwinner,sun8i-h3-spi
- items:
- enum:
- allwinner,sun20i-d1-spi
- allwinner,sun50i-r329-spi-dbi
- const: allwinner,sun50i-r329-spi
- items:
- const: allwinner,sun20i-d1-spi-dbi
- const: allwinner,sun50i-r329-spi-dbi
- const: allwinner,sun50i-r329-spi
reg: reg:
maxItems: 1 maxItems: 1
...@@ -58,12 +65,9 @@ properties: ...@@ -58,12 +65,9 @@ properties:
- const: rx - const: rx
- const: tx - const: tx
num-cs: true
patternProperties: patternProperties:
"^.*@[0-9a-f]+": "^.*@[0-9a-f]+":
type: object type: object
additionalProperties: true
properties: properties:
reg: reg:
items: items:
...@@ -83,7 +87,7 @@ required: ...@@ -83,7 +87,7 @@ required:
- clocks - clocks
- clock-names - clock-names
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |
......
...@@ -20,6 +20,10 @@ properties: ...@@ -20,6 +20,10 @@ properties:
- items: - items:
- const: microchip,sam9x60-spi - const: microchip,sam9x60-spi
- const: atmel,at91rm9200-spi - const: atmel,at91rm9200-spi
- items:
- const: microchip,sam9x7-spi
- const: microchip,sam9x60-spi
- const: atmel,at91rm9200-spi
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -46,12 +46,28 @@ allOf: ...@@ -46,12 +46,28 @@ allOf:
maxItems: 2 maxItems: 2
items: items:
enum: [ qspi, qspi-ocp ] enum: [ qspi, qspi-ocp ]
- if:
properties:
compatible:
contains:
const: amd,pensando-elba-qspi
then:
properties:
cdns,fifo-depth:
enum: [ 128, 256, 1024 ]
default: 1024
else:
properties:
cdns,fifo-depth:
enum: [ 128, 256 ]
default: 128
properties: properties:
compatible: compatible:
oneOf: oneOf:
- items: - items:
- enum: - enum:
- amd,pensando-elba-qspi
- ti,k2g-qspi - ti,k2g-qspi
- ti,am654-ospi - ti,am654-ospi
- intel,lgm-qspi - intel,lgm-qspi
...@@ -76,8 +92,6 @@ properties: ...@@ -76,8 +92,6 @@ properties:
description: description:
Size of the data FIFO in words. Size of the data FIFO in words.
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
enum: [ 128, 256 ]
default: 128
cdns,fifo-width: cdns,fifo-width:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
......
...@@ -29,6 +29,9 @@ properties: ...@@ -29,6 +29,9 @@ properties:
reg: reg:
maxItems: 1 maxItems: 1
iommus:
maxItems: 1
interrupts: interrupts:
maxItems: 1 maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/renesas,rzv2m-csi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/V2M Clocked Serial Interface (CSI)
maintainers:
- Fabrizio Castro <fabrizio.castro.jz@renesas.com>
- Geert Uytterhoeven <geert+renesas@glider.be>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
const: renesas,rzv2m-csi
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: The clock used to generate the output clock (CSICLK)
- description: Internal clock to access the registers (PCLK)
clock-names:
items:
- const: csiclk
- const: pclk
resets:
maxItems: 1
power-domains:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- resets
- power-domains
- '#address-cells'
- '#size-cells'
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/r9a09g011-cpg.h>
csi4: spi@a4020200 {
compatible = "renesas,rzv2m-csi";
reg = <0xa4020200 0x80>;
interrupts = <GIC_SPI 230 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD R9A09G011_CSI4_CLK>,
<&cpg CPG_MOD R9A09G011_CPERI_GRPH_PCLK>;
clock-names = "csiclk", "pclk";
resets = <&cpg R9A09G011_CSI_GPH_PRESETN>;
power-domains = <&cpg>;
#address-cells = <1>;
#size-cells = <0>;
};
...@@ -35,8 +35,6 @@ properties: ...@@ -35,8 +35,6 @@ properties:
minItems: 2 minItems: 2
maxItems: 3 maxItems: 3
cs-gpios: true
dmas: dmas:
minItems: 2 minItems: 2
maxItems: 2 maxItems: 2
......
...@@ -74,6 +74,8 @@ properties: ...@@ -74,6 +74,8 @@ properties:
const: intel,keembay-ssi const: intel,keembay-ssi
- description: Intel Thunder Bay SPI Controller - description: Intel Thunder Bay SPI Controller
const: intel,thunderbay-ssi const: intel,thunderbay-ssi
- description: Intel Mount Evans Integrated Management Complex SPI Controller
const: intel,mountevans-imc-ssi
- description: AMD Pensando Elba SoC SPI Controller - description: AMD Pensando Elba SoC SPI Controller
const: amd,pensando-elba-spi const: amd,pensando-elba-spi
- description: Baikal-T1 SPI Controller - description: Baikal-T1 SPI Controller
......
...@@ -17,9 +17,6 @@ allOf: ...@@ -17,9 +17,6 @@ allOf:
- $ref: spi-controller.yaml# - $ref: spi-controller.yaml#
properties: properties:
"#address-cells": true
"#size-cells": true
compatible: compatible:
const: socionext,uniphier-scssi const: socionext,uniphier-scssi
......
...@@ -17,7 +17,7 @@ description: | ...@@ -17,7 +17,7 @@ description: |
properties: properties:
$nodename: $nodename:
pattern: "^spi(@.*|-[0-9a-f])*$" pattern: "^spi(@.*|-([0-9]|[1-9][0-9]+))?$"
"#address-cells": "#address-cells":
enum: [0, 1] enum: [0, 1]
......
...@@ -32,6 +32,12 @@ properties: ...@@ -32,6 +32,12 @@ properties:
clocks: clocks:
maxItems: 2 maxItems: 2
iommus:
maxItems: 1
power-domains:
maxItems: 1
required: required:
- compatible - compatible
- reg - reg
......
...@@ -825,6 +825,12 @@ config SPI_RSPI ...@@ -825,6 +825,12 @@ config SPI_RSPI
help help
SPI driver for Renesas RSPI and QSPI blocks. SPI driver for Renesas RSPI and QSPI blocks.
config SPI_RZV2M_CSI
tristate "Renesas RZV2M CSI controller"
depends on ARCH_RENESAS || COMPILE_TEST
help
SPI driver for Renesas RZ/V2M Clocked Serial Interface (CSI)
config SPI_QCOM_QSPI config SPI_QCOM_QSPI
tristate "QTI QSPI controller" tristate "QTI QSPI controller"
depends on ARCH_QCOM || COMPILE_TEST depends on ARCH_QCOM || COMPILE_TEST
...@@ -936,6 +942,7 @@ config SPI_SPRD_ADI ...@@ -936,6 +942,7 @@ config SPI_SPRD_ADI
config SPI_STM32 config SPI_STM32
tristate "STMicroelectronics STM32 SPI controller" tristate "STMicroelectronics STM32 SPI controller"
depends on ARCH_STM32 || COMPILE_TEST depends on ARCH_STM32 || COMPILE_TEST
select SPI_SLAVE
help help
SPI driver for STMicroelectronics STM32 SoCs. SPI driver for STMicroelectronics STM32 SoCs.
......
...@@ -113,6 +113,7 @@ obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o ...@@ -113,6 +113,7 @@ obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o
obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o
obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o
obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o
obj-$(CONFIG_SPI_SH) += spi-sh.o obj-$(CONFIG_SPI_SH) += spi-sh.o
......
...@@ -233,7 +233,8 @@ ...@@ -233,7 +233,8 @@
*/ */
#define DMA_MIN_BYTES 16 #define DMA_MIN_BYTES 16
#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000)) #define SPI_DMA_MIN_TIMEOUT (msecs_to_jiffies(1000))
#define SPI_DMA_TIMEOUT_PER_10K (msecs_to_jiffies(4))
#define AUTOSUSPEND_TIMEOUT 2000 #define AUTOSUSPEND_TIMEOUT 2000
...@@ -1279,7 +1280,8 @@ static int atmel_spi_one_transfer(struct spi_controller *host, ...@@ -1279,7 +1280,8 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
struct atmel_spi_device *asd; struct atmel_spi_device *asd;
int timeout; int timeout;
int ret; int ret;
unsigned long dma_timeout; unsigned int dma_timeout;
long ret_timeout;
as = spi_controller_get_devdata(host); as = spi_controller_get_devdata(host);
...@@ -1333,11 +1335,13 @@ static int atmel_spi_one_transfer(struct spi_controller *host, ...@@ -1333,11 +1335,13 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
atmel_spi_unlock(as); atmel_spi_unlock(as);
} }
dma_timeout = wait_for_completion_timeout(&as->xfer_completion, dma_timeout = msecs_to_jiffies(spi_controller_xfer_timeout(host, xfer));
SPI_DMA_TIMEOUT); ret_timeout = wait_for_completion_interruptible_timeout(&as->xfer_completion,
if (WARN_ON(dma_timeout == 0)) { dma_timeout);
dev_err(&spi->dev, "spi transfer timeout\n"); if (ret_timeout <= 0) {
as->done_status = -EIO; dev_err(&spi->dev, "spi transfer %s\n",
!ret_timeout ? "timeout" : "canceled");
as->done_status = ret_timeout < 0 ? ret_timeout : -EIO;
} }
if (as->done_status) if (as->done_status)
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define CQSPI_SUPPORT_EXTERNAL_DMA BIT(2) #define CQSPI_SUPPORT_EXTERNAL_DMA BIT(2)
#define CQSPI_NO_SUPPORT_WR_COMPLETION BIT(3) #define CQSPI_NO_SUPPORT_WR_COMPLETION BIT(3)
#define CQSPI_SLOW_SRAM BIT(4) #define CQSPI_SLOW_SRAM BIT(4)
#define CQSPI_NEEDS_APB_AHB_HAZARD_WAR BIT(5)
/* Capabilities */ /* Capabilities */
#define CQSPI_SUPPORTS_OCTAL BIT(0) #define CQSPI_SUPPORTS_OCTAL BIT(0)
...@@ -90,6 +91,7 @@ struct cqspi_st { ...@@ -90,6 +91,7 @@ struct cqspi_st {
u32 pd_dev_id; u32 pd_dev_id;
bool wr_completion; bool wr_completion;
bool slow_sram; bool slow_sram;
bool apb_ahb_hazard;
}; };
struct cqspi_driver_platdata { struct cqspi_driver_platdata {
...@@ -1027,6 +1029,13 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, ...@@ -1027,6 +1029,13 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata,
if (cqspi->wr_delay) if (cqspi->wr_delay)
ndelay(cqspi->wr_delay); ndelay(cqspi->wr_delay);
/*
* If a hazard exists between the APB and AHB interfaces, perform a
* dummy readback from the controller to ensure synchronization.
*/
if (cqspi->apb_ahb_hazard)
readl(reg_base + CQSPI_REG_INDIRECTWR);
while (remaining > 0) { while (remaining > 0) {
size_t write_words, mod_bytes; size_t write_words, mod_bytes;
...@@ -1754,6 +1763,8 @@ static int cqspi_probe(struct platform_device *pdev) ...@@ -1754,6 +1763,8 @@ static int cqspi_probe(struct platform_device *pdev)
cqspi->wr_completion = false; cqspi->wr_completion = false;
if (ddata->quirks & CQSPI_SLOW_SRAM) if (ddata->quirks & CQSPI_SLOW_SRAM)
cqspi->slow_sram = true; cqspi->slow_sram = true;
if (ddata->quirks & CQSPI_NEEDS_APB_AHB_HAZARD_WAR)
cqspi->apb_ahb_hazard = true;
if (of_device_is_compatible(pdev->dev.of_node, if (of_device_is_compatible(pdev->dev.of_node,
"xlnx,versal-ospi-1.0")) { "xlnx,versal-ospi-1.0")) {
...@@ -1888,6 +1899,10 @@ static const struct cqspi_driver_platdata jh7110_qspi = { ...@@ -1888,6 +1899,10 @@ static const struct cqspi_driver_platdata jh7110_qspi = {
.quirks = CQSPI_DISABLE_DAC_MODE, .quirks = CQSPI_DISABLE_DAC_MODE,
}; };
static const struct cqspi_driver_platdata pensando_cdns_qspi = {
.quirks = CQSPI_NEEDS_APB_AHB_HAZARD_WAR | CQSPI_DISABLE_DAC_MODE,
};
static const struct of_device_id cqspi_dt_ids[] = { static const struct of_device_id cqspi_dt_ids[] = {
{ {
.compatible = "cdns,qspi-nor", .compatible = "cdns,qspi-nor",
...@@ -1917,6 +1932,10 @@ static const struct of_device_id cqspi_dt_ids[] = { ...@@ -1917,6 +1932,10 @@ static const struct of_device_id cqspi_dt_ids[] = {
.compatible = "starfive,jh7110-qspi", .compatible = "starfive,jh7110-qspi",
.data = &jh7110_qspi, .data = &jh7110_qspi,
}, },
{
.compatible = "amd,pensando-elba-qspi",
.data = &pensando_cdns_qspi,
},
{ /* end of table */ } { /* end of table */ }
}; };
......
...@@ -102,6 +102,7 @@ ...@@ -102,6 +102,7 @@
* @regs: Virtual address of the SPI controller registers * @regs: Virtual address of the SPI controller registers
* @ref_clk: Pointer to the peripheral clock * @ref_clk: Pointer to the peripheral clock
* @pclk: Pointer to the APB clock * @pclk: Pointer to the APB clock
* @clk_rate: Reference clock frequency, taken from @ref_clk
* @speed_hz: Current SPI bus clock speed in Hz * @speed_hz: Current SPI bus clock speed in Hz
* @txbuf: Pointer to the TX buffer * @txbuf: Pointer to the TX buffer
* @rxbuf: Pointer to the RX buffer * @rxbuf: Pointer to the RX buffer
......
...@@ -57,21 +57,17 @@ static const struct debugfs_reg32 dw_spi_dbgfs_regs[] = { ...@@ -57,21 +57,17 @@ static const struct debugfs_reg32 dw_spi_dbgfs_regs[] = {
DW_SPI_DBGFS_REG("RX_SAMPLE_DLY", DW_SPI_RX_SAMPLE_DLY), DW_SPI_DBGFS_REG("RX_SAMPLE_DLY", DW_SPI_RX_SAMPLE_DLY),
}; };
static int dw_spi_debugfs_init(struct dw_spi *dws) static void dw_spi_debugfs_init(struct dw_spi *dws)
{ {
char name[32]; char name[32];
snprintf(name, 32, "dw_spi%d", dws->master->bus_num); snprintf(name, 32, "dw_spi%d", dws->master->bus_num);
dws->debugfs = debugfs_create_dir(name, NULL); dws->debugfs = debugfs_create_dir(name, NULL);
if (!dws->debugfs)
return -ENOMEM;
dws->regset.regs = dw_spi_dbgfs_regs; dws->regset.regs = dw_spi_dbgfs_regs;
dws->regset.nregs = ARRAY_SIZE(dw_spi_dbgfs_regs); dws->regset.nregs = ARRAY_SIZE(dw_spi_dbgfs_regs);
dws->regset.base = dws->regs; dws->regset.base = dws->regs;
debugfs_create_regset32("registers", 0400, dws->debugfs, &dws->regset); debugfs_create_regset32("registers", 0400, dws->debugfs, &dws->regset);
return 0;
} }
static void dw_spi_debugfs_remove(struct dw_spi *dws) static void dw_spi_debugfs_remove(struct dw_spi *dws)
...@@ -80,9 +76,8 @@ static void dw_spi_debugfs_remove(struct dw_spi *dws) ...@@ -80,9 +76,8 @@ static void dw_spi_debugfs_remove(struct dw_spi *dws)
} }
#else #else
static inline int dw_spi_debugfs_init(struct dw_spi *dws) static inline void dw_spi_debugfs_init(struct dw_spi *dws)
{ {
return 0;
} }
static inline void dw_spi_debugfs_remove(struct dw_spi *dws) static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
...@@ -426,7 +421,10 @@ static int dw_spi_transfer_one(struct spi_controller *master, ...@@ -426,7 +421,10 @@ static int dw_spi_transfer_one(struct spi_controller *master,
int ret; int ret;
dws->dma_mapped = 0; dws->dma_mapped = 0;
dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); dws->n_bytes =
roundup_pow_of_two(DIV_ROUND_UP(transfer->bits_per_word,
BITS_PER_BYTE));
dws->tx = (void *)transfer->tx_buf; dws->tx = (void *)transfer->tx_buf;
dws->tx_len = transfer->len / dws->n_bytes; dws->tx_len = transfer->len / dws->n_bytes;
dws->rx = transfer->rx_buf; dws->rx = transfer->rx_buf;
......
...@@ -72,12 +72,22 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws) ...@@ -72,12 +72,22 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
dw_writel(dws, DW_SPI_DMATDLR, dws->txburst); dw_writel(dws, DW_SPI_DMATDLR, dws->txburst);
} }
static void dw_spi_dma_sg_burst_init(struct dw_spi *dws) static int dw_spi_dma_caps_init(struct dw_spi *dws)
{ {
struct dma_slave_caps tx = {0}, rx = {0}; struct dma_slave_caps tx, rx;
int ret;
ret = dma_get_slave_caps(dws->txchan, &tx);
if (ret)
return ret;
dma_get_slave_caps(dws->txchan, &tx); ret = dma_get_slave_caps(dws->rxchan, &rx);
dma_get_slave_caps(dws->rxchan, &rx); if (ret)
return ret;
if (!(tx.directions & BIT(DMA_MEM_TO_DEV) &&
rx.directions & BIT(DMA_DEV_TO_MEM)))
return -ENXIO;
if (tx.max_sg_burst > 0 && rx.max_sg_burst > 0) if (tx.max_sg_burst > 0 && rx.max_sg_burst > 0)
dws->dma_sg_burst = min(tx.max_sg_burst, rx.max_sg_burst); dws->dma_sg_burst = min(tx.max_sg_burst, rx.max_sg_burst);
...@@ -87,6 +97,15 @@ static void dw_spi_dma_sg_burst_init(struct dw_spi *dws) ...@@ -87,6 +97,15 @@ static void dw_spi_dma_sg_burst_init(struct dw_spi *dws)
dws->dma_sg_burst = rx.max_sg_burst; dws->dma_sg_burst = rx.max_sg_burst;
else else
dws->dma_sg_burst = 0; dws->dma_sg_burst = 0;
/*
* Assuming both channels belong to the same DMA controller hence the
* peripheral side address width capabilities most likely would be
* the same.
*/
dws->dma_addr_widths = tx.dst_addr_widths & rx.src_addr_widths;
return 0;
} }
static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws) static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
...@@ -95,6 +114,7 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws) ...@@ -95,6 +114,7 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
struct dw_dma_slave dma_rx = { .src_id = 0 }, *rx = &dma_rx; struct dw_dma_slave dma_rx = { .src_id = 0 }, *rx = &dma_rx;
struct pci_dev *dma_dev; struct pci_dev *dma_dev;
dma_cap_mask_t mask; dma_cap_mask_t mask;
int ret = -EBUSY;
/* /*
* Get pci device for DMA controller, currently it could only * Get pci device for DMA controller, currently it could only
...@@ -124,20 +144,25 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws) ...@@ -124,20 +144,25 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
init_completion(&dws->dma_completion); init_completion(&dws->dma_completion);
dw_spi_dma_maxburst_init(dws); ret = dw_spi_dma_caps_init(dws);
if (ret)
goto free_txchan;
dw_spi_dma_sg_burst_init(dws); dw_spi_dma_maxburst_init(dws);
pci_dev_put(dma_dev); pci_dev_put(dma_dev);
return 0; return 0;
free_txchan:
dma_release_channel(dws->txchan);
dws->txchan = NULL;
free_rxchan: free_rxchan:
dma_release_channel(dws->rxchan); dma_release_channel(dws->rxchan);
dws->rxchan = NULL; dws->rxchan = NULL;
err_exit: err_exit:
pci_dev_put(dma_dev); pci_dev_put(dma_dev);
return -EBUSY; return ret;
} }
static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws) static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
...@@ -163,12 +188,17 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws) ...@@ -163,12 +188,17 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
init_completion(&dws->dma_completion); init_completion(&dws->dma_completion);
dw_spi_dma_maxburst_init(dws); ret = dw_spi_dma_caps_init(dws);
if (ret)
goto free_txchan;
dw_spi_dma_sg_burst_init(dws); dw_spi_dma_maxburst_init(dws);
return 0; return 0;
free_txchan:
dma_release_channel(dws->txchan);
dws->txchan = NULL;
free_rxchan: free_rxchan:
dma_release_channel(dws->rxchan); dma_release_channel(dws->rxchan);
dws->rxchan = NULL; dws->rxchan = NULL;
...@@ -198,22 +228,32 @@ static irqreturn_t dw_spi_dma_transfer_handler(struct dw_spi *dws) ...@@ -198,22 +228,32 @@ static irqreturn_t dw_spi_dma_transfer_handler(struct dw_spi *dws)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static enum dma_slave_buswidth dw_spi_dma_convert_width(u8 n_bytes)
{
switch (n_bytes) {
case 1:
return DMA_SLAVE_BUSWIDTH_1_BYTE;
case 2:
return DMA_SLAVE_BUSWIDTH_2_BYTES;
case 4:
return DMA_SLAVE_BUSWIDTH_4_BYTES;
default:
return DMA_SLAVE_BUSWIDTH_UNDEFINED;
}
}
static bool dw_spi_can_dma(struct spi_controller *master, static bool dw_spi_can_dma(struct spi_controller *master,
struct spi_device *spi, struct spi_transfer *xfer) struct spi_device *spi, struct spi_transfer *xfer)
{ {
struct dw_spi *dws = spi_controller_get_devdata(master); struct dw_spi *dws = spi_controller_get_devdata(master);
enum dma_slave_buswidth dma_bus_width;
return xfer->len > dws->fifo_len; if (xfer->len <= dws->fifo_len)
} return false;
static enum dma_slave_buswidth dw_spi_dma_convert_width(u8 n_bytes) dma_bus_width = dw_spi_dma_convert_width(dws->n_bytes);
{
if (n_bytes == 1)
return DMA_SLAVE_BUSWIDTH_1_BYTE;
else if (n_bytes == 2)
return DMA_SLAVE_BUSWIDTH_2_BYTES;
return DMA_SLAVE_BUSWIDTH_UNDEFINED; return dws->dma_addr_widths & BIT(dma_bus_width);
} }
static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed) static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
......
...@@ -236,6 +236,24 @@ static int dw_spi_intel_init(struct platform_device *pdev, ...@@ -236,6 +236,24 @@ static int dw_spi_intel_init(struct platform_device *pdev,
return 0; return 0;
} }
/*
* DMA-based mem ops are not configured for this device and are not tested.
*/
static int dw_spi_mountevans_imc_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio)
{
/*
* The Intel Mount Evans SoC's Integrated Management Complex DW
* apb_ssi_v4.02a controller has an errata where a full TX FIFO can
* result in data corruption. The suggested workaround is to never
* completely fill the FIFO. The TX FIFO has a size of 32 so the
* fifo_len is set to 31.
*/
dwsmmio->dws.fifo_len = 31;
return 0;
}
static int dw_spi_canaan_k210_init(struct platform_device *pdev, static int dw_spi_canaan_k210_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio) struct dw_spi_mmio *dwsmmio)
{ {
...@@ -405,6 +423,10 @@ static const struct of_device_id dw_spi_mmio_of_match[] = { ...@@ -405,6 +423,10 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init}, { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
{ .compatible = "intel,keembay-ssi", .data = dw_spi_intel_init}, { .compatible = "intel,keembay-ssi", .data = dw_spi_intel_init},
{ .compatible = "intel,thunderbay-ssi", .data = dw_spi_intel_init}, { .compatible = "intel,thunderbay-ssi", .data = dw_spi_intel_init},
{
.compatible = "intel,mountevans-imc-ssi",
.data = dw_spi_mountevans_imc_init,
},
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init}, { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
{ .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init}, { .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
{ .compatible = "amd,pensando-elba-spi", .data = dw_spi_elba_init}, { .compatible = "amd,pensando-elba-spi", .data = dw_spi_elba_init},
......
...@@ -190,6 +190,7 @@ struct dw_spi { ...@@ -190,6 +190,7 @@ struct dw_spi {
struct dma_chan *rxchan; struct dma_chan *rxchan;
u32 rxburst; u32 rxburst;
u32 dma_sg_burst; u32 dma_sg_burst;
u32 dma_addr_widths;
unsigned long dma_chan_busy; unsigned long dma_chan_busy;
dma_addr_t dma_addr; /* phy address of the Data register */ dma_addr_t dma_addr; /* phy address of the Data register */
const struct dw_spi_dma_ops *dma_ops; const struct dw_spi_dma_ops *dma_ops;
......
...@@ -303,6 +303,12 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) ...@@ -303,6 +303,12 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
perclk_rate = clk_get_rate(fsl_lpspi->clk_per); perclk_rate = clk_get_rate(fsl_lpspi->clk_per);
if (!config.speed_hz) {
dev_err(fsl_lpspi->dev,
"error: the transmission speed provided is 0!\n");
return -EINVAL;
}
if (config.speed_hz > perclk_rate / 2) { if (config.speed_hz > perclk_rate / 2) {
dev_err(fsl_lpspi->dev, dev_err(fsl_lpspi->dev,
"per-clk should be at least two times of transfer speed"); "per-clk should be at least two times of transfer speed");
...@@ -911,7 +917,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) ...@@ -911,7 +917,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
if (ret == -EPROBE_DEFER) if (ret == -EPROBE_DEFER)
goto out_pm_get; goto out_pm_get;
if (ret < 0) if (ret < 0)
dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret); dev_warn(&pdev->dev, "dma setup error %d, use pio\n", ret);
else else
/* /*
* disable LPSPI module IRQ when enable DMA mode successfully, * disable LPSPI module IRQ when enable DMA mode successfully,
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#define CS_DEMUX_OUTPUT_SEL GENMASK(3, 0) #define CS_DEMUX_OUTPUT_SEL GENMASK(3, 0)
#define SE_SPI_TRANS_CFG 0x25c #define SE_SPI_TRANS_CFG 0x25c
#define CS_TOGGLE BIT(0) #define CS_TOGGLE BIT(1)
#define SE_SPI_WORD_LEN 0x268 #define SE_SPI_WORD_LEN 0x268
#define WORD_LEN_MSK GENMASK(9, 0) #define WORD_LEN_MSK GENMASK(9, 0)
......
...@@ -169,7 +169,7 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs) ...@@ -169,7 +169,7 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs)
master = container_of(hs->dev, struct spi_controller, dev); master = container_of(hs->dev, struct spi_controller, dev);
snprintf(name, 32, "hisi_spi%d", master->bus_num); snprintf(name, 32, "hisi_spi%d", master->bus_num);
hs->debugfs = debugfs_create_dir(name, NULL); hs->debugfs = debugfs_create_dir(name, NULL);
if (!hs->debugfs) if (IS_ERR(hs->debugfs))
return -ENOMEM; return -ENOMEM;
hs->regset.regs = hisi_spi_regs; hs->regset.regs = hisi_spi_regs;
......
...@@ -281,6 +281,7 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device ...@@ -281,6 +281,7 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
#define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs & 3) + 4)) #define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs & 3) + 4))
#define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs & 3) + 8)) #define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs & 3) + 8))
#define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs & 3) + 12)) #define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs & 3) + 12))
#define MX51_ECSPI_CONFIG_DATACTL(cs) (1 << ((cs & 3) + 16))
#define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs & 3) + 20)) #define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs & 3) + 20))
#define MX51_ECSPI_INT 0x10 #define MX51_ECSPI_INT 0x10
...@@ -516,6 +517,13 @@ static void mx51_ecspi_disable(struct spi_imx_data *spi_imx) ...@@ -516,6 +517,13 @@ static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
} }
static int mx51_ecspi_channel(const struct spi_device *spi)
{
if (!spi_get_csgpiod(spi, 0))
return spi_get_chipselect(spi, 0);
return spi->controller->unused_native_cs;
}
static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx, static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
struct spi_message *msg) struct spi_message *msg)
{ {
...@@ -526,6 +534,7 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx, ...@@ -526,6 +534,7 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
u32 testreg, delay; u32 testreg, delay;
u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG); u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
u32 current_cfg = cfg; u32 current_cfg = cfg;
int channel = mx51_ecspi_channel(spi);
/* set Master or Slave mode */ /* set Master or Slave mode */
if (spi_imx->slave_mode) if (spi_imx->slave_mode)
...@@ -540,7 +549,7 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx, ...@@ -540,7 +549,7 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl); ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl);
/* set chip select to use */ /* set chip select to use */
ctrl |= MX51_ECSPI_CTRL_CS(spi_get_chipselect(spi, 0)); ctrl |= MX51_ECSPI_CTRL_CS(channel);
/* /*
* The ctrl register must be written first, with the EN bit set other * The ctrl register must be written first, with the EN bit set other
...@@ -561,22 +570,27 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx, ...@@ -561,22 +570,27 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
* BURST_LENGTH + 1 bits are received * BURST_LENGTH + 1 bits are received
*/ */
if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx)) if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(spi_get_chipselect(spi, 0)); cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(channel);
else else
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi_get_chipselect(spi, 0)); cfg |= MX51_ECSPI_CONFIG_SBBCTRL(channel);
if (spi->mode & SPI_CPOL) { if (spi->mode & SPI_CPOL) {
cfg |= MX51_ECSPI_CONFIG_SCLKPOL(spi_get_chipselect(spi, 0)); cfg |= MX51_ECSPI_CONFIG_SCLKPOL(channel);
cfg |= MX51_ECSPI_CONFIG_SCLKCTL(spi_get_chipselect(spi, 0)); cfg |= MX51_ECSPI_CONFIG_SCLKCTL(channel);
} else { } else {
cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(spi_get_chipselect(spi, 0)); cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(channel);
cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi_get_chipselect(spi, 0)); cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(channel);
} }
if (spi->mode & SPI_MOSI_IDLE_LOW)
cfg |= MX51_ECSPI_CONFIG_DATACTL(channel);
else
cfg &= ~MX51_ECSPI_CONFIG_DATACTL(channel);
if (spi->mode & SPI_CS_HIGH) if (spi->mode & SPI_CS_HIGH)
cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0)); cfg |= MX51_ECSPI_CONFIG_SSBPOL(channel);
else else
cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0)); cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(channel);
if (cfg == current_cfg) if (cfg == current_cfg)
return 0; return 0;
...@@ -621,14 +635,15 @@ static void mx51_configure_cpha(struct spi_imx_data *spi_imx, ...@@ -621,14 +635,15 @@ static void mx51_configure_cpha(struct spi_imx_data *spi_imx,
bool cpha = (spi->mode & SPI_CPHA); bool cpha = (spi->mode & SPI_CPHA);
bool flip_cpha = (spi->mode & SPI_RX_CPHA_FLIP) && spi_imx->rx_only; bool flip_cpha = (spi->mode & SPI_RX_CPHA_FLIP) && spi_imx->rx_only;
u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG); u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
int channel = mx51_ecspi_channel(spi);
/* Flip cpha logical value iff flip_cpha */ /* Flip cpha logical value iff flip_cpha */
cpha ^= flip_cpha; cpha ^= flip_cpha;
if (cpha) if (cpha)
cfg |= MX51_ECSPI_CONFIG_SCLKPHA(spi_get_chipselect(spi, 0)); cfg |= MX51_ECSPI_CONFIG_SCLKPHA(channel);
else else
cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(spi_get_chipselect(spi, 0)); cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(channel);
writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG); writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
} }
...@@ -1737,20 +1752,21 @@ static int spi_imx_probe(struct platform_device *pdev) ...@@ -1737,20 +1752,21 @@ static int spi_imx_probe(struct platform_device *pdev)
else else
controller->num_chipselect = 3; controller->num_chipselect = 3;
spi_imx->controller->transfer_one = spi_imx_transfer_one; controller->transfer_one = spi_imx_transfer_one;
spi_imx->controller->setup = spi_imx_setup; controller->setup = spi_imx_setup;
spi_imx->controller->cleanup = spi_imx_cleanup; controller->cleanup = spi_imx_cleanup;
spi_imx->controller->prepare_message = spi_imx_prepare_message; controller->prepare_message = spi_imx_prepare_message;
spi_imx->controller->unprepare_message = spi_imx_unprepare_message; controller->unprepare_message = spi_imx_unprepare_message;
spi_imx->controller->slave_abort = spi_imx_slave_abort; controller->slave_abort = spi_imx_slave_abort;
spi_imx->controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS; controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS |
SPI_MOSI_IDLE_LOW;
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) || if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
is_imx53_ecspi(spi_imx)) is_imx53_ecspi(spi_imx))
spi_imx->controller->mode_bits |= SPI_LOOP | SPI_READY; controller->mode_bits |= SPI_LOOP | SPI_READY;
if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx))
spi_imx->controller->mode_bits |= SPI_RX_CPHA_FLIP; controller->mode_bits |= SPI_RX_CPHA_FLIP;
if (is_imx51_ecspi(spi_imx) && if (is_imx51_ecspi(spi_imx) &&
device_property_read_u32(&pdev->dev, "cs-gpios", NULL)) device_property_read_u32(&pdev->dev, "cs-gpios", NULL))
...@@ -1759,7 +1775,12 @@ static int spi_imx_probe(struct platform_device *pdev) ...@@ -1759,7 +1775,12 @@ static int spi_imx_probe(struct platform_device *pdev)
* setting the burst length to the word size. This is * setting the burst length to the word size. This is
* considerably faster than manually controlling the CS. * considerably faster than manually controlling the CS.
*/ */
spi_imx->controller->mode_bits |= SPI_CS_WORD; controller->mode_bits |= SPI_CS_WORD;
if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) {
controller->max_native_cs = 4;
controller->flags |= SPI_MASTER_GPIO_SS;
}
spi_imx->spi_drctl = spi_drctl; spi_imx->spi_drctl = spi_drctl;
......
...@@ -1144,7 +1144,8 @@ static int mtk_spi_probe(struct platform_device *pdev) ...@@ -1144,7 +1144,8 @@ static int mtk_spi_probe(struct platform_device *pdev)
if (mdata->dev_comp->must_tx) if (mdata->dev_comp->must_tx)
master->flags = SPI_MASTER_MUST_TX; master->flags = SPI_MASTER_MUST_TX;
if (mdata->dev_comp->ipm_design) if (mdata->dev_comp->ipm_design)
master->mode_bits |= SPI_LOOP; master->mode_bits |= SPI_LOOP | SPI_RX_DUAL | SPI_TX_DUAL |
SPI_RX_QUAD | SPI_TX_QUAD;
if (mdata->dev_comp->ipm_design) { if (mdata->dev_comp->ipm_design) {
mdata->dev = dev; mdata->dev = dev;
...@@ -1269,7 +1270,7 @@ static int mtk_spi_probe(struct platform_device *pdev) ...@@ -1269,7 +1270,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int mtk_spi_remove(struct platform_device *pdev) static void mtk_spi_remove(struct platform_device *pdev)
{ {
struct spi_master *master = platform_get_drvdata(pdev); struct spi_master *master = platform_get_drvdata(pdev);
struct mtk_spi *mdata = spi_master_get_devdata(master); struct mtk_spi *mdata = spi_master_get_devdata(master);
...@@ -1278,21 +1279,25 @@ static int mtk_spi_remove(struct platform_device *pdev) ...@@ -1278,21 +1279,25 @@ static int mtk_spi_remove(struct platform_device *pdev)
if (mdata->use_spimem && !completion_done(&mdata->spimem_done)) if (mdata->use_spimem && !completion_done(&mdata->spimem_done))
complete(&mdata->spimem_done); complete(&mdata->spimem_done);
ret = pm_runtime_resume_and_get(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) if (ret < 0) {
return ret; dev_warn(&pdev->dev, "Failed to resume hardware (%pe)\n", ERR_PTR(ret));
} else {
mtk_spi_reset(mdata); /*
* If pm runtime resume failed, clks are disabled and
* unprepared. So don't access the hardware and skip clk
* unpreparing.
*/
mtk_spi_reset(mdata);
if (mdata->dev_comp->no_need_unprepare) { if (mdata->dev_comp->no_need_unprepare) {
clk_unprepare(mdata->spi_clk); clk_unprepare(mdata->spi_clk);
clk_unprepare(mdata->spi_hclk); clk_unprepare(mdata->spi_hclk);
}
} }
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -1311,7 +1316,7 @@ static int mtk_spi_suspend(struct device *dev) ...@@ -1311,7 +1316,7 @@ static int mtk_spi_suspend(struct device *dev)
clk_disable_unprepare(mdata->spi_hclk); clk_disable_unprepare(mdata->spi_hclk);
} }
return ret; return 0;
} }
static int mtk_spi_resume(struct device *dev) static int mtk_spi_resume(struct device *dev)
...@@ -1412,7 +1417,7 @@ static struct platform_driver mtk_spi_driver = { ...@@ -1412,7 +1417,7 @@ static struct platform_driver mtk_spi_driver = {
.of_match_table = mtk_spi_of_match, .of_match_table = mtk_spi_of_match,
}, },
.probe = mtk_spi_probe, .probe = mtk_spi_probe,
.remove = mtk_spi_remove, .remove_new = mtk_spi_remove,
}; };
module_platform_driver(mtk_spi_driver); module_platform_driver(mtk_spi_driver);
......
...@@ -2217,8 +2217,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2217,8 +2217,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
amba_set_drvdata(adev, pl022); amba_set_drvdata(adev, pl022);
status = devm_spi_register_master(&adev->dev, master); status = devm_spi_register_master(&adev->dev, master);
if (status != 0) { if (status != 0) {
dev_err(&adev->dev, dev_err_probe(&adev->dev, status,
"probe - problem registering spi master\n"); "problem registering spi master\n");
goto err_spi_register; goto err_spi_register;
} }
dev_dbg(dev, "probe succeeded\n"); dev_dbg(dev, "probe succeeded\n");
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. // Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/interconnect.h> #include <linux/interconnect.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -62,6 +64,7 @@ ...@@ -62,6 +64,7 @@
#define WR_FIFO_FULL BIT(10) #define WR_FIFO_FULL BIT(10)
#define WR_FIFO_OVERRUN BIT(11) #define WR_FIFO_OVERRUN BIT(11)
#define TRANSACTION_DONE BIT(16) #define TRANSACTION_DONE BIT(16)
#define DMA_CHAIN_DONE BIT(31)
#define QSPI_ERR_IRQS (RESP_FIFO_UNDERRUN | HRESP_FROM_NOC_ERR | \ #define QSPI_ERR_IRQS (RESP_FIFO_UNDERRUN | HRESP_FROM_NOC_ERR | \
WR_FIFO_OVERRUN) WR_FIFO_OVERRUN)
#define QSPI_ALL_IRQS (QSPI_ERR_IRQS | RESP_FIFO_RDY | \ #define QSPI_ALL_IRQS (QSPI_ERR_IRQS | RESP_FIFO_RDY | \
...@@ -108,18 +111,34 @@ ...@@ -108,18 +111,34 @@
#define RD_FIFO_RESET 0x0030 #define RD_FIFO_RESET 0x0030
#define RESET_FIFO BIT(0) #define RESET_FIFO BIT(0)
#define NEXT_DMA_DESC_ADDR 0x0040
#define CURRENT_DMA_DESC_ADDR 0x0044
#define CURRENT_MEM_ADDR 0x0048
#define CUR_MEM_ADDR 0x0048 #define CUR_MEM_ADDR 0x0048
#define HW_VERSION 0x004c #define HW_VERSION 0x004c
#define RD_FIFO 0x0050 #define RD_FIFO 0x0050
#define SAMPLING_CLK_CFG 0x0090 #define SAMPLING_CLK_CFG 0x0090
#define SAMPLING_CLK_STATUS 0x0094 #define SAMPLING_CLK_STATUS 0x0094
#define QSPI_ALIGN_REQ 32
enum qspi_dir { enum qspi_dir {
QSPI_READ, QSPI_READ,
QSPI_WRITE, QSPI_WRITE,
}; };
struct qspi_cmd_desc {
u32 data_address;
u32 next_descriptor;
u32 direction:1;
u32 multi_io_mode:3;
u32 reserved1:4;
u32 fragment:1;
u32 reserved2:7;
u32 length:16;
};
struct qspi_xfer { struct qspi_xfer {
union { union {
const void *tx_buf; const void *tx_buf;
...@@ -137,11 +156,23 @@ enum qspi_clocks { ...@@ -137,11 +156,23 @@ enum qspi_clocks {
QSPI_NUM_CLKS QSPI_NUM_CLKS
}; };
/*
* Number of entries in sgt returned from spi framework that-
* will be supported. Can be modified as required.
* In practice, given max_dma_len is 64KB, the number of
* entries is not expected to exceed 1.
*/
#define QSPI_MAX_SG 5
struct qcom_qspi { struct qcom_qspi {
void __iomem *base; void __iomem *base;
struct device *dev; struct device *dev;
struct clk_bulk_data *clks; struct clk_bulk_data *clks;
struct qspi_xfer xfer; struct qspi_xfer xfer;
struct dma_pool *dma_cmd_pool;
dma_addr_t dma_cmd_desc[QSPI_MAX_SG];
void *virt_cmd_desc[QSPI_MAX_SG];
unsigned int n_cmd_desc;
struct icc_path *icc_path_cpu_to_qspi; struct icc_path *icc_path_cpu_to_qspi;
unsigned long last_speed; unsigned long last_speed;
/* Lock to protect data accessed by IRQs */ /* Lock to protect data accessed by IRQs */
...@@ -153,21 +184,22 @@ static u32 qspi_buswidth_to_iomode(struct qcom_qspi *ctrl, ...@@ -153,21 +184,22 @@ static u32 qspi_buswidth_to_iomode(struct qcom_qspi *ctrl,
{ {
switch (buswidth) { switch (buswidth) {
case 1: case 1:
return SDR_1BIT << MULTI_IO_MODE_SHFT; return SDR_1BIT;
case 2: case 2:
return SDR_2BIT << MULTI_IO_MODE_SHFT; return SDR_2BIT;
case 4: case 4:
return SDR_4BIT << MULTI_IO_MODE_SHFT; return SDR_4BIT;
default: default:
dev_warn_once(ctrl->dev, dev_warn_once(ctrl->dev,
"Unexpected bus width: %u\n", buswidth); "Unexpected bus width: %u\n", buswidth);
return SDR_1BIT << MULTI_IO_MODE_SHFT; return SDR_1BIT;
} }
} }
static void qcom_qspi_pio_xfer_cfg(struct qcom_qspi *ctrl) static void qcom_qspi_pio_xfer_cfg(struct qcom_qspi *ctrl)
{ {
u32 pio_xfer_cfg; u32 pio_xfer_cfg;
u32 iomode;
const struct qspi_xfer *xfer; const struct qspi_xfer *xfer;
xfer = &ctrl->xfer; xfer = &ctrl->xfer;
...@@ -179,7 +211,8 @@ static void qcom_qspi_pio_xfer_cfg(struct qcom_qspi *ctrl) ...@@ -179,7 +211,8 @@ static void qcom_qspi_pio_xfer_cfg(struct qcom_qspi *ctrl)
else else
pio_xfer_cfg |= TRANSFER_FRAGMENT; pio_xfer_cfg |= TRANSFER_FRAGMENT;
pio_xfer_cfg &= ~MULTI_IO_MODE_MSK; pio_xfer_cfg &= ~MULTI_IO_MODE_MSK;
pio_xfer_cfg |= qspi_buswidth_to_iomode(ctrl, xfer->buswidth); iomode = qspi_buswidth_to_iomode(ctrl, xfer->buswidth);
pio_xfer_cfg |= iomode << MULTI_IO_MODE_SHFT;
writel(pio_xfer_cfg, ctrl->base + PIO_XFER_CFG); writel(pio_xfer_cfg, ctrl->base + PIO_XFER_CFG);
} }
...@@ -217,12 +250,22 @@ static void qcom_qspi_pio_xfer(struct qcom_qspi *ctrl) ...@@ -217,12 +250,22 @@ static void qcom_qspi_pio_xfer(struct qcom_qspi *ctrl)
static void qcom_qspi_handle_err(struct spi_master *master, static void qcom_qspi_handle_err(struct spi_master *master,
struct spi_message *msg) struct spi_message *msg)
{ {
u32 int_status;
struct qcom_qspi *ctrl = spi_master_get_devdata(master); struct qcom_qspi *ctrl = spi_master_get_devdata(master);
unsigned long flags; unsigned long flags;
int i;
spin_lock_irqsave(&ctrl->lock, flags); spin_lock_irqsave(&ctrl->lock, flags);
writel(0, ctrl->base + MSTR_INT_EN); writel(0, ctrl->base + MSTR_INT_EN);
int_status = readl(ctrl->base + MSTR_INT_STATUS);
writel(int_status, ctrl->base + MSTR_INT_STATUS);
ctrl->xfer.rem_bytes = 0; ctrl->xfer.rem_bytes = 0;
/* free cmd descriptors if they are around (DMA mode) */
for (i = 0; i < ctrl->n_cmd_desc; i++)
dma_pool_free(ctrl->dma_cmd_pool, ctrl->virt_cmd_desc[i],
ctrl->dma_cmd_desc[i]);
ctrl->n_cmd_desc = 0;
spin_unlock_irqrestore(&ctrl->lock, flags); spin_unlock_irqrestore(&ctrl->lock, flags);
} }
...@@ -242,7 +285,7 @@ static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz) ...@@ -242,7 +285,7 @@ static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz)
} }
/* /*
* Set BW quota for CPU as driver supports FIFO mode only. * Set BW quota for CPU.
* We don't have explicit peak requirement so keep it equal to avg_bw. * We don't have explicit peak requirement so keep it equal to avg_bw.
*/ */
avg_bw_cpu = Bps_to_icc(speed_hz); avg_bw_cpu = Bps_to_icc(speed_hz);
...@@ -258,6 +301,102 @@ static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz) ...@@ -258,6 +301,102 @@ static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz)
return 0; return 0;
} }
static int qcom_qspi_alloc_desc(struct qcom_qspi *ctrl, dma_addr_t dma_ptr,
uint32_t n_bytes)
{
struct qspi_cmd_desc *virt_cmd_desc, *prev;
dma_addr_t dma_cmd_desc;
/* allocate for dma cmd descriptor */
virt_cmd_desc = dma_pool_alloc(ctrl->dma_cmd_pool, GFP_KERNEL | __GFP_ZERO, &dma_cmd_desc);
if (!virt_cmd_desc)
return -ENOMEM;
ctrl->virt_cmd_desc[ctrl->n_cmd_desc] = virt_cmd_desc;
ctrl->dma_cmd_desc[ctrl->n_cmd_desc] = dma_cmd_desc;
ctrl->n_cmd_desc++;
/* setup cmd descriptor */
virt_cmd_desc->data_address = dma_ptr;
virt_cmd_desc->direction = ctrl->xfer.dir;
virt_cmd_desc->multi_io_mode = qspi_buswidth_to_iomode(ctrl, ctrl->xfer.buswidth);
virt_cmd_desc->fragment = !ctrl->xfer.is_last;
virt_cmd_desc->length = n_bytes;
/* update previous descriptor */
if (ctrl->n_cmd_desc >= 2) {
prev = (ctrl->virt_cmd_desc)[ctrl->n_cmd_desc - 2];
prev->next_descriptor = dma_cmd_desc;
prev->fragment = 1;
}
return 0;
}
static int qcom_qspi_setup_dma_desc(struct qcom_qspi *ctrl,
struct spi_transfer *xfer)
{
int ret;
struct sg_table *sgt;
dma_addr_t dma_ptr_sg;
unsigned int dma_len_sg;
int i;
if (ctrl->n_cmd_desc) {
dev_err(ctrl->dev, "Remnant dma buffers n_cmd_desc-%d\n", ctrl->n_cmd_desc);
return -EIO;
}
sgt = (ctrl->xfer.dir == QSPI_READ) ? &xfer->rx_sg : &xfer->tx_sg;
if (!sgt->nents || sgt->nents > QSPI_MAX_SG) {
dev_warn_once(ctrl->dev, "Cannot handle %d entries in scatter list\n", sgt->nents);
return -EAGAIN;
}
for (i = 0; i < sgt->nents; i++) {
dma_ptr_sg = sg_dma_address(sgt->sgl + i);
if (!IS_ALIGNED(dma_ptr_sg, QSPI_ALIGN_REQ)) {
dev_warn_once(ctrl->dev, "dma_address not aligned to %d\n", QSPI_ALIGN_REQ);
return -EAGAIN;
}
}
for (i = 0; i < sgt->nents; i++) {
dma_ptr_sg = sg_dma_address(sgt->sgl + i);
dma_len_sg = sg_dma_len(sgt->sgl + i);
ret = qcom_qspi_alloc_desc(ctrl, dma_ptr_sg, dma_len_sg);
if (ret)
goto cleanup;
}
return 0;
cleanup:
for (i = 0; i < ctrl->n_cmd_desc; i++)
dma_pool_free(ctrl->dma_cmd_pool, ctrl->virt_cmd_desc[i],
ctrl->dma_cmd_desc[i]);
ctrl->n_cmd_desc = 0;
return ret;
}
static void qcom_qspi_dma_xfer(struct qcom_qspi *ctrl)
{
/* Setup new interrupts */
writel(DMA_CHAIN_DONE, ctrl->base + MSTR_INT_EN);
/* kick off transfer */
writel((u32)((ctrl->dma_cmd_desc)[0]), ctrl->base + NEXT_DMA_DESC_ADDR);
}
/* Switch to DMA if transfer length exceeds this */
#define QSPI_MAX_BYTES_FIFO 64
static bool qcom_qspi_can_dma(struct spi_controller *ctlr,
struct spi_device *slv, struct spi_transfer *xfer)
{
return xfer->len > QSPI_MAX_BYTES_FIFO;
}
static int qcom_qspi_transfer_one(struct spi_master *master, static int qcom_qspi_transfer_one(struct spi_master *master,
struct spi_device *slv, struct spi_device *slv,
struct spi_transfer *xfer) struct spi_transfer *xfer)
...@@ -266,6 +405,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master, ...@@ -266,6 +405,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
int ret; int ret;
unsigned long speed_hz; unsigned long speed_hz;
unsigned long flags; unsigned long flags;
u32 mstr_cfg;
speed_hz = slv->max_speed_hz; speed_hz = slv->max_speed_hz;
if (xfer->speed_hz) if (xfer->speed_hz)
...@@ -276,6 +416,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master, ...@@ -276,6 +416,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
return ret; return ret;
spin_lock_irqsave(&ctrl->lock, flags); spin_lock_irqsave(&ctrl->lock, flags);
mstr_cfg = readl(ctrl->base + MSTR_CONFIG);
/* We are half duplex, so either rx or tx will be set */ /* We are half duplex, so either rx or tx will be set */
if (xfer->rx_buf) { if (xfer->rx_buf) {
...@@ -290,10 +431,36 @@ static int qcom_qspi_transfer_one(struct spi_master *master, ...@@ -290,10 +431,36 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
ctrl->xfer.is_last = list_is_last(&xfer->transfer_list, ctrl->xfer.is_last = list_is_last(&xfer->transfer_list,
&master->cur_msg->transfers); &master->cur_msg->transfers);
ctrl->xfer.rem_bytes = xfer->len; ctrl->xfer.rem_bytes = xfer->len;
if (xfer->rx_sg.nents || xfer->tx_sg.nents) {
/* do DMA transfer */
if (!(mstr_cfg & DMA_ENABLE)) {
mstr_cfg |= DMA_ENABLE;
writel(mstr_cfg, ctrl->base + MSTR_CONFIG);
}
ret = qcom_qspi_setup_dma_desc(ctrl, xfer);
if (ret != -EAGAIN) {
if (!ret)
qcom_qspi_dma_xfer(ctrl);
goto exit;
}
dev_warn_once(ctrl->dev, "DMA failure, falling back to PIO\n");
ret = 0; /* We'll retry w/ PIO */
}
if (mstr_cfg & DMA_ENABLE) {
mstr_cfg &= ~DMA_ENABLE;
writel(mstr_cfg, ctrl->base + MSTR_CONFIG);
}
qcom_qspi_pio_xfer(ctrl); qcom_qspi_pio_xfer(ctrl);
exit:
spin_unlock_irqrestore(&ctrl->lock, flags); spin_unlock_irqrestore(&ctrl->lock, flags);
if (ret)
return ret;
/* We'll call spi_finalize_current_transfer() when done */ /* We'll call spi_finalize_current_transfer() when done */
return 1; return 1;
} }
...@@ -328,6 +495,16 @@ static int qcom_qspi_prepare_message(struct spi_master *master, ...@@ -328,6 +495,16 @@ static int qcom_qspi_prepare_message(struct spi_master *master,
return 0; return 0;
} }
static int qcom_qspi_alloc_dma(struct qcom_qspi *ctrl)
{
ctrl->dma_cmd_pool = dmam_pool_create("qspi cmd desc pool",
ctrl->dev, sizeof(struct qspi_cmd_desc), 0, 0);
if (!ctrl->dma_cmd_pool)
return -ENOMEM;
return 0;
}
static irqreturn_t pio_read(struct qcom_qspi *ctrl) static irqreturn_t pio_read(struct qcom_qspi *ctrl)
{ {
u32 rd_fifo_status; u32 rd_fifo_status;
...@@ -426,6 +603,7 @@ static irqreturn_t qcom_qspi_irq(int irq, void *dev_id) ...@@ -426,6 +603,7 @@ static irqreturn_t qcom_qspi_irq(int irq, void *dev_id)
int_status = readl(ctrl->base + MSTR_INT_STATUS); int_status = readl(ctrl->base + MSTR_INT_STATUS);
writel(int_status, ctrl->base + MSTR_INT_STATUS); writel(int_status, ctrl->base + MSTR_INT_STATUS);
/* PIO mode handling */
if (ctrl->xfer.dir == QSPI_WRITE) { if (ctrl->xfer.dir == QSPI_WRITE) {
if (int_status & WR_FIFO_EMPTY) if (int_status & WR_FIFO_EMPTY)
ret = pio_write(ctrl); ret = pio_write(ctrl);
...@@ -449,6 +627,22 @@ static irqreturn_t qcom_qspi_irq(int irq, void *dev_id) ...@@ -449,6 +627,22 @@ static irqreturn_t qcom_qspi_irq(int irq, void *dev_id)
spi_finalize_current_transfer(dev_get_drvdata(ctrl->dev)); spi_finalize_current_transfer(dev_get_drvdata(ctrl->dev));
} }
/* DMA mode handling */
if (int_status & DMA_CHAIN_DONE) {
int i;
writel(0, ctrl->base + MSTR_INT_EN);
ctrl->xfer.rem_bytes = 0;
for (i = 0; i < ctrl->n_cmd_desc; i++)
dma_pool_free(ctrl->dma_cmd_pool, ctrl->virt_cmd_desc[i],
ctrl->dma_cmd_desc[i]);
ctrl->n_cmd_desc = 0;
ret = IRQ_HANDLED;
spi_finalize_current_transfer(dev_get_drvdata(ctrl->dev));
}
spin_unlock(&ctrl->lock); spin_unlock(&ctrl->lock);
return ret; return ret;
} }
...@@ -517,7 +711,13 @@ static int qcom_qspi_probe(struct platform_device *pdev) ...@@ -517,7 +711,13 @@ static int qcom_qspi_probe(struct platform_device *pdev)
return ret; return ret;
} }
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret)
return dev_err_probe(dev, ret, "could not set DMA mask\n");
master->max_speed_hz = 300000000; master->max_speed_hz = 300000000;
master->max_dma_len = 65536; /* as per HPG */
master->dma_alignment = QSPI_ALIGN_REQ;
master->num_chipselect = QSPI_NUM_CS; master->num_chipselect = QSPI_NUM_CS;
master->bus_num = -1; master->bus_num = -1;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
...@@ -528,6 +728,8 @@ static int qcom_qspi_probe(struct platform_device *pdev) ...@@ -528,6 +728,8 @@ static int qcom_qspi_probe(struct platform_device *pdev)
master->prepare_message = qcom_qspi_prepare_message; master->prepare_message = qcom_qspi_prepare_message;
master->transfer_one = qcom_qspi_transfer_one; master->transfer_one = qcom_qspi_transfer_one;
master->handle_err = qcom_qspi_handle_err; master->handle_err = qcom_qspi_handle_err;
if (of_property_read_bool(pdev->dev.of_node, "iommus"))
master->can_dma = qcom_qspi_can_dma;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
ret = devm_pm_opp_set_clkname(&pdev->dev, "core"); ret = devm_pm_opp_set_clkname(&pdev->dev, "core");
...@@ -540,6 +742,10 @@ static int qcom_qspi_probe(struct platform_device *pdev) ...@@ -540,6 +742,10 @@ static int qcom_qspi_probe(struct platform_device *pdev)
return ret; return ret;
} }
ret = qcom_qspi_alloc_dma(ctrl);
if (ret)
return ret;
pm_runtime_use_autosuspend(dev); pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, 250); pm_runtime_set_autosuspend_delay(dev, 250);
pm_runtime_enable(dev); pm_runtime_enable(dev);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Renesas RZ/V2M Clocked Serial Interface (CSI) driver
*
* Copyright (C) 2023 Renesas Electronics Corporation
*/
#include <linux/clk.h>
#include <linux/count_zeros.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
/* Registers */
#define CSI_MODE 0x00 /* CSI mode control */
#define CSI_CLKSEL 0x04 /* CSI clock select */
#define CSI_CNT 0x08 /* CSI control */
#define CSI_INT 0x0C /* CSI interrupt status */
#define CSI_IFIFOL 0x10 /* CSI receive FIFO level display */
#define CSI_OFIFOL 0x14 /* CSI transmit FIFO level display */
#define CSI_IFIFO 0x18 /* CSI receive window */
#define CSI_OFIFO 0x1C /* CSI transmit window */
#define CSI_FIFOTRG 0x20 /* CSI FIFO trigger level */
/* CSI_MODE */
#define CSI_MODE_CSIE BIT(7)
#define CSI_MODE_TRMD BIT(6)
#define CSI_MODE_CCL BIT(5)
#define CSI_MODE_DIR BIT(4)
#define CSI_MODE_CSOT BIT(0)
#define CSI_MODE_SETUP 0x00000040
/* CSI_CLKSEL */
#define CSI_CLKSEL_CKP BIT(17)
#define CSI_CLKSEL_DAP BIT(16)
#define CSI_CLKSEL_SLAVE BIT(15)
#define CSI_CLKSEL_CKS GENMASK(14, 1)
/* CSI_CNT */
#define CSI_CNT_CSIRST BIT(28)
#define CSI_CNT_R_TRGEN BIT(19)
#define CSI_CNT_UNDER_E BIT(13)
#define CSI_CNT_OVERF_E BIT(12)
#define CSI_CNT_TREND_E BIT(9)
#define CSI_CNT_CSIEND_E BIT(8)
#define CSI_CNT_T_TRGR_E BIT(4)
#define CSI_CNT_R_TRGR_E BIT(0)
/* CSI_INT */
#define CSI_INT_UNDER BIT(13)
#define CSI_INT_OVERF BIT(12)
#define CSI_INT_TREND BIT(9)
#define CSI_INT_CSIEND BIT(8)
#define CSI_INT_T_TRGR BIT(4)
#define CSI_INT_R_TRGR BIT(0)
/* CSI_FIFOTRG */
#define CSI_FIFOTRG_R_TRG GENMASK(2, 0)
#define CSI_FIFO_SIZE_BYTES 32
#define CSI_FIFO_HALF_SIZE 16
#define CSI_EN_DIS_TIMEOUT_US 100
#define CSI_CKS_MAX 0x3FFF
#define UNDERRUN_ERROR BIT(0)
#define OVERFLOW_ERROR BIT(1)
#define TX_TIMEOUT_ERROR BIT(2)
#define RX_TIMEOUT_ERROR BIT(3)
#define CSI_MAX_SPI_SCKO 8000000
struct rzv2m_csi_priv {
void __iomem *base;
struct clk *csiclk;
struct clk *pclk;
struct device *dev;
struct spi_controller *controller;
const u8 *txbuf;
u8 *rxbuf;
int buffer_len;
int bytes_sent;
int bytes_received;
int bytes_to_transfer;
int words_to_transfer;
unsigned char bytes_per_word;
wait_queue_head_t wait;
u8 errors;
u32 status;
};
static const unsigned char x_trg[] = {
0, 1, 1, 2, 2, 2, 2, 3,
3, 3, 3, 3, 3, 3, 3, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 5
};
static const unsigned char x_trg_words[] = {
1, 2, 2, 4, 4, 4, 4, 8,
8, 8, 8, 8, 8, 8, 8, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 32
};
static void rzv2m_csi_reg_write_bit(const struct rzv2m_csi_priv *csi,
int reg_offs, int bit_mask, u32 value)
{
int nr_zeros;
u32 tmp;
nr_zeros = count_trailing_zeros(bit_mask);
value <<= nr_zeros;
tmp = (readl(csi->base + reg_offs) & ~bit_mask) | value;
writel(tmp, csi->base + reg_offs);
}
static int rzv2m_csi_sw_reset(struct rzv2m_csi_priv *csi, int assert)
{
u32 reg;
rzv2m_csi_reg_write_bit(csi, CSI_CNT, CSI_CNT_CSIRST, assert);
if (assert) {
return readl_poll_timeout(csi->base + CSI_MODE, reg,
!(reg & CSI_MODE_CSOT), 0,
CSI_EN_DIS_TIMEOUT_US);
}
return 0;
}
static int rzv2m_csi_start_stop_operation(const struct rzv2m_csi_priv *csi,
int enable, bool wait)
{
u32 reg;
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_CSIE, enable);
if (!enable && wait)
return readl_poll_timeout(csi->base + CSI_MODE, reg,
!(reg & CSI_MODE_CSOT), 0,
CSI_EN_DIS_TIMEOUT_US);
return 0;
}
static int rzv2m_csi_fill_txfifo(struct rzv2m_csi_priv *csi)
{
int i;
if (readl(csi->base + CSI_OFIFOL))
return -EIO;
if (csi->bytes_per_word == 2) {
u16 *buf = (u16 *)csi->txbuf;
for (i = 0; i < csi->words_to_transfer; i++)
writel(buf[i], csi->base + CSI_OFIFO);
} else {
u8 *buf = (u8 *)csi->txbuf;
for (i = 0; i < csi->words_to_transfer; i++)
writel(buf[i], csi->base + CSI_OFIFO);
}
csi->txbuf += csi->bytes_to_transfer;
csi->bytes_sent += csi->bytes_to_transfer;
return 0;
}
static int rzv2m_csi_read_rxfifo(struct rzv2m_csi_priv *csi)
{
int i;
if (readl(csi->base + CSI_IFIFOL) != csi->bytes_to_transfer)
return -EIO;
if (csi->bytes_per_word == 2) {
u16 *buf = (u16 *)csi->rxbuf;
for (i = 0; i < csi->words_to_transfer; i++)
buf[i] = (u16)readl(csi->base + CSI_IFIFO);
} else {
u8 *buf = (u8 *)csi->rxbuf;
for (i = 0; i < csi->words_to_transfer; i++)
buf[i] = (u8)readl(csi->base + CSI_IFIFO);
}
csi->rxbuf += csi->bytes_to_transfer;
csi->bytes_received += csi->bytes_to_transfer;
return 0;
}
static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
{
int bytes_transferred = max_t(int, csi->bytes_received, csi->bytes_sent);
int bytes_remaining = csi->buffer_len - bytes_transferred;
int to_transfer;
if (csi->txbuf)
/*
* Leaving a little bit of headroom in the FIFOs makes it very
* hard to raise an overflow error (which is only possible
* when IP transmits and receives at the same time).
*/
to_transfer = min_t(int, CSI_FIFO_HALF_SIZE, bytes_remaining);
else
to_transfer = min_t(int, CSI_FIFO_SIZE_BYTES, bytes_remaining);
if (csi->bytes_per_word == 2)
to_transfer >>= 1;
/*
* We can only choose a trigger level from a predefined set of values.
* This will pick a value that is the greatest possible integer that's
* less than or equal to the number of bytes we need to transfer.
* This may result in multiple smaller transfers.
*/
csi->words_to_transfer = x_trg_words[to_transfer - 1];
if (csi->bytes_per_word == 2)
csi->bytes_to_transfer = csi->words_to_transfer << 1;
else
csi->bytes_to_transfer = csi->words_to_transfer;
}
static inline void rzv2m_csi_set_rx_fifo_trigger_level(struct rzv2m_csi_priv *csi)
{
rzv2m_csi_reg_write_bit(csi, CSI_FIFOTRG, CSI_FIFOTRG_R_TRG,
x_trg[csi->words_to_transfer - 1]);
}
static inline void rzv2m_csi_enable_rx_trigger(struct rzv2m_csi_priv *csi,
bool enable)
{
rzv2m_csi_reg_write_bit(csi, CSI_CNT, CSI_CNT_R_TRGEN, enable);
}
static void rzv2m_csi_disable_irqs(const struct rzv2m_csi_priv *csi,
u32 enable_bits)
{
u32 cnt = readl(csi->base + CSI_CNT);
writel(cnt & ~enable_bits, csi->base + CSI_CNT);
}
static void rzv2m_csi_disable_all_irqs(struct rzv2m_csi_priv *csi)
{
rzv2m_csi_disable_irqs(csi, CSI_CNT_R_TRGR_E | CSI_CNT_T_TRGR_E |
CSI_CNT_CSIEND_E | CSI_CNT_TREND_E |
CSI_CNT_OVERF_E | CSI_CNT_UNDER_E);
}
static inline void rzv2m_csi_clear_irqs(struct rzv2m_csi_priv *csi, u32 irqs)
{
writel(irqs, csi->base + CSI_INT);
}
static void rzv2m_csi_clear_all_irqs(struct rzv2m_csi_priv *csi)
{
rzv2m_csi_clear_irqs(csi, CSI_INT_UNDER | CSI_INT_OVERF |
CSI_INT_TREND | CSI_INT_CSIEND | CSI_INT_T_TRGR |
CSI_INT_R_TRGR);
}
static void rzv2m_csi_enable_irqs(struct rzv2m_csi_priv *csi, u32 enable_bits)
{
u32 cnt = readl(csi->base + CSI_CNT);
writel(cnt | enable_bits, csi->base + CSI_CNT);
}
static int rzv2m_csi_wait_for_interrupt(struct rzv2m_csi_priv *csi,
u32 wait_mask, u32 enable_bits)
{
int ret;
rzv2m_csi_enable_irqs(csi, enable_bits);
ret = wait_event_timeout(csi->wait,
((csi->status & wait_mask) == wait_mask) ||
csi->errors, HZ);
rzv2m_csi_disable_irqs(csi, enable_bits);
if (csi->errors)
return -EIO;
if (!ret)
return -ETIMEDOUT;
return 0;
}
static int rzv2m_csi_wait_for_tx_empty(struct rzv2m_csi_priv *csi)
{
int ret;
if (readl(csi->base + CSI_OFIFOL) == 0)
return 0;
ret = rzv2m_csi_wait_for_interrupt(csi, CSI_INT_TREND, CSI_CNT_TREND_E);
if (ret == -ETIMEDOUT)
csi->errors |= TX_TIMEOUT_ERROR;
return ret;
}
static inline int rzv2m_csi_wait_for_rx_ready(struct rzv2m_csi_priv *csi)
{
int ret;
if (readl(csi->base + CSI_IFIFOL) == csi->bytes_to_transfer)
return 0;
ret = rzv2m_csi_wait_for_interrupt(csi, CSI_INT_R_TRGR,
CSI_CNT_R_TRGR_E);
if (ret == -ETIMEDOUT)
csi->errors |= RX_TIMEOUT_ERROR;
return ret;
}
static irqreturn_t rzv2m_csi_irq_handler(int irq, void *data)
{
struct rzv2m_csi_priv *csi = (struct rzv2m_csi_priv *)data;
csi->status = readl(csi->base + CSI_INT);
rzv2m_csi_disable_irqs(csi, csi->status);
if (csi->status & CSI_INT_OVERF)
csi->errors |= OVERFLOW_ERROR;
if (csi->status & CSI_INT_UNDER)
csi->errors |= UNDERRUN_ERROR;
wake_up(&csi->wait);
return IRQ_HANDLED;
}
static void rzv2m_csi_setup_clock(struct rzv2m_csi_priv *csi, u32 spi_hz)
{
unsigned long csiclk_rate = clk_get_rate(csi->csiclk);
unsigned long pclk_rate = clk_get_rate(csi->pclk);
unsigned long csiclk_rate_limit = pclk_rate >> 1;
u32 cks;
/*
* There is a restriction on the frequency of CSICLK, it has to be <=
* PCLK / 2.
*/
if (csiclk_rate > csiclk_rate_limit) {
clk_set_rate(csi->csiclk, csiclk_rate >> 1);
csiclk_rate = clk_get_rate(csi->csiclk);
} else if ((csiclk_rate << 1) <= csiclk_rate_limit) {
clk_set_rate(csi->csiclk, csiclk_rate << 1);
csiclk_rate = clk_get_rate(csi->csiclk);
}
spi_hz = spi_hz > CSI_MAX_SPI_SCKO ? CSI_MAX_SPI_SCKO : spi_hz;
cks = DIV_ROUND_UP(csiclk_rate, spi_hz << 1);
if (cks > CSI_CKS_MAX)
cks = CSI_CKS_MAX;
dev_dbg(csi->dev, "SPI clk rate is %ldHz\n", csiclk_rate / (cks << 1));
rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_CKS, cks);
}
static void rzv2m_csi_setup_operating_mode(struct rzv2m_csi_priv *csi,
struct spi_transfer *t)
{
if (t->rx_buf && !t->tx_buf)
/* Reception-only mode */
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_TRMD, 0);
else
/* Send and receive mode */
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_TRMD, 1);
csi->bytes_per_word = t->bits_per_word / 8;
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_CCL,
csi->bytes_per_word == 2);
}
static int rzv2m_csi_setup(struct spi_device *spi)
{
struct rzv2m_csi_priv *csi = spi_controller_get_devdata(spi->controller);
int ret;
rzv2m_csi_sw_reset(csi, 0);
writel(CSI_MODE_SETUP, csi->base + CSI_MODE);
/* Setup clock polarity and phase timing */
rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_CKP,
!(spi->mode & SPI_CPOL));
rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_DAP,
!(spi->mode & SPI_CPHA));
/* Setup serial data order */
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_DIR,
!!(spi->mode & SPI_LSB_FIRST));
/* Set the operation mode as master */
rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_SLAVE, 0);
/* Give the IP a SW reset */
ret = rzv2m_csi_sw_reset(csi, 1);
if (ret)
return ret;
rzv2m_csi_sw_reset(csi, 0);
/*
* We need to enable the communication so that the clock will settle
* for the right polarity before enabling the CS.
*/
rzv2m_csi_start_stop_operation(csi, 1, false);
udelay(10);
rzv2m_csi_start_stop_operation(csi, 0, false);
return 0;
}
static int rzv2m_csi_pio_transfer(struct rzv2m_csi_priv *csi)
{
bool tx_completed = csi->txbuf ? false : true;
bool rx_completed = csi->rxbuf ? false : true;
int ret = 0;
/* Make sure the TX FIFO is empty */
writel(0, csi->base + CSI_OFIFOL);
csi->bytes_sent = 0;
csi->bytes_received = 0;
csi->errors = 0;
rzv2m_csi_disable_all_irqs(csi);
rzv2m_csi_clear_all_irqs(csi);
rzv2m_csi_enable_rx_trigger(csi, true);
while (!tx_completed || !rx_completed) {
/*
* Decide how many words we are going to transfer during
* this cycle (for both TX and RX), then set the RX FIFO trigger
* level accordingly. No need to set a trigger level for the
* TX FIFO, as this IP comes with an interrupt that fires when
* the TX FIFO is empty.
*/
rzv2m_csi_calc_current_transfer(csi);
rzv2m_csi_set_rx_fifo_trigger_level(csi);
rzv2m_csi_enable_irqs(csi, CSI_INT_OVERF | CSI_INT_UNDER);
/* Make sure the RX FIFO is empty */
writel(0, csi->base + CSI_IFIFOL);
writel(readl(csi->base + CSI_INT), csi->base + CSI_INT);
csi->status = 0;
rzv2m_csi_start_stop_operation(csi, 1, false);
/* TX */
if (csi->txbuf) {
ret = rzv2m_csi_fill_txfifo(csi);
if (ret)
break;
ret = rzv2m_csi_wait_for_tx_empty(csi);
if (ret)
break;
if (csi->bytes_sent == csi->buffer_len)
tx_completed = true;
}
/*
* Make sure the RX FIFO contains the desired number of words.
* We then either flush its content, or we copy it onto
* csi->rxbuf.
*/
ret = rzv2m_csi_wait_for_rx_ready(csi);
if (ret)
break;
/* RX */
if (csi->rxbuf) {
rzv2m_csi_start_stop_operation(csi, 0, false);
ret = rzv2m_csi_read_rxfifo(csi);
if (ret)
break;
if (csi->bytes_received == csi->buffer_len)
rx_completed = true;
}
ret = rzv2m_csi_start_stop_operation(csi, 0, true);
if (ret)
goto pio_quit;
if (csi->errors) {
ret = -EIO;
goto pio_quit;
}
}
rzv2m_csi_start_stop_operation(csi, 0, true);
pio_quit:
rzv2m_csi_disable_all_irqs(csi);
rzv2m_csi_enable_rx_trigger(csi, false);
rzv2m_csi_clear_all_irqs(csi);
return ret;
}
static int rzv2m_csi_transfer_one(struct spi_controller *controller,
struct spi_device *spi,
struct spi_transfer *transfer)
{
struct rzv2m_csi_priv *csi = spi_controller_get_devdata(controller);
struct device *dev = csi->dev;
int ret;
csi->txbuf = transfer->tx_buf;
csi->rxbuf = transfer->rx_buf;
csi->buffer_len = transfer->len;
rzv2m_csi_setup_operating_mode(csi, transfer);
rzv2m_csi_setup_clock(csi, transfer->speed_hz);
ret = rzv2m_csi_pio_transfer(csi);
if (ret) {
if (csi->errors & UNDERRUN_ERROR)
dev_err(dev, "Underrun error\n");
if (csi->errors & OVERFLOW_ERROR)
dev_err(dev, "Overflow error\n");
if (csi->errors & TX_TIMEOUT_ERROR)
dev_err(dev, "TX timeout error\n");
if (csi->errors & RX_TIMEOUT_ERROR)
dev_err(dev, "RX timeout error\n");
}
return ret;
}
static int rzv2m_csi_probe(struct platform_device *pdev)
{
struct spi_controller *controller;
struct device *dev = &pdev->dev;
struct rzv2m_csi_priv *csi;
struct reset_control *rstc;
int irq;
int ret;
controller = devm_spi_alloc_master(dev, sizeof(*csi));
if (!controller)
return -ENOMEM;
csi = spi_controller_get_devdata(controller);
platform_set_drvdata(pdev, csi);
csi->dev = dev;
csi->controller = controller;
csi->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(csi->base))
return PTR_ERR(csi->base);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
csi->csiclk = devm_clk_get(dev, "csiclk");
if (IS_ERR(csi->csiclk))
return dev_err_probe(dev, PTR_ERR(csi->csiclk),
"could not get csiclk\n");
csi->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(csi->pclk))
return dev_err_probe(dev, PTR_ERR(csi->pclk),
"could not get pclk\n");
rstc = devm_reset_control_get_shared(dev, NULL);
if (IS_ERR(rstc))
return dev_err_probe(dev, PTR_ERR(rstc), "Missing reset ctrl\n");
init_waitqueue_head(&csi->wait);
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
controller->dev.of_node = pdev->dev.of_node;
controller->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
controller->setup = rzv2m_csi_setup;
controller->transfer_one = rzv2m_csi_transfer_one;
controller->use_gpio_descriptors = true;
ret = devm_request_irq(dev, irq, rzv2m_csi_irq_handler, 0,
dev_name(dev), csi);
if (ret)
return dev_err_probe(dev, ret, "cannot request IRQ\n");
/*
* The reset also affects other HW that is not under the control
* of Linux. Therefore, all we can do is make sure the reset is
* deasserted.
*/
reset_control_deassert(rstc);
/* Make sure the IP is in SW reset state */
ret = rzv2m_csi_sw_reset(csi, 1);
if (ret)
return ret;
ret = clk_prepare_enable(csi->csiclk);
if (ret)
return dev_err_probe(dev, ret, "could not enable csiclk\n");
ret = spi_register_controller(controller);
if (ret) {
clk_disable_unprepare(csi->csiclk);
return dev_err_probe(dev, ret, "register controller failed\n");
}
return 0;
}
static int rzv2m_csi_remove(struct platform_device *pdev)
{
struct rzv2m_csi_priv *csi = platform_get_drvdata(pdev);
spi_unregister_controller(csi->controller);
rzv2m_csi_sw_reset(csi, 1);
clk_disable_unprepare(csi->csiclk);
return 0;
}
static const struct of_device_id rzv2m_csi_match[] = {
{ .compatible = "renesas,rzv2m-csi" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rzv2m_csi_match);
static struct platform_driver rzv2m_csi_drv = {
.probe = rzv2m_csi_probe,
.remove = rzv2m_csi_remove,
.driver = {
.name = "rzv2m_csi",
.of_match_table = rzv2m_csi_match,
},
};
module_platform_driver(rzv2m_csi_drv);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Fabrizio Castro <castro.fabrizio.jz@renesas.com>");
MODULE_DESCRIPTION("Clocked Serial Interface Driver");
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/platform_data/spi-s3c64xx.h> #include <linux/platform_data/spi-s3c64xx.h>
#define MAX_SPI_PORTS 12 #define MAX_SPI_PORTS 12
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
#define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1) #define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1)
#define AUTOSUSPEND_TIMEOUT 2000 #define AUTOSUSPEND_TIMEOUT 2000
...@@ -59,6 +58,8 @@ ...@@ -59,6 +58,8 @@
#define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD (1<<17) #define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD (1<<17)
#define S3C64XX_SPI_MODE_BUS_TSZ_WORD (2<<17) #define S3C64XX_SPI_MODE_BUS_TSZ_WORD (2<<17)
#define S3C64XX_SPI_MODE_BUS_TSZ_MASK (3<<17) #define S3C64XX_SPI_MODE_BUS_TSZ_MASK (3<<17)
#define S3C64XX_SPI_MODE_RX_RDY_LVL GENMASK(16, 11)
#define S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT 11
#define S3C64XX_SPI_MODE_SELF_LOOPBACK (1<<3) #define S3C64XX_SPI_MODE_SELF_LOOPBACK (1<<3)
#define S3C64XX_SPI_MODE_RXDMA_ON (1<<2) #define S3C64XX_SPI_MODE_RXDMA_ON (1<<2)
#define S3C64XX_SPI_MODE_TXDMA_ON (1<<1) #define S3C64XX_SPI_MODE_TXDMA_ON (1<<1)
...@@ -115,8 +116,10 @@ ...@@ -115,8 +116,10 @@
#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT #define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT
#define S3C64XX_SPI_POLLING_SIZE 32
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
#define is_polling(x) (x->port_conf->quirks & S3C64XX_SPI_QUIRK_POLL) #define is_polling(x) (x->cntrlr_info->polling)
#define RXBUSY (1<<2) #define RXBUSY (1<<2)
#define TXBUSY (1<<3) #define TXBUSY (1<<3)
...@@ -553,7 +556,7 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd, ...@@ -553,7 +556,7 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
} }
static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
struct spi_transfer *xfer) struct spi_transfer *xfer, bool use_irq)
{ {
void __iomem *regs = sdd->regs; void __iomem *regs = sdd->regs;
unsigned long val; unsigned long val;
...@@ -562,11 +565,24 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, ...@@ -562,11 +565,24 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
u32 cpy_len; u32 cpy_len;
u8 *buf; u8 *buf;
int ms; int ms;
unsigned long time_us;
/* millisecs to xfer 'len' bytes @ 'cur_speed' */ /* microsecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed; time_us = (xfer->len * 8 * 1000 * 1000) / sdd->cur_speed;
ms = (time_us / 1000);
ms += 10; /* some tolerance */ ms += 10; /* some tolerance */
/* sleep during signal transfer time */
status = readl(regs + S3C64XX_SPI_STATUS);
if (RX_FIFO_LVL(status, sdd) < xfer->len)
usleep_range(time_us / 2, time_us);
if (use_irq) {
val = msecs_to_jiffies(ms);
if (!wait_for_completion_timeout(&sdd->xfer_completion, val))
return -EIO;
}
val = msecs_to_loops(ms); val = msecs_to_loops(ms);
do { do {
status = readl(regs + S3C64XX_SPI_STATUS); status = readl(regs + S3C64XX_SPI_STATUS);
...@@ -729,10 +745,13 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, ...@@ -729,10 +745,13 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
void *rx_buf = NULL; void *rx_buf = NULL;
int target_len = 0, origin_len = 0; int target_len = 0, origin_len = 0;
int use_dma = 0; int use_dma = 0;
bool use_irq = false;
int status; int status;
u32 speed; u32 speed;
u8 bpw; u8 bpw;
unsigned long flags; unsigned long flags;
u32 rdy_lv;
u32 val;
reinit_completion(&sdd->xfer_completion); reinit_completion(&sdd->xfer_completion);
...@@ -753,17 +772,46 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, ...@@ -753,17 +772,46 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
sdd->rx_dma.ch && sdd->tx_dma.ch) { sdd->rx_dma.ch && sdd->tx_dma.ch) {
use_dma = 1; use_dma = 1;
} else if (xfer->len > fifo_len) { } else if (xfer->len >= fifo_len) {
tx_buf = xfer->tx_buf; tx_buf = xfer->tx_buf;
rx_buf = xfer->rx_buf; rx_buf = xfer->rx_buf;
origin_len = xfer->len; origin_len = xfer->len;
target_len = xfer->len; target_len = xfer->len;
if (xfer->len > fifo_len) xfer->len = fifo_len - 1;
xfer->len = fifo_len;
} }
do { do {
/* transfer size is greater than 32, change to IRQ mode */
if (!use_dma && xfer->len > S3C64XX_SPI_POLLING_SIZE)
use_irq = true;
if (use_irq) {
reinit_completion(&sdd->xfer_completion);
rdy_lv = xfer->len;
/* Setup RDY_FIFO trigger Level
* RDY_LVL =
* fifo_lvl up to 64 byte -> N bytes
* 128 byte -> RDY_LVL * 2 bytes
* 256 byte -> RDY_LVL * 4 bytes
*/
if (fifo_len == 128)
rdy_lv /= 2;
else if (fifo_len == 256)
rdy_lv /= 4;
val = readl(sdd->regs + S3C64XX_SPI_MODE_CFG);
val &= ~S3C64XX_SPI_MODE_RX_RDY_LVL;
val |= (rdy_lv << S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT);
writel(val, sdd->regs + S3C64XX_SPI_MODE_CFG);
/* Enable FIFO_RDY_EN IRQ */
val = readl(sdd->regs + S3C64XX_SPI_INT_EN);
writel((val | S3C64XX_SPI_INT_RX_FIFORDY_EN),
sdd->regs + S3C64XX_SPI_INT_EN);
}
spin_lock_irqsave(&sdd->lock, flags); spin_lock_irqsave(&sdd->lock, flags);
/* Pending only which is to be done */ /* Pending only which is to be done */
...@@ -785,7 +833,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, ...@@ -785,7 +833,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (use_dma) if (use_dma)
status = s3c64xx_wait_for_dma(sdd, xfer); status = s3c64xx_wait_for_dma(sdd, xfer);
else else
status = s3c64xx_wait_for_pio(sdd, xfer); status = s3c64xx_wait_for_pio(sdd, xfer, use_irq);
if (status) { if (status) {
dev_err(&spi->dev, dev_err(&spi->dev,
...@@ -824,8 +872,8 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, ...@@ -824,8 +872,8 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (xfer->rx_buf) if (xfer->rx_buf)
xfer->rx_buf += xfer->len; xfer->rx_buf += xfer->len;
if (target_len > fifo_len) if (target_len >= fifo_len)
xfer->len = fifo_len; xfer->len = fifo_len - 1;
else else
xfer->len = target_len; xfer->len = target_len;
} }
...@@ -995,6 +1043,14 @@ static irqreturn_t s3c64xx_spi_irq(int irq, void *data) ...@@ -995,6 +1043,14 @@ static irqreturn_t s3c64xx_spi_irq(int irq, void *data)
dev_err(&spi->dev, "TX underrun\n"); dev_err(&spi->dev, "TX underrun\n");
} }
if (val & S3C64XX_SPI_ST_RX_FIFORDY) {
complete(&sdd->xfer_completion);
/* No pending clear irq, turn-off INT_EN_RX_FIFO_RDY */
val = readl(sdd->regs + S3C64XX_SPI_INT_EN);
writel((val & ~S3C64XX_SPI_INT_RX_FIFORDY_EN),
sdd->regs + S3C64XX_SPI_INT_EN);
}
/* Clear the pending irq by setting and then clearing it */ /* Clear the pending irq by setting and then clearing it */
writel(clr, sdd->regs + S3C64XX_SPI_PENDING_CLR); writel(clr, sdd->regs + S3C64XX_SPI_PENDING_CLR);
writel(0, sdd->regs + S3C64XX_SPI_PENDING_CLR); writel(0, sdd->regs + S3C64XX_SPI_PENDING_CLR);
...@@ -1068,6 +1124,7 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) ...@@ -1068,6 +1124,7 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
} }
sci->no_cs = of_property_read_bool(dev->of_node, "no-cs-readback"); sci->no_cs = of_property_read_bool(dev->of_node, "no-cs-readback");
sci->polling = !of_property_present(dev->of_node, "dmas");
return sci; return sci;
} }
...@@ -1103,29 +1160,23 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1103,29 +1160,23 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
return PTR_ERR(sci); return PTR_ERR(sci);
} }
if (!sci) { if (!sci)
dev_err(&pdev->dev, "platform_data missing!\n"); return dev_err_probe(&pdev->dev, -ENODEV,
return -ENODEV; "Platform_data missing!\n");
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (mem_res == NULL) { if (!mem_res)
dev_err(&pdev->dev, "Unable to get SPI MEM resource\n"); return dev_err_probe(&pdev->dev, -ENXIO,
return -ENXIO; "Unable to get SPI MEM resource\n");
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0)
dev_warn(&pdev->dev, "Failed to get IRQ: %d\n", irq); return dev_err_probe(&pdev->dev, irq, "Failed to get IRQ\n");
return irq;
}
master = spi_alloc_master(&pdev->dev, master = devm_spi_alloc_master(&pdev->dev, sizeof(*sdd));
sizeof(struct s3c64xx_spi_driver_data)); if (!master)
if (master == NULL) { return dev_err_probe(&pdev->dev, -ENOMEM,
dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); "Unable to allocate SPI Master\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
...@@ -1137,11 +1188,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1137,11 +1188,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
sdd->sfr_start = mem_res->start; sdd->sfr_start = mem_res->start;
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
ret = of_alias_get_id(pdev->dev.of_node, "spi"); ret = of_alias_get_id(pdev->dev.of_node, "spi");
if (ret < 0) { if (ret < 0)
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", return dev_err_probe(&pdev->dev, ret,
ret); "Failed to get alias id\n");
goto err_deref_master;
}
sdd->port_id = ret; sdd->port_id = ret;
} else { } else {
sdd->port_id = pdev->id; sdd->port_id = pdev->id;
...@@ -1175,59 +1224,31 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1175,59 +1224,31 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->can_dma = s3c64xx_spi_can_dma; master->can_dma = s3c64xx_spi_can_dma;
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res); sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sdd->regs)) { if (IS_ERR(sdd->regs))
ret = PTR_ERR(sdd->regs); return PTR_ERR(sdd->regs);
goto err_deref_master;
}
if (sci->cfg_gpio && sci->cfg_gpio()) { if (sci->cfg_gpio && sci->cfg_gpio())
dev_err(&pdev->dev, "Unable to config gpio\n"); return dev_err_probe(&pdev->dev, -EBUSY,
ret = -EBUSY; "Unable to config gpio\n");
goto err_deref_master;
}
/* Setup clocks */ /* Setup clocks */
sdd->clk = devm_clk_get(&pdev->dev, "spi"); sdd->clk = devm_clk_get_enabled(&pdev->dev, "spi");
if (IS_ERR(sdd->clk)) { if (IS_ERR(sdd->clk))
dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n"); return dev_err_probe(&pdev->dev, PTR_ERR(sdd->clk),
ret = PTR_ERR(sdd->clk); "Unable to acquire clock 'spi'\n");
goto err_deref_master;
}
ret = clk_prepare_enable(sdd->clk);
if (ret) {
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
goto err_deref_master;
}
sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr); sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
sdd->src_clk = devm_clk_get(&pdev->dev, clk_name); sdd->src_clk = devm_clk_get_enabled(&pdev->dev, clk_name);
if (IS_ERR(sdd->src_clk)) { if (IS_ERR(sdd->src_clk))
dev_err(&pdev->dev, return dev_err_probe(&pdev->dev, PTR_ERR(sdd->src_clk),
"Unable to acquire clock '%s'\n", clk_name); "Unable to acquire clock '%s'\n",
ret = PTR_ERR(sdd->src_clk); clk_name);
goto err_disable_clk;
}
ret = clk_prepare_enable(sdd->src_clk);
if (ret) {
dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
goto err_disable_clk;
}
if (sdd->port_conf->clk_ioclk) { if (sdd->port_conf->clk_ioclk) {
sdd->ioclk = devm_clk_get(&pdev->dev, "spi_ioclk"); sdd->ioclk = devm_clk_get_enabled(&pdev->dev, "spi_ioclk");
if (IS_ERR(sdd->ioclk)) { if (IS_ERR(sdd->ioclk))
dev_err(&pdev->dev, "Unable to acquire 'ioclk'\n"); return dev_err_probe(&pdev->dev, PTR_ERR(sdd->ioclk),
ret = PTR_ERR(sdd->ioclk); "Unable to acquire 'ioclk'\n");
goto err_disable_src_clk;
}
ret = clk_prepare_enable(sdd->ioclk);
if (ret) {
dev_err(&pdev->dev, "Couldn't enable clock 'ioclk'\n");
goto err_disable_src_clk;
}
} }
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
...@@ -1275,14 +1296,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1275,14 +1296,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev); pm_runtime_set_suspended(&pdev->dev);
clk_disable_unprepare(sdd->ioclk);
err_disable_src_clk:
clk_disable_unprepare(sdd->src_clk);
err_disable_clk:
clk_disable_unprepare(sdd->clk);
err_deref_master:
spi_master_put(master);
return ret; return ret;
} }
...@@ -1300,12 +1313,6 @@ static void s3c64xx_spi_remove(struct platform_device *pdev) ...@@ -1300,12 +1313,6 @@ static void s3c64xx_spi_remove(struct platform_device *pdev)
dma_release_channel(sdd->tx_dma.ch); dma_release_channel(sdd->tx_dma.ch);
} }
clk_disable_unprepare(sdd->ioclk);
clk_disable_unprepare(sdd->src_clk);
clk_disable_unprepare(sdd->clk);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev); pm_runtime_set_suspended(&pdev->dev);
......
...@@ -337,7 +337,7 @@ static struct i2c_driver sc18is602_driver = { ...@@ -337,7 +337,7 @@ static struct i2c_driver sc18is602_driver = {
.name = "sc18is602", .name = "sc18is602",
.of_match_table = of_match_ptr(sc18is602_of_match), .of_match_table = of_match_ptr(sc18is602_of_match),
}, },
.probe_new = sc18is602_probe, .probe = sc18is602_probe,
.id_table = sc18is602_id, .id_table = sc18is602_id,
}; };
......
...@@ -526,7 +526,7 @@ static int f_ospi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -526,7 +526,7 @@ static int f_ospi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static bool f_ospi_supports_op_width(struct spi_mem *mem, static bool f_ospi_supports_op_width(struct spi_mem *mem,
const struct spi_mem_op *op) const struct spi_mem_op *op)
{ {
u8 width_available[] = { 0, 1, 2, 4, 8 }; static const u8 width_available[] = { 0, 1, 2, 4, 8 };
u8 width_op[] = { op->cmd.buswidth, op->addr.buswidth, u8 width_op[] = { op->cmd.buswidth, op->addr.buswidth,
op->dummy.buswidth, op->data.buswidth }; op->dummy.buswidth, op->data.buswidth };
bool is_match_found; bool is_match_found;
...@@ -566,7 +566,7 @@ static bool f_ospi_supports_op(struct spi_mem *mem, ...@@ -566,7 +566,7 @@ static bool f_ospi_supports_op(struct spi_mem *mem,
static int f_ospi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) static int f_ospi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{ {
op->data.nbytes = min((int)op->data.nbytes, (int)(OSPI_DAT_SIZE_MAX)); op->data.nbytes = min_t(int, op->data.nbytes, OSPI_DAT_SIZE_MAX);
return 0; return 0;
} }
...@@ -634,18 +634,12 @@ static int f_ospi_probe(struct platform_device *pdev) ...@@ -634,18 +634,12 @@ static int f_ospi_probe(struct platform_device *pdev)
goto err_put_ctlr; goto err_put_ctlr;
} }
ospi->clk = devm_clk_get(dev, NULL); ospi->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(ospi->clk)) { if (IS_ERR(ospi->clk)) {
ret = PTR_ERR(ospi->clk); ret = PTR_ERR(ospi->clk);
goto err_put_ctlr; goto err_put_ctlr;
} }
ret = clk_prepare_enable(ospi->clk);
if (ret) {
dev_err(dev, "Failed to enable the clock\n");
goto err_disable_clk;
}
mutex_init(&ospi->mlock); mutex_init(&ospi->mlock);
ret = f_ospi_init(ospi); ret = f_ospi_init(ospi);
...@@ -661,9 +655,6 @@ static int f_ospi_probe(struct platform_device *pdev) ...@@ -661,9 +655,6 @@ static int f_ospi_probe(struct platform_device *pdev)
err_destroy_mutex: err_destroy_mutex:
mutex_destroy(&ospi->mlock); mutex_destroy(&ospi->mlock);
err_disable_clk:
clk_disable_unprepare(ospi->clk);
err_put_ctlr: err_put_ctlr:
spi_controller_put(ctlr); spi_controller_put(ctlr);
...@@ -674,8 +665,6 @@ static void f_ospi_remove(struct platform_device *pdev) ...@@ -674,8 +665,6 @@ static void f_ospi_remove(struct platform_device *pdev)
{ {
struct f_ospi *ospi = platform_get_drvdata(pdev); struct f_ospi *ospi = platform_get_drvdata(pdev);
clk_disable_unprepare(ospi->clk);
mutex_destroy(&ospi->mlock); mutex_destroy(&ospi->mlock);
} }
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
// //
// STMicroelectronics STM32 SPI Controller driver (master mode only) // STMicroelectronics STM32 SPI Controller driver
// //
// Copyright (C) 2017, STMicroelectronics - All Rights Reserved // Copyright (C) 2017, STMicroelectronics - All Rights Reserved
// Author(s): Amelie Delaunay <amelie.delaunay@st.com> for STMicroelectronics. // Author(s): Amelie Delaunay <amelie.delaunay@st.com> for STMicroelectronics.
...@@ -117,6 +117,7 @@ ...@@ -117,6 +117,7 @@
#define STM32H7_SPI_CFG2_CPHA BIT(24) #define STM32H7_SPI_CFG2_CPHA BIT(24)
#define STM32H7_SPI_CFG2_CPOL BIT(25) #define STM32H7_SPI_CFG2_CPOL BIT(25)
#define STM32H7_SPI_CFG2_SSM BIT(26) #define STM32H7_SPI_CFG2_SSM BIT(26)
#define STM32H7_SPI_CFG2_SSIOP BIT(28)
#define STM32H7_SPI_CFG2_AFCNTR BIT(31) #define STM32H7_SPI_CFG2_AFCNTR BIT(31)
/* STM32H7_SPI_IER bit fields */ /* STM32H7_SPI_IER bit fields */
...@@ -170,6 +171,10 @@ ...@@ -170,6 +171,10 @@
*/ */
#define SPI_DMA_MIN_BYTES 16 #define SPI_DMA_MIN_BYTES 16
/* STM32 SPI driver helpers */
#define STM32_SPI_MASTER_MODE(stm32_spi) (!(stm32_spi)->device_mode)
#define STM32_SPI_DEVICE_MODE(stm32_spi) ((stm32_spi)->device_mode)
/** /**
* struct stm32_spi_reg - stm32 SPI register & bitfield desc * struct stm32_spi_reg - stm32 SPI register & bitfield desc
* @reg: register offset * @reg: register offset
...@@ -190,6 +195,7 @@ struct stm32_spi_reg { ...@@ -190,6 +195,7 @@ struct stm32_spi_reg {
* @cpol: clock polarity register and polarity bit * @cpol: clock polarity register and polarity bit
* @cpha: clock phase register and phase bit * @cpha: clock phase register and phase bit
* @lsb_first: LSB transmitted first register and bit * @lsb_first: LSB transmitted first register and bit
* @cs_high: chips select active value
* @br: baud rate register and bitfields * @br: baud rate register and bitfields
* @rx: SPI RX data register * @rx: SPI RX data register
* @tx: SPI TX data register * @tx: SPI TX data register
...@@ -201,6 +207,7 @@ struct stm32_spi_regspec { ...@@ -201,6 +207,7 @@ struct stm32_spi_regspec {
const struct stm32_spi_reg cpol; const struct stm32_spi_reg cpol;
const struct stm32_spi_reg cpha; const struct stm32_spi_reg cpha;
const struct stm32_spi_reg lsb_first; const struct stm32_spi_reg lsb_first;
const struct stm32_spi_reg cs_high;
const struct stm32_spi_reg br; const struct stm32_spi_reg br;
const struct stm32_spi_reg rx; const struct stm32_spi_reg rx;
const struct stm32_spi_reg tx; const struct stm32_spi_reg tx;
...@@ -258,7 +265,7 @@ struct stm32_spi_cfg { ...@@ -258,7 +265,7 @@ struct stm32_spi_cfg {
/** /**
* struct stm32_spi - private data of the SPI controller * struct stm32_spi - private data of the SPI controller
* @dev: driver model representation of the controller * @dev: driver model representation of the controller
* @master: controller master interface * @ctrl: controller interface
* @cfg: compatible configuration data * @cfg: compatible configuration data
* @base: virtual memory area * @base: virtual memory area
* @clk: hw kernel clock feeding the SPI clock generator * @clk: hw kernel clock feeding the SPI clock generator
...@@ -280,10 +287,11 @@ struct stm32_spi_cfg { ...@@ -280,10 +287,11 @@ struct stm32_spi_cfg {
* @dma_tx: dma channel for TX transfer * @dma_tx: dma channel for TX transfer
* @dma_rx: dma channel for RX transfer * @dma_rx: dma channel for RX transfer
* @phys_addr: SPI registers physical base address * @phys_addr: SPI registers physical base address
* @device_mode: the controller is configured as SPI device
*/ */
struct stm32_spi { struct stm32_spi {
struct device *dev; struct device *dev;
struct spi_master *master; struct spi_controller *ctrl;
const struct stm32_spi_cfg *cfg; const struct stm32_spi_cfg *cfg;
void __iomem *base; void __iomem *base;
struct clk *clk; struct clk *clk;
...@@ -307,6 +315,8 @@ struct stm32_spi { ...@@ -307,6 +315,8 @@ struct stm32_spi {
struct dma_chan *dma_tx; struct dma_chan *dma_tx;
struct dma_chan *dma_rx; struct dma_chan *dma_rx;
dma_addr_t phys_addr; dma_addr_t phys_addr;
bool device_mode;
}; };
static const struct stm32_spi_regspec stm32f4_spi_regspec = { static const struct stm32_spi_regspec stm32f4_spi_regspec = {
...@@ -318,6 +328,7 @@ static const struct stm32_spi_regspec stm32f4_spi_regspec = { ...@@ -318,6 +328,7 @@ static const struct stm32_spi_regspec stm32f4_spi_regspec = {
.cpol = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPOL }, .cpol = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPOL },
.cpha = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPHA }, .cpha = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPHA },
.lsb_first = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_LSBFRST }, .lsb_first = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_LSBFRST },
.cs_high = {},
.br = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_BR, STM32F4_SPI_CR1_BR_SHIFT }, .br = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_BR, STM32F4_SPI_CR1_BR_SHIFT },
.rx = { STM32F4_SPI_DR }, .rx = { STM32F4_SPI_DR },
...@@ -336,6 +347,7 @@ static const struct stm32_spi_regspec stm32h7_spi_regspec = { ...@@ -336,6 +347,7 @@ static const struct stm32_spi_regspec stm32h7_spi_regspec = {
.cpol = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPOL }, .cpol = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPOL },
.cpha = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPHA }, .cpha = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPHA },
.lsb_first = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_LSBFRST }, .lsb_first = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_LSBFRST },
.cs_high = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_SSIOP },
.br = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_MBR, .br = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_MBR,
STM32H7_SPI_CFG1_MBR_SHIFT }, STM32H7_SPI_CFG1_MBR_SHIFT },
...@@ -437,9 +449,9 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, ...@@ -437,9 +449,9 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
div = DIV_ROUND_CLOSEST(spi->clk_rate & ~0x1, speed_hz); div = DIV_ROUND_CLOSEST(spi->clk_rate & ~0x1, speed_hz);
/* /*
* SPI framework set xfer->speed_hz to master->max_speed_hz if * SPI framework set xfer->speed_hz to ctrl->max_speed_hz if
* xfer->speed_hz is greater than master->max_speed_hz, and it returns * xfer->speed_hz is greater than ctrl->max_speed_hz, and it returns
* an error when xfer->speed_hz is lower than master->min_speed_hz, so * an error when xfer->speed_hz is lower than ctrl->min_speed_hz, so
* no need to check it there. * no need to check it there.
* However, we need to ensure the following calculations. * However, we need to ensure the following calculations.
*/ */
...@@ -657,9 +669,9 @@ static void stm32f4_spi_disable(struct stm32_spi *spi) ...@@ -657,9 +669,9 @@ static void stm32f4_spi_disable(struct stm32_spi *spi)
} }
if (spi->cur_usedma && spi->dma_tx) if (spi->cur_usedma && spi->dma_tx)
dmaengine_terminate_all(spi->dma_tx); dmaengine_terminate_async(spi->dma_tx);
if (spi->cur_usedma && spi->dma_rx) if (spi->cur_usedma && spi->dma_rx)
dmaengine_terminate_all(spi->dma_rx); dmaengine_terminate_async(spi->dma_rx);
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE); stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE);
...@@ -696,9 +708,9 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) ...@@ -696,9 +708,9 @@ static void stm32h7_spi_disable(struct stm32_spi *spi)
} }
if (spi->cur_usedma && spi->dma_tx) if (spi->cur_usedma && spi->dma_tx)
dmaengine_terminate_all(spi->dma_tx); dmaengine_terminate_async(spi->dma_tx);
if (spi->cur_usedma && spi->dma_rx) if (spi->cur_usedma && spi->dma_rx)
dmaengine_terminate_all(spi->dma_rx); dmaengine_terminate_async(spi->dma_rx);
stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE); stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE);
...@@ -714,19 +726,19 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) ...@@ -714,19 +726,19 @@ static void stm32h7_spi_disable(struct stm32_spi *spi)
/** /**
* stm32_spi_can_dma - Determine if the transfer is eligible for DMA use * stm32_spi_can_dma - Determine if the transfer is eligible for DMA use
* @master: controller master interface * @ctrl: controller interface
* @spi_dev: pointer to the spi device * @spi_dev: pointer to the spi device
* @transfer: pointer to spi transfer * @transfer: pointer to spi transfer
* *
* If driver has fifo and the current transfer size is greater than fifo size, * If driver has fifo and the current transfer size is greater than fifo size,
* use DMA. Otherwise use DMA for transfer longer than defined DMA min bytes. * use DMA. Otherwise use DMA for transfer longer than defined DMA min bytes.
*/ */
static bool stm32_spi_can_dma(struct spi_master *master, static bool stm32_spi_can_dma(struct spi_controller *ctrl,
struct spi_device *spi_dev, struct spi_device *spi_dev,
struct spi_transfer *transfer) struct spi_transfer *transfer)
{ {
unsigned int dma_size; unsigned int dma_size;
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
if (spi->cfg->has_fifo) if (spi->cfg->has_fifo)
dma_size = spi->fifo_size; dma_size = spi->fifo_size;
...@@ -742,12 +754,12 @@ static bool stm32_spi_can_dma(struct spi_master *master, ...@@ -742,12 +754,12 @@ static bool stm32_spi_can_dma(struct spi_master *master,
/** /**
* stm32f4_spi_irq_event - Interrupt handler for SPI controller events * stm32f4_spi_irq_event - Interrupt handler for SPI controller events
* @irq: interrupt line * @irq: interrupt line
* @dev_id: SPI controller master interface * @dev_id: SPI controller ctrl interface
*/ */
static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id) static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
{ {
struct spi_master *master = dev_id; struct spi_controller *ctrl = dev_id;
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
u32 sr, mask = 0; u32 sr, mask = 0;
bool end = false; bool end = false;
...@@ -830,14 +842,14 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id) ...@@ -830,14 +842,14 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
/** /**
* stm32f4_spi_irq_thread - Thread of interrupt handler for SPI controller * stm32f4_spi_irq_thread - Thread of interrupt handler for SPI controller
* @irq: interrupt line * @irq: interrupt line
* @dev_id: SPI controller master interface * @dev_id: SPI controller interface
*/ */
static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id) static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id)
{ {
struct spi_master *master = dev_id; struct spi_controller *ctrl = dev_id;
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
spi_finalize_current_transfer(master); spi_finalize_current_transfer(ctrl);
stm32f4_spi_disable(spi); stm32f4_spi_disable(spi);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -846,12 +858,12 @@ static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id) ...@@ -846,12 +858,12 @@ static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id)
/** /**
* stm32h7_spi_irq_thread - Thread of interrupt handler for SPI controller * stm32h7_spi_irq_thread - Thread of interrupt handler for SPI controller
* @irq: interrupt line * @irq: interrupt line
* @dev_id: SPI controller master interface * @dev_id: SPI controller interface
*/ */
static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
{ {
struct spi_master *master = dev_id; struct spi_controller *ctrl = dev_id;
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
u32 sr, ier, mask; u32 sr, ier, mask;
unsigned long flags; unsigned long flags;
bool end = false; bool end = false;
...@@ -931,7 +943,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) ...@@ -931,7 +943,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
if (end) { if (end) {
stm32h7_spi_disable(spi); stm32h7_spi_disable(spi);
spi_finalize_current_transfer(master); spi_finalize_current_transfer(ctrl);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -939,13 +951,13 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) ...@@ -939,13 +951,13 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
/** /**
* stm32_spi_prepare_msg - set up the controller to transfer a single message * stm32_spi_prepare_msg - set up the controller to transfer a single message
* @master: controller master interface * @ctrl: controller interface
* @msg: pointer to spi message * @msg: pointer to spi message
*/ */
static int stm32_spi_prepare_msg(struct spi_master *master, static int stm32_spi_prepare_msg(struct spi_controller *ctrl,
struct spi_message *msg) struct spi_message *msg)
{ {
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
struct spi_device *spi_dev = msg->spi; struct spi_device *spi_dev = msg->spi;
struct device_node *np = spi_dev->dev.of_node; struct device_node *np = spi_dev->dev.of_node;
unsigned long flags; unsigned long flags;
...@@ -971,6 +983,11 @@ static int stm32_spi_prepare_msg(struct spi_master *master, ...@@ -971,6 +983,11 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
else else
clrb |= spi->cfg->regs->lsb_first.mask; clrb |= spi->cfg->regs->lsb_first.mask;
if (STM32_SPI_DEVICE_MODE(spi) && spi_dev->mode & SPI_CS_HIGH)
setb |= spi->cfg->regs->cs_high.mask;
else
clrb |= spi->cfg->regs->cs_high.mask;
dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d\n", dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d\n",
!!(spi_dev->mode & SPI_CPOL), !!(spi_dev->mode & SPI_CPOL),
!!(spi_dev->mode & SPI_CPHA), !!(spi_dev->mode & SPI_CPHA),
...@@ -984,9 +1001,9 @@ static int stm32_spi_prepare_msg(struct spi_master *master, ...@@ -984,9 +1001,9 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
if (spi->cfg->set_number_of_data) { if (spi->cfg->set_number_of_data) {
int ret; int ret;
ret = spi_split_transfers_maxwords(master, msg, ret = spi_split_transfers_maxsize(ctrl, msg,
STM32H7_SPI_TSIZE_MAX, STM32H7_SPI_TSIZE_MAX,
GFP_KERNEL | GFP_DMA); GFP_KERNEL | GFP_DMA);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -1016,7 +1033,7 @@ static void stm32f4_spi_dma_tx_cb(void *data) ...@@ -1016,7 +1033,7 @@ static void stm32f4_spi_dma_tx_cb(void *data)
struct stm32_spi *spi = data; struct stm32_spi *spi = data;
if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) { if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) {
spi_finalize_current_transfer(spi->master); spi_finalize_current_transfer(spi->ctrl);
stm32f4_spi_disable(spi); stm32f4_spi_disable(spi);
} }
} }
...@@ -1031,7 +1048,7 @@ static void stm32_spi_dma_rx_cb(void *data) ...@@ -1031,7 +1048,7 @@ static void stm32_spi_dma_rx_cb(void *data)
{ {
struct stm32_spi *spi = data; struct stm32_spi *spi = data;
spi_finalize_current_transfer(spi->master); spi_finalize_current_transfer(spi->ctrl);
spi->cfg->disable(spi); spi->cfg->disable(spi);
} }
...@@ -1161,7 +1178,8 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) ...@@ -1161,7 +1178,8 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi)
if (spi->tx_buf) if (spi->tx_buf)
stm32h7_spi_write_txfifo(spi); stm32h7_spi_write_txfifo(spi);
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); if (STM32_SPI_MASTER_MODE(spi))
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
writel_relaxed(ier, spi->base + STM32H7_SPI_IER); writel_relaxed(ier, spi->base + STM32H7_SPI_IER);
...@@ -1208,7 +1226,8 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) ...@@ -1208,7 +1226,8 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
stm32_spi_enable(spi); stm32_spi_enable(spi);
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); if (STM32_SPI_MASTER_MODE(spi))
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
} }
/** /**
...@@ -1302,7 +1321,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, ...@@ -1302,7 +1321,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
dma_submit_error: dma_submit_error:
if (spi->dma_rx) if (spi->dma_rx)
dmaengine_terminate_all(spi->dma_rx); dmaengine_terminate_sync(spi->dma_rx);
dma_desc_error: dma_desc_error:
stm32_spi_clr_bits(spi, spi->cfg->regs->dma_rx_en.reg, stm32_spi_clr_bits(spi, spi->cfg->regs->dma_rx_en.reg,
...@@ -1536,16 +1555,18 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, ...@@ -1536,16 +1555,18 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
spi->cfg->set_bpw(spi); spi->cfg->set_bpw(spi);
/* Update spi->cur_speed with real clock speed */ /* Update spi->cur_speed with real clock speed */
mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, if (STM32_SPI_MASTER_MODE(spi)) {
spi->cfg->baud_rate_div_min, mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz,
spi->cfg->baud_rate_div_max); spi->cfg->baud_rate_div_min,
if (mbr < 0) { spi->cfg->baud_rate_div_max);
ret = mbr; if (mbr < 0) {
goto out; ret = mbr;
} goto out;
}
transfer->speed_hz = spi->cur_speed; transfer->speed_hz = spi->cur_speed;
stm32_spi_set_mbr(spi, mbr); stm32_spi_set_mbr(spi, mbr);
}
comm_type = stm32_spi_communication_type(spi_dev, transfer); comm_type = stm32_spi_communication_type(spi_dev, transfer);
ret = spi->cfg->set_mode(spi, comm_type); ret = spi->cfg->set_mode(spi, comm_type);
...@@ -1554,7 +1575,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, ...@@ -1554,7 +1575,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
spi->cur_comm = comm_type; spi->cur_comm = comm_type;
if (spi->cfg->set_data_idleness) if (STM32_SPI_MASTER_MODE(spi) && spi->cfg->set_data_idleness)
spi->cfg->set_data_idleness(spi, transfer->len); spi->cfg->set_data_idleness(spi, transfer->len);
if (spi->cur_bpw <= 8) if (spi->cur_bpw <= 8)
...@@ -1575,7 +1596,8 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, ...@@ -1575,7 +1596,8 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
dev_dbg(spi->dev, dev_dbg(spi->dev,
"data frame of %d-bit, data packet of %d data frames\n", "data frame of %d-bit, data packet of %d data frames\n",
spi->cur_bpw, spi->cur_fthlv); spi->cur_bpw, spi->cur_fthlv);
dev_dbg(spi->dev, "speed set to %dHz\n", spi->cur_speed); if (STM32_SPI_MASTER_MODE(spi))
dev_dbg(spi->dev, "speed set to %dHz\n", spi->cur_speed);
dev_dbg(spi->dev, "transfer of %d bytes (%d data frames)\n", dev_dbg(spi->dev, "transfer of %d bytes (%d data frames)\n",
spi->cur_xferlen, nb_words); spi->cur_xferlen, nb_words);
dev_dbg(spi->dev, "dma %s\n", dev_dbg(spi->dev, "dma %s\n",
...@@ -1589,18 +1611,18 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, ...@@ -1589,18 +1611,18 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
/** /**
* stm32_spi_transfer_one - transfer a single spi_transfer * stm32_spi_transfer_one - transfer a single spi_transfer
* @master: controller master interface * @ctrl: controller interface
* @spi_dev: pointer to the spi device * @spi_dev: pointer to the spi device
* @transfer: pointer to spi transfer * @transfer: pointer to spi transfer
* *
* It must return 0 if the transfer is finished or 1 if the transfer is still * It must return 0 if the transfer is finished or 1 if the transfer is still
* in progress. * in progress.
*/ */
static int stm32_spi_transfer_one(struct spi_master *master, static int stm32_spi_transfer_one(struct spi_controller *ctrl,
struct spi_device *spi_dev, struct spi_device *spi_dev,
struct spi_transfer *transfer) struct spi_transfer *transfer)
{ {
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
int ret; int ret;
spi->tx_buf = transfer->tx_buf; spi->tx_buf = transfer->tx_buf;
...@@ -1608,8 +1630,8 @@ static int stm32_spi_transfer_one(struct spi_master *master, ...@@ -1608,8 +1630,8 @@ static int stm32_spi_transfer_one(struct spi_master *master,
spi->tx_len = spi->tx_buf ? transfer->len : 0; spi->tx_len = spi->tx_buf ? transfer->len : 0;
spi->rx_len = spi->rx_buf ? transfer->len : 0; spi->rx_len = spi->rx_buf ? transfer->len : 0;
spi->cur_usedma = (master->can_dma && spi->cur_usedma = (ctrl->can_dma &&
master->can_dma(master, spi_dev, transfer)); ctrl->can_dma(ctrl, spi_dev, transfer));
ret = stm32_spi_transfer_one_setup(spi, spi_dev, transfer); ret = stm32_spi_transfer_one_setup(spi, spi_dev, transfer);
if (ret) { if (ret) {
...@@ -1625,13 +1647,13 @@ static int stm32_spi_transfer_one(struct spi_master *master, ...@@ -1625,13 +1647,13 @@ static int stm32_spi_transfer_one(struct spi_master *master,
/** /**
* stm32_spi_unprepare_msg - relax the hardware * stm32_spi_unprepare_msg - relax the hardware
* @master: controller master interface * @ctrl: controller interface
* @msg: pointer to the spi message * @msg: pointer to the spi message
*/ */
static int stm32_spi_unprepare_msg(struct spi_master *master, static int stm32_spi_unprepare_msg(struct spi_controller *ctrl,
struct spi_message *msg) struct spi_message *msg)
{ {
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
spi->cfg->disable(spi); spi->cfg->disable(spi);
...@@ -1670,12 +1692,13 @@ static int stm32f4_spi_config(struct stm32_spi *spi) ...@@ -1670,12 +1692,13 @@ static int stm32f4_spi_config(struct stm32_spi *spi)
} }
/** /**
* stm32h7_spi_config - Configure SPI controller as SPI master * stm32h7_spi_config - Configure SPI controller
* @spi: pointer to the spi controller data structure * @spi: pointer to the spi controller data structure
*/ */
static int stm32h7_spi_config(struct stm32_spi *spi) static int stm32h7_spi_config(struct stm32_spi *spi)
{ {
unsigned long flags; unsigned long flags;
u32 cr1 = 0, cfg2 = 0;
spin_lock_irqsave(&spi->lock, flags); spin_lock_irqsave(&spi->lock, flags);
...@@ -1683,24 +1706,28 @@ static int stm32h7_spi_config(struct stm32_spi *spi) ...@@ -1683,24 +1706,28 @@ static int stm32h7_spi_config(struct stm32_spi *spi)
stm32_spi_clr_bits(spi, STM32H7_SPI_I2SCFGR, stm32_spi_clr_bits(spi, STM32H7_SPI_I2SCFGR,
STM32H7_SPI_I2SCFGR_I2SMOD); STM32H7_SPI_I2SCFGR_I2SMOD);
/* if (STM32_SPI_DEVICE_MODE(spi)) {
* - SS input value high /* Use native device select */
* - transmitter half duplex direction cfg2 &= ~STM32H7_SPI_CFG2_SSM;
* - automatic communication suspend when RX-Fifo is full } else {
*/ /*
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SSI | * - Transmitter half duplex direction
STM32H7_SPI_CR1_HDDIR | * - Automatic communication suspend when RX-Fifo is full
STM32H7_SPI_CR1_MASRX); * - SS input value high
*/
cr1 |= STM32H7_SPI_CR1_HDDIR | STM32H7_SPI_CR1_MASRX | STM32H7_SPI_CR1_SSI;
/* /*
* - Set the master mode (default Motorola mode) * - Set the master mode (default Motorola mode)
* - Consider 1 master/n slaves configuration and * - Consider 1 master/n devices configuration and
* SS input value is determined by the SSI bit * SS input value is determined by the SSI bit
* - keep control of all associated GPIOs * - keep control of all associated GPIOs
*/ */
stm32_spi_set_bits(spi, STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_MASTER | cfg2 |= STM32H7_SPI_CFG2_MASTER | STM32H7_SPI_CFG2_SSM | STM32H7_SPI_CFG2_AFCNTR;
STM32H7_SPI_CFG2_SSM | }
STM32H7_SPI_CFG2_AFCNTR);
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, cr1);
stm32_spi_set_bits(spi, STM32H7_SPI_CFG2, cfg2);
spin_unlock_irqrestore(&spi->lock, flags); spin_unlock_irqrestore(&spi->lock, flags);
...@@ -1756,24 +1783,38 @@ static const struct of_device_id stm32_spi_of_match[] = { ...@@ -1756,24 +1783,38 @@ static const struct of_device_id stm32_spi_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, stm32_spi_of_match); MODULE_DEVICE_TABLE(of, stm32_spi_of_match);
static int stm32h7_spi_device_abort(struct spi_controller *ctrl)
{
spi_finalize_current_transfer(ctrl);
return 0;
}
static int stm32_spi_probe(struct platform_device *pdev) static int stm32_spi_probe(struct platform_device *pdev)
{ {
struct spi_master *master; struct spi_controller *ctrl;
struct stm32_spi *spi; struct stm32_spi *spi;
struct resource *res; struct resource *res;
struct reset_control *rst; struct reset_control *rst;
struct device_node *np = pdev->dev.of_node;
bool device_mode;
int ret; int ret;
master = devm_spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); device_mode = of_property_read_bool(np, "spi-slave");
if (!master) {
dev_err(&pdev->dev, "spi master allocation failed\n"); if (device_mode)
ctrl = devm_spi_alloc_slave(&pdev->dev, sizeof(struct stm32_spi));
else
ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi));
if (!ctrl) {
dev_err(&pdev->dev, "spi controller allocation failed\n");
return -ENOMEM; return -ENOMEM;
} }
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, ctrl);
spi = spi_master_get_devdata(master); spi = spi_controller_get_devdata(ctrl);
spi->dev = &pdev->dev; spi->dev = &pdev->dev;
spi->master = master; spi->ctrl = ctrl;
spi->device_mode = device_mode;
spin_lock_init(&spi->lock); spin_lock_init(&spi->lock);
spi->cfg = (const struct stm32_spi_cfg *) spi->cfg = (const struct stm32_spi_cfg *)
...@@ -1794,7 +1835,7 @@ static int stm32_spi_probe(struct platform_device *pdev) ...@@ -1794,7 +1835,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, spi->irq, ret = devm_request_threaded_irq(&pdev->dev, spi->irq,
spi->cfg->irq_handler_event, spi->cfg->irq_handler_event,
spi->cfg->irq_handler_thread, spi->cfg->irq_handler_thread,
IRQF_ONESHOT, pdev->name, master); IRQF_ONESHOT, pdev->name, ctrl);
if (ret) { if (ret) {
dev_err(&pdev->dev, "irq%d request failed: %d\n", spi->irq, dev_err(&pdev->dev, "irq%d request failed: %d\n", spi->irq,
ret); ret);
...@@ -1843,19 +1884,21 @@ static int stm32_spi_probe(struct platform_device *pdev) ...@@ -1843,19 +1884,21 @@ static int stm32_spi_probe(struct platform_device *pdev)
goto err_clk_disable; goto err_clk_disable;
} }
master->dev.of_node = pdev->dev.of_node; ctrl->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true; ctrl->auto_runtime_pm = true;
master->bus_num = pdev->id; ctrl->bus_num = pdev->id;
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | ctrl->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST |
SPI_3WIRE; SPI_3WIRE;
master->bits_per_word_mask = spi->cfg->get_bpw_mask(spi); ctrl->bits_per_word_mask = spi->cfg->get_bpw_mask(spi);
master->max_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_min; ctrl->max_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_min;
master->min_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_max; ctrl->min_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_max;
master->use_gpio_descriptors = true; ctrl->use_gpio_descriptors = true;
master->prepare_message = stm32_spi_prepare_msg; ctrl->prepare_message = stm32_spi_prepare_msg;
master->transfer_one = stm32_spi_transfer_one; ctrl->transfer_one = stm32_spi_transfer_one;
master->unprepare_message = stm32_spi_unprepare_msg; ctrl->unprepare_message = stm32_spi_unprepare_msg;
master->flags = spi->cfg->flags; ctrl->flags = spi->cfg->flags;
if (STM32_SPI_DEVICE_MODE(spi))
ctrl->slave_abort = stm32h7_spi_device_abort;
spi->dma_tx = dma_request_chan(spi->dev, "tx"); spi->dma_tx = dma_request_chan(spi->dev, "tx");
if (IS_ERR(spi->dma_tx)) { if (IS_ERR(spi->dma_tx)) {
...@@ -1866,7 +1909,7 @@ static int stm32_spi_probe(struct platform_device *pdev) ...@@ -1866,7 +1909,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "failed to request tx dma channel\n"); dev_warn(&pdev->dev, "failed to request tx dma channel\n");
} else { } else {
master->dma_tx = spi->dma_tx; ctrl->dma_tx = spi->dma_tx;
} }
spi->dma_rx = dma_request_chan(spi->dev, "rx"); spi->dma_rx = dma_request_chan(spi->dev, "rx");
...@@ -1878,11 +1921,11 @@ static int stm32_spi_probe(struct platform_device *pdev) ...@@ -1878,11 +1921,11 @@ static int stm32_spi_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "failed to request rx dma channel\n"); dev_warn(&pdev->dev, "failed to request rx dma channel\n");
} else { } else {
master->dma_rx = spi->dma_rx; ctrl->dma_rx = spi->dma_rx;
} }
if (spi->dma_tx || spi->dma_rx) if (spi->dma_tx || spi->dma_rx)
master->can_dma = stm32_spi_can_dma; ctrl->can_dma = stm32_spi_can_dma;
pm_runtime_set_autosuspend_delay(&pdev->dev, pm_runtime_set_autosuspend_delay(&pdev->dev,
STM32_SPI_AUTOSUSPEND_DELAY); STM32_SPI_AUTOSUSPEND_DELAY);
...@@ -1891,9 +1934,9 @@ static int stm32_spi_probe(struct platform_device *pdev) ...@@ -1891,9 +1934,9 @@ static int stm32_spi_probe(struct platform_device *pdev)
pm_runtime_get_noresume(&pdev->dev); pm_runtime_get_noresume(&pdev->dev);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
ret = spi_register_master(master); ret = spi_register_controller(ctrl);
if (ret) { if (ret) {
dev_err(&pdev->dev, "spi master registration failed: %d\n", dev_err(&pdev->dev, "spi controller registration failed: %d\n",
ret); ret);
goto err_pm_disable; goto err_pm_disable;
} }
...@@ -1901,7 +1944,8 @@ static int stm32_spi_probe(struct platform_device *pdev) ...@@ -1901,7 +1944,8 @@ static int stm32_spi_probe(struct platform_device *pdev)
pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev);
dev_info(&pdev->dev, "driver initialized\n"); dev_info(&pdev->dev, "driver initialized (%s mode)\n",
STM32_SPI_MASTER_MODE(spi) ? "master" : "device");
return 0; return 0;
...@@ -1923,12 +1967,12 @@ static int stm32_spi_probe(struct platform_device *pdev) ...@@ -1923,12 +1967,12 @@ static int stm32_spi_probe(struct platform_device *pdev)
static void stm32_spi_remove(struct platform_device *pdev) static void stm32_spi_remove(struct platform_device *pdev)
{ {
struct spi_master *master = platform_get_drvdata(pdev); struct spi_controller *ctrl = platform_get_drvdata(pdev);
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
spi_unregister_master(master); spi_unregister_controller(ctrl);
spi->cfg->disable(spi); spi->cfg->disable(spi);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
...@@ -1936,10 +1980,10 @@ static void stm32_spi_remove(struct platform_device *pdev) ...@@ -1936,10 +1980,10 @@ static void stm32_spi_remove(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev); pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev);
if (master->dma_tx) if (ctrl->dma_tx)
dma_release_channel(master->dma_tx); dma_release_channel(ctrl->dma_tx);
if (master->dma_rx) if (ctrl->dma_rx)
dma_release_channel(master->dma_rx); dma_release_channel(ctrl->dma_rx);
clk_disable_unprepare(spi->clk); clk_disable_unprepare(spi->clk);
...@@ -1949,8 +1993,8 @@ static void stm32_spi_remove(struct platform_device *pdev) ...@@ -1949,8 +1993,8 @@ static void stm32_spi_remove(struct platform_device *pdev)
static int __maybe_unused stm32_spi_runtime_suspend(struct device *dev) static int __maybe_unused stm32_spi_runtime_suspend(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_controller *ctrl = dev_get_drvdata(dev);
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
clk_disable_unprepare(spi->clk); clk_disable_unprepare(spi->clk);
...@@ -1959,8 +2003,8 @@ static int __maybe_unused stm32_spi_runtime_suspend(struct device *dev) ...@@ -1959,8 +2003,8 @@ static int __maybe_unused stm32_spi_runtime_suspend(struct device *dev)
static int __maybe_unused stm32_spi_runtime_resume(struct device *dev) static int __maybe_unused stm32_spi_runtime_resume(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_controller *ctrl = dev_get_drvdata(dev);
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
int ret; int ret;
ret = pinctrl_pm_select_default_state(dev); ret = pinctrl_pm_select_default_state(dev);
...@@ -1972,10 +2016,10 @@ static int __maybe_unused stm32_spi_runtime_resume(struct device *dev) ...@@ -1972,10 +2016,10 @@ static int __maybe_unused stm32_spi_runtime_resume(struct device *dev)
static int __maybe_unused stm32_spi_suspend(struct device *dev) static int __maybe_unused stm32_spi_suspend(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_controller *ctrl = dev_get_drvdata(dev);
int ret; int ret;
ret = spi_master_suspend(master); ret = spi_controller_suspend(ctrl);
if (ret) if (ret)
return ret; return ret;
...@@ -1984,15 +2028,15 @@ static int __maybe_unused stm32_spi_suspend(struct device *dev) ...@@ -1984,15 +2028,15 @@ static int __maybe_unused stm32_spi_suspend(struct device *dev)
static int __maybe_unused stm32_spi_resume(struct device *dev) static int __maybe_unused stm32_spi_resume(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_controller *ctrl = dev_get_drvdata(dev);
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
int ret; int ret;
ret = pm_runtime_force_resume(dev); ret = pm_runtime_force_resume(dev);
if (ret) if (ret)
return ret; return ret;
ret = spi_master_resume(master); ret = spi_controller_resume(ctrl);
if (ret) { if (ret) {
clk_disable_unprepare(spi->clk); clk_disable_unprepare(spi->clk);
return ret; return ret;
......
...@@ -42,7 +42,9 @@ ...@@ -42,7 +42,9 @@
#define SUN6I_TFR_CTL_CS_MANUAL BIT(6) #define SUN6I_TFR_CTL_CS_MANUAL BIT(6)
#define SUN6I_TFR_CTL_CS_LEVEL BIT(7) #define SUN6I_TFR_CTL_CS_LEVEL BIT(7)
#define SUN6I_TFR_CTL_DHB BIT(8) #define SUN6I_TFR_CTL_DHB BIT(8)
#define SUN6I_TFR_CTL_SDC BIT(11)
#define SUN6I_TFR_CTL_FBS BIT(12) #define SUN6I_TFR_CTL_FBS BIT(12)
#define SUN6I_TFR_CTL_SDM BIT(13)
#define SUN6I_TFR_CTL_XCH BIT(31) #define SUN6I_TFR_CTL_XCH BIT(31)
#define SUN6I_INT_CTL_REG 0x10 #define SUN6I_INT_CTL_REG 0x10
...@@ -85,6 +87,11 @@ ...@@ -85,6 +87,11 @@
#define SUN6I_TXDATA_REG 0x200 #define SUN6I_TXDATA_REG 0x200
#define SUN6I_RXDATA_REG 0x300 #define SUN6I_RXDATA_REG 0x300
struct sun6i_spi_cfg {
unsigned long fifo_depth;
bool has_clk_ctl;
};
struct sun6i_spi { struct sun6i_spi {
struct spi_master *master; struct spi_master *master;
void __iomem *base_addr; void __iomem *base_addr;
...@@ -99,7 +106,7 @@ struct sun6i_spi { ...@@ -99,7 +106,7 @@ struct sun6i_spi {
const u8 *tx_buf; const u8 *tx_buf;
u8 *rx_buf; u8 *rx_buf;
int len; int len;
unsigned long fifo_depth; const struct sun6i_spi_cfg *cfg;
}; };
static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg) static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
...@@ -156,7 +163,7 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi) ...@@ -156,7 +163,7 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
u8 byte; u8 byte;
/* See how much data we can fit */ /* See how much data we can fit */
cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi); cnt = sspi->cfg->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
len = min((int)cnt, sspi->len); len = min((int)cnt, sspi->len);
...@@ -256,7 +263,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -256,7 +263,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
struct spi_transfer *tfr) struct spi_transfer *tfr)
{ {
struct sun6i_spi *sspi = spi_master_get_devdata(master); struct sun6i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout; unsigned int div, div_cdr1, div_cdr2, timeout;
unsigned int start, end, tx_time; unsigned int start, end, tx_time;
unsigned int trig_level; unsigned int trig_level;
unsigned int tx_len = 0, rx_len = 0; unsigned int tx_len = 0, rx_len = 0;
...@@ -289,14 +296,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -289,14 +296,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
* the hardcoded value used in old generation of Allwinner * the hardcoded value used in old generation of Allwinner
* SPI controller. (See spi-sun4i.c) * SPI controller. (See spi-sun4i.c)
*/ */
trig_level = sspi->fifo_depth / 4 * 3; trig_level = sspi->cfg->fifo_depth / 4 * 3;
} else { } else {
/* /*
* Setup FIFO DMA request trigger level * Setup FIFO DMA request trigger level
* We choose 1/2 of the full fifo depth, that value will * We choose 1/2 of the full fifo depth, that value will
* be used as DMA burst length. * be used as DMA burst length.
*/ */
trig_level = sspi->fifo_depth / 2; trig_level = sspi->cfg->fifo_depth / 2;
if (tfr->tx_buf) if (tfr->tx_buf)
reg |= SUN6I_FIFO_CTL_TF_DRQ_EN; reg |= SUN6I_FIFO_CTL_TF_DRQ_EN;
...@@ -346,39 +353,65 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -346,39 +353,65 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
/* Ensure that we have a parent clock fast enough */ if (sspi->cfg->has_clk_ctl) {
mclk_rate = clk_get_rate(sspi->mclk); unsigned int mclk_rate = clk_get_rate(sspi->mclk);
if (mclk_rate < (2 * tfr->speed_hz)) {
clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
mclk_rate = clk_get_rate(sspi->mclk);
}
/* /* Ensure that we have a parent clock fast enough */
* Setup clock divider. if (mclk_rate < (2 * tfr->speed_hz)) {
* clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
* We have two choices there. Either we can use the clock mclk_rate = clk_get_rate(sspi->mclk);
* divide rate 1, which is calculated thanks to this formula: }
* SPI_CLK = MOD_CLK / (2 ^ cdr)
* Or we can use CDR2, which is calculated with the formula: /*
* SPI_CLK = MOD_CLK / (2 * (cdr + 1)) * Setup clock divider.
* Wether we use the former or the latter is set through the *
* DRS bit. * We have two choices there. Either we can use the clock
* * divide rate 1, which is calculated thanks to this formula:
* First try CDR2, and if we can't reach the expected * SPI_CLK = MOD_CLK / (2 ^ cdr)
* frequency, fall back to CDR1. * Or we can use CDR2, which is calculated with the formula:
*/ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz); * Wether we use the former or the latter is set through the
div_cdr2 = DIV_ROUND_UP(div_cdr1, 2); * DRS bit.
if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) { *
reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS; * First try CDR2, and if we can't reach the expected
tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2); * frequency, fall back to CDR1.
*/
div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
} else {
div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
reg = SUN6I_CLK_CTL_CDR1(div);
tfr->effective_speed_hz = mclk_rate / (1 << div);
}
sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
} else { } else {
div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1)); clk_set_rate(sspi->mclk, tfr->speed_hz);
reg = SUN6I_CLK_CTL_CDR1(div); tfr->effective_speed_hz = clk_get_rate(sspi->mclk);
tfr->effective_speed_hz = mclk_rate / (1 << div);
/*
* Configure work mode.
*
* There are three work modes depending on the controller clock
* frequency:
* - normal sample mode : CLK <= 24MHz SDM=1 SDC=0
* - delay half-cycle sample mode : CLK <= 40MHz SDM=0 SDC=0
* - delay one-cycle sample mode : CLK >= 80MHz SDM=0 SDC=1
*/
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
reg &= ~(SUN6I_TFR_CTL_SDM | SUN6I_TFR_CTL_SDC);
if (tfr->effective_speed_hz <= 24000000)
reg |= SUN6I_TFR_CTL_SDM;
else if (tfr->effective_speed_hz >= 80000000)
reg |= SUN6I_TFR_CTL_SDC;
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
} }
sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
/* Finally enable the bus - doing so before might raise SCK to HIGH */ /* Finally enable the bus - doing so before might raise SCK to HIGH */
reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG); reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
reg |= SUN6I_GBL_CTL_BUS_ENABLE; reg |= SUN6I_GBL_CTL_BUS_ENABLE;
...@@ -410,9 +443,9 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -410,9 +443,9 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
reg = SUN6I_INT_CTL_TC; reg = SUN6I_INT_CTL_TC;
if (!use_dma) { if (!use_dma) {
if (rx_len > sspi->fifo_depth) if (rx_len > sspi->cfg->fifo_depth)
reg |= SUN6I_INT_CTL_RF_RDY; reg |= SUN6I_INT_CTL_RF_RDY;
if (tx_len > sspi->fifo_depth) if (tx_len > sspi->cfg->fifo_depth)
reg |= SUN6I_INT_CTL_TF_ERQ; reg |= SUN6I_INT_CTL_TF_ERQ;
} }
...@@ -422,7 +455,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -422,7 +455,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH); sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U); tx_time = spi_controller_xfer_timeout(master, tfr);
start = jiffies; start = jiffies;
timeout = wait_for_completion_timeout(&sspi->done, timeout = wait_for_completion_timeout(&sspi->done,
msecs_to_jiffies(tx_time)); msecs_to_jiffies(tx_time));
...@@ -543,7 +576,7 @@ static bool sun6i_spi_can_dma(struct spi_master *master, ...@@ -543,7 +576,7 @@ static bool sun6i_spi_can_dma(struct spi_master *master,
* the fifo length we can just fill the fifo and wait for a single * the fifo length we can just fill the fifo and wait for a single
* irq, so don't bother setting up dma * irq, so don't bother setting up dma
*/ */
return xfer->len > sspi->fifo_depth; return xfer->len > sspi->cfg->fifo_depth;
} }
static int sun6i_spi_probe(struct platform_device *pdev) static int sun6i_spi_probe(struct platform_device *pdev)
...@@ -582,7 +615,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) ...@@ -582,7 +615,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
} }
sspi->master = master; sspi->master = master;
sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev); sspi->cfg = of_device_get_match_data(&pdev->dev);
master->max_speed_hz = 100 * 1000 * 1000; master->max_speed_hz = 100 * 1000 * 1000;
master->min_speed_hz = 3 * 1000; master->min_speed_hz = 3 * 1000;
...@@ -695,9 +728,27 @@ static void sun6i_spi_remove(struct platform_device *pdev) ...@@ -695,9 +728,27 @@ static void sun6i_spi_remove(struct platform_device *pdev)
dma_release_channel(master->dma_rx); dma_release_channel(master->dma_rx);
} }
static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
.fifo_depth = SUN6I_FIFO_DEPTH,
.has_clk_ctl = true,
};
static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
.fifo_depth = SUN8I_FIFO_DEPTH,
.has_clk_ctl = true,
};
static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = {
.fifo_depth = SUN8I_FIFO_DEPTH,
};
static const struct of_device_id sun6i_spi_match[] = { static const struct of_device_id sun6i_spi_match[] = {
{ .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH }, { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg },
{ .compatible = "allwinner,sun8i-h3-spi", .data = (void *)SUN8I_FIFO_DEPTH }, { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_cfg },
{
.compatible = "allwinner,sun50i-r329-spi",
.data = &sun50i_r329_spi_cfg
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, sun6i_spi_match); MODULE_DEVICE_TABLE(of, sun6i_spi_match);
......
...@@ -241,7 +241,7 @@ static struct i2c_driver spi_xcomm_driver = { ...@@ -241,7 +241,7 @@ static struct i2c_driver spi_xcomm_driver = {
.name = "spi-xcomm", .name = "spi-xcomm",
}, },
.id_table = spi_xcomm_ids, .id_table = spi_xcomm_ids,
.probe_new = spi_xcomm_probe, .probe = spi_xcomm_probe,
}; };
module_i2c_driver(spi_xcomm_driver); module_i2c_driver(spi_xcomm_driver);
......
...@@ -64,7 +64,8 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256); ...@@ -64,7 +64,8 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \ | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
| SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \ | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
| SPI_RX_QUAD | SPI_RX_OCTAL \ | SPI_RX_QUAD | SPI_RX_OCTAL \
| SPI_RX_CPHA_FLIP) | SPI_RX_CPHA_FLIP | SPI_3WIRE_HIZ \
| SPI_MOSI_IDLE_LOW)
struct spidev_data { struct spidev_data {
dev_t devt; dev_t devt;
......
...@@ -36,6 +36,7 @@ struct s3c64xx_spi_info { ...@@ -36,6 +36,7 @@ struct s3c64xx_spi_info {
int src_clk_nr; int src_clk_nr;
int num_cs; int num_cs;
bool no_cs; bool no_cs;
bool polling;
int (*cfg_gpio)(void); int (*cfg_gpio)(void);
}; };
......
...@@ -1261,6 +1261,23 @@ static inline bool spi_is_bpw_supported(struct spi_device *spi, u32 bpw) ...@@ -1261,6 +1261,23 @@ static inline bool spi_is_bpw_supported(struct spi_device *spi, u32 bpw)
return false; return false;
} }
/**
* spi_controller_xfer_timeout - Compute a suitable timeout value
* @ctlr: SPI device
* @xfer: Transfer descriptor
*
* Compute a relevant timeout value for the given transfer. We derive the time
* that it would take on a single data line and take twice this amount of time
* with a minimum of 500ms to avoid false positives on loaded systems.
*
* Returns: Transfer timeout value in milliseconds.
*/
static inline unsigned int spi_controller_xfer_timeout(struct spi_controller *ctlr,
struct spi_transfer *xfer)
{
return max(xfer->len * 8 * 2 / (xfer->speed_hz / 1000), 500U);
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* SPI transfer replacement methods which make use of spi_res */ /* SPI transfer replacement methods which make use of spi_res */
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */ #define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */
#define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */ #define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */
#define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */ #define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */
#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave mosi line low when idle */
/* /*
* All the bits defined above should be covered by SPI_MODE_USER_MASK. * All the bits defined above should be covered by SPI_MODE_USER_MASK.
...@@ -37,6 +38,6 @@ ...@@ -37,6 +38,6 @@
* These bits must not overlap. A static assert check should make sure of that. * These bits must not overlap. A static assert check should make sure of that.
* If adding extra bits, make sure to increase the bit index below as well. * If adding extra bits, make sure to increase the bit index below as well.
*/ */
#define SPI_MODE_USER_MASK (_BITUL(17) - 1) #define SPI_MODE_USER_MASK (_BITUL(18) - 1)
#endif /* _UAPI_SPI_H */ #endif /* _UAPI_SPI_H */
...@@ -172,28 +172,37 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) ...@@ -172,28 +172,37 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
static void print_usage(const char *prog) static void print_usage(const char *prog)
{ {
printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog); printf("Usage: %s [-2348CDFHILMNORSZbdilopsv]\n", prog);
puts(" -D --device device to use (default /dev/spidev1.1)\n" puts("general device settings:\n"
" -s --speed max speed (Hz)\n" " -D --device device to use (default /dev/spidev1.1)\n"
" -d --delay delay (usec)\n" " -s --speed max speed (Hz)\n"
" -b --bpw bits per word\n" " -d --delay delay (usec)\n"
" -i --input input data from a file (e.g. \"test.bin\")\n" " -l --loop loopback\n"
" -o --output output data to a file (e.g. \"results.bin\")\n" "spi mode:\n"
" -l --loop loopback\n" " -H --cpha clock phase\n"
" -H --cpha clock phase\n" " -O --cpol clock polarity\n"
" -O --cpol clock polarity\n" " -F --rx-cpha-flip flip CPHA on Rx only xfer\n"
" -L --lsb least significant bit first\n" "number of wires for transmission:\n"
" -C --cs-high chip select active high\n" " -2 --dual dual transfer\n"
" -3 --3wire SI/SO signals shared\n" " -4 --quad quad transfer\n"
" -v --verbose Verbose (show tx buffer)\n" " -8 --octal octal transfer\n"
" -p Send data (e.g. \"1234\\xde\\xad\")\n" " -3 --3wire SI/SO signals shared\n"
" -N --no-cs no chip select\n" " -Z --3wire-hiz high impedance turnaround\n"
" -R --ready slave pulls low to pause\n" "data:\n"
" -2 --dual dual transfer\n" " -i --input input data from a file (e.g. \"test.bin\")\n"
" -4 --quad quad transfer\n" " -o --output output data to a file (e.g. \"results.bin\")\n"
" -8 --octal octal transfer\n" " -p Send data (e.g. \"1234\\xde\\xad\")\n"
" -S --size transfer size\n" " -S --size transfer size\n"
" -I --iter iterations\n"); " -I --iter iterations\n"
"additional parameters:\n"
" -b --bpw bits per word\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -N --no-cs no chip select\n"
" -R --ready slave pulls low to pause\n"
" -M --mosi-idle-low leave mosi line low when idle\n"
"misc:\n"
" -v --verbose Verbose (show tx buffer)\n");
exit(1); exit(1);
} }
...@@ -201,31 +210,34 @@ static void parse_opts(int argc, char *argv[]) ...@@ -201,31 +210,34 @@ static void parse_opts(int argc, char *argv[])
{ {
while (1) { while (1) {
static const struct option lopts[] = { static const struct option lopts[] = {
{ "device", 1, 0, 'D' }, { "device", 1, 0, 'D' },
{ "speed", 1, 0, 's' }, { "speed", 1, 0, 's' },
{ "delay", 1, 0, 'd' }, { "delay", 1, 0, 'd' },
{ "bpw", 1, 0, 'b' }, { "loop", 0, 0, 'l' },
{ "input", 1, 0, 'i' }, { "cpha", 0, 0, 'H' },
{ "output", 1, 0, 'o' }, { "cpol", 0, 0, 'O' },
{ "loop", 0, 0, 'l' }, { "rx-cpha-flip", 0, 0, 'F' },
{ "cpha", 0, 0, 'H' }, { "dual", 0, 0, '2' },
{ "cpol", 0, 0, 'O' }, { "quad", 0, 0, '4' },
{ "lsb", 0, 0, 'L' }, { "octal", 0, 0, '8' },
{ "cs-high", 0, 0, 'C' }, { "3wire", 0, 0, '3' },
{ "3wire", 0, 0, '3' }, { "3wire-hiz", 0, 0, 'Z' },
{ "no-cs", 0, 0, 'N' }, { "input", 1, 0, 'i' },
{ "ready", 0, 0, 'R' }, { "output", 1, 0, 'o' },
{ "dual", 0, 0, '2' }, { "size", 1, 0, 'S' },
{ "verbose", 0, 0, 'v' }, { "iter", 1, 0, 'I' },
{ "quad", 0, 0, '4' }, { "bpw", 1, 0, 'b' },
{ "octal", 0, 0, '8' }, { "lsb", 0, 0, 'L' },
{ "size", 1, 0, 'S' }, { "cs-high", 0, 0, 'C' },
{ "iter", 1, 0, 'I' }, { "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
{ "mosi-idle-low", 0, 0, 'M' },
{ "verbose", 0, 0, 'v' },
{ NULL, 0, 0, 0 }, { NULL, 0, 0, 0 },
}; };
int c; int c;
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR248p:vS:I:", c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3ZFMNR248p:vS:I:",
lopts, NULL); lopts, NULL);
if (c == -1) if (c == -1)
...@@ -268,6 +280,15 @@ static void parse_opts(int argc, char *argv[]) ...@@ -268,6 +280,15 @@ static void parse_opts(int argc, char *argv[])
case '3': case '3':
mode |= SPI_3WIRE; mode |= SPI_3WIRE;
break; break;
case 'Z':
mode |= SPI_3WIRE_HIZ;
break;
case 'F':
mode |= SPI_RX_CPHA_FLIP;
break;
case 'M':
mode |= SPI_MOSI_IDLE_LOW;
break;
case 'N': case 'N':
mode |= SPI_NO_CS; mode |= SPI_NO_CS;
break; break;
......
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