Commit 4b51c747 authored by Mark Brown's avatar Mark Brown

Merge branch 'spi-4.20' into spi-next

parents 92d58fd1 0c903aaf
...@@ -53,20 +53,8 @@ Required properties: ...@@ -53,20 +53,8 @@ Required properties:
- clocks: Serial engine core clock needed by the device. - clocks: Serial engine core clock needed by the device.
Qualcomm Technologies Inc. GENI Serial Engine based SPI Controller Qualcomm Technologies Inc. GENI Serial Engine based SPI Controller
node binding is described in
Required properties: Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.txt.
- compatible: Must contain "qcom,geni-spi".
- reg: Must contain SPI register location and length.
- interrupts: Must contain SPI controller interrupts.
- clock-names: Must contain "se".
- clocks: Serial engine core clock needed by the device.
- spi-max-frequency: Specifies maximum SPI clock frequency, units - Hz.
- #address-cells: Must be <1> to define a chip select address on
the SPI bus.
- #size-cells: Must be <0>.
SPI slave nodes must be children of the SPI master node and conform to SPI bus
binding as described in Documentation/devicetree/bindings/spi/spi-bus.txt.
Example: Example:
geniqup@8c0000 { geniqup@8c0000 {
...@@ -103,17 +91,4 @@ Example: ...@@ -103,17 +91,4 @@ Example:
pinctrl-1 = <&qup_1_uart_3_sleep>; pinctrl-1 = <&qup_1_uart_3_sleep>;
}; };
spi0: spi@a84000 {
compatible = "qcom,geni-spi";
reg = <0xa84000 0x4000>;
interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "se";
clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&qup_1_spi_2_active>;
pinctrl-1 = <&qup_1_spi_2_sleep>;
spi-max-frequency = <19200000>;
#address-cells = <1>;
#size-cells = <0>;
};
} }
GENI based Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI)
The QUP v3 core is a GENI based AHB slave that provides a common data path
(an output FIFO and an input FIFO) for serial peripheral interface (SPI)
mini-core.
SPI in master mode supports up to 50MHz, up to four chip selects, programmable
data path from 4 bits to 32 bits and numerous protocol variants.
Required properties:
- compatible: Must contain "qcom,geni-spi".
- reg: Must contain SPI register location and length.
- interrupts: Must contain SPI controller interrupts.
- clock-names: Must contain "se".
- clocks: Serial engine core clock needed by the device.
- #address-cells: Must be <1> to define a chip select address on
the SPI bus.
- #size-cells: Must be <0>.
SPI Controller nodes must be child of GENI based Qualcomm Universal
Peripharal. Please refer GENI based QUP wrapper controller node bindings
described in Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt.
SPI slave nodes must be children of the SPI master node and conform to SPI bus
binding as described in Documentation/devicetree/bindings/spi/spi-bus.txt.
Example:
spi0: spi@a84000 {
compatible = "qcom,geni-spi";
reg = <0xa84000 0x4000>;
interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "se";
clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&qup_1_spi_2_active>;
pinctrl-1 = <&qup_1_spi_2_sleep>;
#address-cells = <1>;
#size-cells = <0>;
};
Qualcomm Quad Serial Peripheral Interface (QSPI)
The QSPI controller allows SPI protocol communication in single, dual, or quad
wire transmission modes for read/write access to slaves such as NOR flash.
Required properties:
- compatible: An SoC specific identifier followed by "qcom,qspi-v1", such as
"qcom,sdm845-qspi", "qcom,qspi-v1"
- reg: Should contain the base register location and length.
- interrupts: Interrupt number used by the controller.
- clocks: Should contain the core and AHB clock.
- clock-names: Should be "core" for core clock and "iface" for AHB clock.
SPI slave nodes must be children of the SPI master node and can contain
properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
qspi: spi@88df000 {
compatible = "qcom,sdm845-qspi", "qcom,qspi-v1";
reg = <0x88df000 0x600>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "iface", "core";
clocks = <&gcc GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
<&gcc GCC_QSPI_CORE_CLK>;
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <25000000>;
spi-tx-bus-width = <2>;
spi-rx-bus-width = <2>;
};
};
...@@ -2,7 +2,9 @@ Renesas MSIOF spi controller ...@@ -2,7 +2,9 @@ Renesas MSIOF spi controller
Required properties: Required properties:
- compatible : "renesas,msiof-r8a7743" (RZ/G1M) - compatible : "renesas,msiof-r8a7743" (RZ/G1M)
"renesas,msiof-r8a7744" (RZ/G1N)
"renesas,msiof-r8a7745" (RZ/G1E) "renesas,msiof-r8a7745" (RZ/G1E)
"renesas,msiof-r8a774a1" (RZ/G2M)
"renesas,msiof-r8a7790" (R-Car H2) "renesas,msiof-r8a7790" (R-Car H2)
"renesas,msiof-r8a7791" (R-Car M2-W) "renesas,msiof-r8a7791" (R-Car M2-W)
"renesas,msiof-r8a7792" (R-Car V2H) "renesas,msiof-r8a7792" (R-Car V2H)
...@@ -11,10 +13,14 @@ Required properties: ...@@ -11,10 +13,14 @@ Required properties:
"renesas,msiof-r8a7795" (R-Car H3) "renesas,msiof-r8a7795" (R-Car H3)
"renesas,msiof-r8a7796" (R-Car M3-W) "renesas,msiof-r8a7796" (R-Car M3-W)
"renesas,msiof-r8a77965" (R-Car M3-N) "renesas,msiof-r8a77965" (R-Car M3-N)
"renesas,msiof-r8a77970" (R-Car V3M)
"renesas,msiof-r8a77980" (R-Car V3H)
"renesas,msiof-r8a77990" (R-Car E3)
"renesas,msiof-r8a77995" (R-Car D3)
"renesas,msiof-sh73a0" (SH-Mobile AG5) "renesas,msiof-sh73a0" (SH-Mobile AG5)
"renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device) "renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device)
"renesas,rcar-gen2-msiof" (generic R-Car Gen2 and RZ/G1 compatible device) "renesas,rcar-gen2-msiof" (generic R-Car Gen2 and RZ/G1 compatible device)
"renesas,rcar-gen3-msiof" (generic R-Car Gen3 compatible device) "renesas,rcar-gen3-msiof" (generic R-Car Gen3 and RZ/G2 compatible device)
"renesas,sh-msiof" (deprecated) "renesas,sh-msiof" (deprecated)
When compatible with the generic version, nodes When compatible with the generic version, nodes
......
...@@ -2,7 +2,7 @@ Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface. ...@@ -2,7 +2,7 @@ Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface.
Required properties: Required properties:
- compatible : "snps,dw-apb-ssi" or "mscc,<soc>-spi", where soc is "ocelot" or - compatible : "snps,dw-apb-ssi" or "mscc,<soc>-spi", where soc is "ocelot" or
"jaguar2" "jaguar2", or "amazon,alpine-dw-apb-ssi"
- reg : The register base for the controller. For "mscc,<soc>-spi", a second - reg : The register base for the controller. For "mscc,<soc>-spi", a second
register set is required (named ICPU_CFG:SPI_MST) register set is required (named ICPU_CFG:SPI_MST)
- interrupts : One interrupt, used by the controller. - interrupts : One interrupt, used by the controller.
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
Required properties: Required properties:
- compatible : - compatible :
- "fsl,imx7ulp-spi" for LPSPI compatible with the one integrated on i.MX7ULP soc - "fsl,imx7ulp-spi" for LPSPI compatible with the one integrated on i.MX7ULP soc
- "fsl,imx8qxp-spi" for LPSPI compatible with the one integrated on i.MX8QXP soc
- reg : address and length of the lpspi master registers - reg : address and length of the lpspi master registers
- interrupts : lpspi interrupt - interrupts : lpspi interrupt
- clocks : lpspi clock specifier - clocks : lpspi clock specifier
......
PXA2xx SSP SPI Controller
Required properties:
- compatible: Must be "marvell,mmp2-ssp".
- reg: Offset and length of the device's register set.
- interrupts: Should be the interrupt number.
- clocks: Should contain a single entry describing the clock input.
- #address-cells: Number of cells required to define a chip select address.
- #size-cells: Should be zero.
Optional properties:
- cs-gpios: list of GPIO chip selects. See the SPI bus bindings,
Documentation/devicetree/bindings/spi/spi-bus.txt
Child nodes represent devices on the SPI bus
See ../spi/spi-bus.txt
Example:
ssp1: spi@d4035000 {
compatible = "marvell,mmp2-ssp";
reg = <0xd4035000 0x1000>;
clocks = <&soc_clocks MMP2_CLK_SSP0>;
interrupts = <0>;
};
...@@ -3,7 +3,7 @@ Device tree configuration for Renesas RSPI/QSPI driver ...@@ -3,7 +3,7 @@ Device tree configuration for Renesas RSPI/QSPI driver
Required properties: Required properties:
- compatible : For Renesas Serial Peripheral Interface on legacy SH: - compatible : For Renesas Serial Peripheral Interface on legacy SH:
"renesas,rspi-<soctype>", "renesas,rspi" as fallback. "renesas,rspi-<soctype>", "renesas,rspi" as fallback.
For Renesas Serial Peripheral Interface on RZ/A1H: For Renesas Serial Peripheral Interface on RZ/A:
"renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback. "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
For Quad Serial Peripheral Interface on R-Car Gen2 and For Quad Serial Peripheral Interface on R-Car Gen2 and
RZ/G1 devices: RZ/G1 devices:
...@@ -11,7 +11,9 @@ Required properties: ...@@ -11,7 +11,9 @@ Required properties:
Examples with soctypes are: Examples with soctypes are:
- "renesas,rspi-sh7757" (SH) - "renesas,rspi-sh7757" (SH)
- "renesas,rspi-r7s72100" (RZ/A1H) - "renesas,rspi-r7s72100" (RZ/A1H)
- "renesas,rspi-r7s9210" (RZ/A2)
- "renesas,qspi-r8a7743" (RZ/G1M) - "renesas,qspi-r8a7743" (RZ/G1M)
- "renesas,qspi-r8a7744" (RZ/G1N)
- "renesas,qspi-r8a7745" (RZ/G1E) - "renesas,qspi-r8a7745" (RZ/G1E)
- "renesas,qspi-r8a7790" (R-Car H2) - "renesas,qspi-r8a7790" (R-Car H2)
- "renesas,qspi-r8a7791" (R-Car M2-W) - "renesas,qspi-r8a7791" (R-Car M2-W)
......
Binding for MTK SPI Slave controller
Required properties:
- compatible: should be one of the following.
- mediatek,mt2712-spi-slave: for mt2712 platforms
- reg: Address and length of the register set for the device.
- interrupts: Should contain spi interrupt.
- clocks: phandles to input clocks.
It's clock gate, and should be <&infracfg CLK_INFRA_AO_SPI1>.
- clock-names: should be "spi" for the clock gate.
Optional properties:
- assigned-clocks: it's mux clock, should be <&topckgen CLK_TOP_SPISLV_SEL>.
- assigned-clock-parents: parent of mux clock.
It's PLL, and should be one of the following.
- <&topckgen CLK_TOP_UNIVPLL1_D2>: specify parent clock 312MHZ.
It's the default one.
- <&topckgen CLK_TOP_UNIVPLL1_D4>: specify parent clock 156MHZ.
- <&topckgen CLK_TOP_UNIVPLL2_D4>: specify parent clock 104MHZ.
- <&topckgen CLK_TOP_UNIVPLL1_D8>: specify parent clock 78MHZ.
Example:
- SoC Specific Portion:
spis1: spi@10013000 {
compatible = "mediatek,mt2712-spi-slave";
reg = <0 0x10013000 0 0x100>;
interrupts = <GIC_SPI 283 IRQ_TYPE_LEVEL_LOW>;
clocks = <&infracfg CLK_INFRA_AO_SPI1>;
clock-names = "spi";
assigned-clocks = <&topckgen CLK_TOP_SPISLV_SEL>;
assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>;
};
Spreadtrum SPI Controller
Required properties:
- compatible: Should be "sprd,sc9860-spi".
- reg: Offset and length of SPI controller register space.
- interrupts: Should contain SPI interrupt.
- clock-names: Should contain following entries:
"spi" for SPI clock,
"source" for SPI source (parent) clock,
"enable" for SPI module enable clock.
- clocks: List of clock input name strings sorted in the same order
as the clock-names property.
- #address-cells: The number of cells required to define a chip select
address on the SPI bus. Should be set to 1.
- #size-cells: Should be set to 0.
Example:
spi0: spi@70a00000{
compatible = "sprd,sc9860-spi";
reg = <0 0x70a00000 0 0x1000>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "spi", "source","enable";
clocks = <&clk_spi0>, <&ext_26m>, <&clk_ap_apb_gates 5>;
#address-cells = <1>;
#size-cells = <0>;
};
* STMicroelectronics Quad Serial Peripheral Interface(QSPI)
Required properties:
- compatible: should be "st,stm32f469-qspi"
- reg: the first contains the register location and length.
the second contains the memory mapping address and length
- reg-names: should contain the reg names "qspi" "qspi_mm"
- interrupts: should contain the interrupt for the device
- clocks: the phandle of the clock needed by the QSPI controller
- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
Optional properties:
- resets: must contain the phandle to the reset controller.
A spi flash (NOR/NAND) must be a child of spi node and could have some
properties. Also see jedec,spi-nor.txt.
Required properties:
- reg: chip-Select number (QSPI controller may connect 2 flashes)
- spi-max-frequency: max frequency of spi bus
Optional property:
- spi-rx-bus-width: see ./spi-bus.txt for the description
Example:
qspi: spi@a0001000 {
compatible = "st,stm32f469-qspi";
reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
reg-names = "qspi", "qspi_mm";
interrupts = <91>;
resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_qspi0>;
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-rx-bus-width = <4>;
spi-max-frequency = <108000000>;
...
};
};
...@@ -513,7 +513,7 @@ EXPORT_SYMBOL(geni_se_resources_on); ...@@ -513,7 +513,7 @@ EXPORT_SYMBOL(geni_se_resources_on);
*/ */
int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
{ {
unsigned long freq = 0; long freq = 0;
int i; int i;
if (se->clk_perf_tbl) { if (se->clk_perf_tbl) {
...@@ -529,7 +529,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) ...@@ -529,7 +529,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) {
freq = clk_round_rate(se->clk, freq + 1); freq = clk_round_rate(se->clk, freq + 1);
if (!freq || freq == se->clk_perf_tbl[i - 1]) if (freq <= 0 || freq == se->clk_perf_tbl[i - 1])
break; break;
se->clk_perf_tbl[i] = freq; se->clk_perf_tbl[i] = freq;
} }
...@@ -544,16 +544,17 @@ EXPORT_SYMBOL(geni_se_clk_tbl_get); ...@@ -544,16 +544,17 @@ EXPORT_SYMBOL(geni_se_clk_tbl_get);
* @se: Pointer to the concerned serial engine. * @se: Pointer to the concerned serial engine.
* @req_freq: Requested clock frequency. * @req_freq: Requested clock frequency.
* @index: Index of the resultant frequency in the table. * @index: Index of the resultant frequency in the table.
* @res_freq: Resultant frequency which matches or is closer to the * @res_freq: Resultant frequency of the source clock.
* requested frequency.
* @exact: Flag to indicate exact multiple requirement of the requested * @exact: Flag to indicate exact multiple requirement of the requested
* frequency. * frequency.
* *
* This function is called by the protocol drivers to determine the matching * This function is called by the protocol drivers to determine the best match
* or exact multiple of the requested frequency, as provided by the serial * of the requested frequency as provided by the serial engine clock in order
* engine clock in order to meet the performance requirements. If there is * to meet the performance requirements.
* no matching or exact multiple of the requested frequency found, then it *
* selects the closest floor frequency, if exact flag is not set. * If we return success:
* - if @exact is true then @res_freq / <an_integer> == @req_freq
* - if @exact is false then @res_freq / <an_integer> <= @req_freq
* *
* Return: 0 on success, standard Linux error codes on failure. * Return: 0 on success, standard Linux error codes on failure.
*/ */
...@@ -564,6 +565,9 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, ...@@ -564,6 +565,9 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
unsigned long *tbl; unsigned long *tbl;
int num_clk_levels; int num_clk_levels;
int i; int i;
unsigned long best_delta;
unsigned long new_delta;
unsigned int divider;
num_clk_levels = geni_se_clk_tbl_get(se, &tbl); num_clk_levels = geni_se_clk_tbl_get(se, &tbl);
if (num_clk_levels < 0) if (num_clk_levels < 0)
...@@ -572,18 +576,21 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, ...@@ -572,18 +576,21 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
if (num_clk_levels == 0) if (num_clk_levels == 0)
return -EINVAL; return -EINVAL;
*res_freq = 0; best_delta = ULONG_MAX;
for (i = 0; i < num_clk_levels; i++) { for (i = 0; i < num_clk_levels; i++) {
if (!(tbl[i] % req_freq)) { divider = DIV_ROUND_UP(tbl[i], req_freq);
new_delta = req_freq - tbl[i] / divider;
if (new_delta < best_delta) {
/* We have a new best! */
*index = i; *index = i;
*res_freq = tbl[i]; *res_freq = tbl[i];
return 0;
}
if (!(*res_freq) || ((tbl[i] > *res_freq) && /* If the new best is exact then we're done */
(tbl[i] < req_freq))) { if (new_delta == 0)
*index = i; return 0;
*res_freq = tbl[i];
/* Record how close we got */
best_delta = new_delta;
} }
} }
......
...@@ -129,7 +129,7 @@ config SPI_BCM63XX ...@@ -129,7 +129,7 @@ config SPI_BCM63XX
config SPI_BCM63XX_HSSPI config SPI_BCM63XX_HSSPI
tristate "Broadcom BCM63XX HS SPI controller driver" tristate "Broadcom BCM63XX HS SPI controller driver"
depends on BCM63XX || COMPILE_TEST depends on BCM63XX || ARCH_BCM_63XX || COMPILE_TEST
help help
This enables support for the High Speed SPI controller present on This enables support for the High Speed SPI controller present on
newer Broadcom BCM63XX SoCs. newer Broadcom BCM63XX SoCs.
...@@ -520,6 +520,12 @@ config SPI_RSPI ...@@ -520,6 +520,12 @@ config SPI_RSPI
help help
SPI driver for Renesas RSPI and QSPI blocks. SPI driver for Renesas RSPI and QSPI blocks.
config SPI_QCOM_QSPI
tristate "QTI QSPI controller"
depends on ARCH_QCOM
help
QSPI(Quad SPI) driver for Qualcomm QSPI controller.
config SPI_QUP config SPI_QUP
tristate "Qualcomm SPI controller with QUP interface" tristate "Qualcomm SPI controller with QUP interface"
depends on ARCH_QCOM || (ARM && COMPILE_TEST) depends on ARCH_QCOM || (ARM && COMPILE_TEST)
...@@ -533,6 +539,18 @@ config SPI_QUP ...@@ -533,6 +539,18 @@ config SPI_QUP
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called spi_qup. will be called spi_qup.
config SPI_QCOM_GENI
tristate "Qualcomm GENI based SPI controller"
depends on QCOM_GENI_SE
help
This driver supports GENI serial engine based SPI controller in
master mode on the Qualcomm Technologies Inc.'s SoCs. If you say
yes to this option, support will be included for the built-in SPI
interface on the Qualcomm Technologies Inc.'s SoCs.
This driver can also be built as a module. If so, the module
will be called spi-geni-qcom.
config SPI_S3C24XX config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI" tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C24XX depends on ARCH_S3C24XX
...@@ -596,6 +614,22 @@ config SPI_SIRF ...@@ -596,6 +614,22 @@ config SPI_SIRF
help help
SPI driver for CSR SiRFprimaII SoCs SPI driver for CSR SiRFprimaII SoCs
config SPI_SLAVE_MT27XX
tristate "MediaTek SPI slave device"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on SPI_SLAVE
help
This selects the MediaTek(R) SPI slave device driver.
If you want to use MediaTek(R) SPI slave interface,
say Y or M here.If you are not sure, say N.
SPI slave drivers for Mediatek MT27XX series ARM SoCs.
config SPI_SPRD
tristate "Spreadtrum SPI controller"
depends on ARCH_SPRD || COMPILE_TEST
help
SPI driver for Spreadtrum SoCs.
config SPI_SPRD_ADI config SPI_SPRD_ADI
tristate "Spreadtrum ADI controller" tristate "Spreadtrum ADI controller"
depends on ARCH_SPRD || COMPILE_TEST depends on ARCH_SPRD || COMPILE_TEST
...@@ -613,6 +647,15 @@ config SPI_STM32 ...@@ -613,6 +647,15 @@ config SPI_STM32
is not available, the driver automatically falls back to is not available, the driver automatically falls back to
PIO mode. PIO mode.
config SPI_STM32_QSPI
tristate "STMicroelectronics STM32 QUAD SPI controller"
depends on ARCH_STM32 || COMPILE_TEST
depends on OF
help
This enables support for the Quad SPI controller in master mode.
This driver does not support generic SPI. The implementation only
supports spi-mem interface.
config SPI_ST_SSC4 config SPI_ST_SSC4
tristate "STMicroelectronics SPI SSC-based driver" tristate "STMicroelectronics SPI SSC-based driver"
depends on ARCH_STI || COMPILE_TEST depends on ARCH_STI || COMPILE_TEST
......
...@@ -74,6 +74,8 @@ obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o ...@@ -74,6 +74,8 @@ obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o
obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
...@@ -88,8 +90,11 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o ...@@ -88,8 +90,11 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_SLAVE_MT27XX) += spi-slave-mt27xx.o
obj-$(CONFIG_SPI_SPRD) += spi-sprd.o
obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o
obj-$(CONFIG_SPI_STM32) += spi-stm32.o obj-$(CONFIG_SPI_STM32) += spi-stm32.o
obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o
obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
......
...@@ -1767,10 +1767,8 @@ static int atmel_spi_suspend(struct device *dev) ...@@ -1767,10 +1767,8 @@ static int atmel_spi_suspend(struct device *dev)
/* Stop the queue running */ /* Stop the queue running */
ret = spi_master_suspend(master); ret = spi_master_suspend(master);
if (ret) { if (ret)
dev_warn(dev, "cannot suspend master\n");
return ret; return ret;
}
if (!pm_runtime_suspended(dev)) if (!pm_runtime_suspended(dev))
atmel_spi_runtime_suspend(dev); atmel_spi_runtime_suspend(dev);
...@@ -1799,11 +1797,7 @@ static int atmel_spi_resume(struct device *dev) ...@@ -1799,11 +1797,7 @@ static int atmel_spi_resume(struct device *dev)
} }
/* Start the queue running */ /* Start the queue running */
ret = spi_master_resume(master); return spi_master_resume(master);
if (ret)
dev_err(dev, "problem starting queue (%d)\n", ret);
return ret;
} }
#endif #endif
......
...@@ -101,6 +101,7 @@ struct bcm63xx_hsspi { ...@@ -101,6 +101,7 @@ struct bcm63xx_hsspi {
struct platform_device *pdev; struct platform_device *pdev;
struct clk *clk; struct clk *clk;
struct clk *pll_clk;
void __iomem *regs; void __iomem *regs;
u8 __iomem *fifo; u8 __iomem *fifo;
...@@ -332,7 +333,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) ...@@ -332,7 +333,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
struct resource *res_mem; struct resource *res_mem;
void __iomem *regs; void __iomem *regs;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct clk *clk; struct clk *clk, *pll_clk = NULL;
int irq, ret; int irq, ret;
u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS; u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
...@@ -358,7 +359,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) ...@@ -358,7 +359,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
rate = clk_get_rate(clk); rate = clk_get_rate(clk);
if (!rate) { if (!rate) {
struct clk *pll_clk = devm_clk_get(dev, "pll"); pll_clk = devm_clk_get(dev, "pll");
if (IS_ERR(pll_clk)) { if (IS_ERR(pll_clk)) {
ret = PTR_ERR(pll_clk); ret = PTR_ERR(pll_clk);
...@@ -373,19 +374,20 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) ...@@ -373,19 +374,20 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
clk_disable_unprepare(pll_clk); clk_disable_unprepare(pll_clk);
if (!rate) { if (!rate) {
ret = -EINVAL; ret = -EINVAL;
goto out_disable_clk; goto out_disable_pll_clk;
} }
} }
master = spi_alloc_master(&pdev->dev, sizeof(*bs)); master = spi_alloc_master(&pdev->dev, sizeof(*bs));
if (!master) { if (!master) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_disable_clk; goto out_disable_pll_clk;
} }
bs = spi_master_get_devdata(master); bs = spi_master_get_devdata(master);
bs->pdev = pdev; bs->pdev = pdev;
bs->clk = clk; bs->clk = clk;
bs->pll_clk = pll_clk;
bs->regs = regs; bs->regs = regs;
bs->speed_hz = rate; bs->speed_hz = rate;
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0)); bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
...@@ -440,6 +442,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) ...@@ -440,6 +442,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
out_put_master: out_put_master:
spi_master_put(master); spi_master_put(master);
out_disable_pll_clk:
clk_disable_unprepare(pll_clk);
out_disable_clk: out_disable_clk:
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
return ret; return ret;
...@@ -453,6 +457,7 @@ static int bcm63xx_hsspi_remove(struct platform_device *pdev) ...@@ -453,6 +457,7 @@ static int bcm63xx_hsspi_remove(struct platform_device *pdev)
/* reset the hardware and block queue progress */ /* reset the hardware and block queue progress */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG); __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk); clk_disable_unprepare(bs->clk);
return 0; return 0;
...@@ -465,6 +470,7 @@ static int bcm63xx_hsspi_suspend(struct device *dev) ...@@ -465,6 +470,7 @@ static int bcm63xx_hsspi_suspend(struct device *dev)
struct bcm63xx_hsspi *bs = spi_master_get_devdata(master); struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
spi_master_suspend(master); spi_master_suspend(master);
clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk); clk_disable_unprepare(bs->clk);
return 0; return 0;
...@@ -480,6 +486,12 @@ static int bcm63xx_hsspi_resume(struct device *dev) ...@@ -480,6 +486,12 @@ static int bcm63xx_hsspi_resume(struct device *dev)
if (ret) if (ret)
return ret; return ret;
if (bs->pll_clk) {
ret = clk_prepare_enable(bs->pll_clk);
if (ret)
return ret;
}
spi_master_resume(master); spi_master_resume(master);
return 0; return 0;
......
...@@ -208,13 +208,11 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits) ...@@ -208,13 +208,11 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits)
static void davinci_spi_chipselect(struct spi_device *spi, int value) static void davinci_spi_chipselect(struct spi_device *spi, int value)
{ {
struct davinci_spi *dspi; struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata;
struct davinci_spi_config *spicfg = spi->controller_data; struct davinci_spi_config *spicfg = spi->controller_data;
u8 chip_sel = spi->chip_select; u8 chip_sel = spi->chip_select;
u16 spidat1 = CS_DEFAULT; u16 spidat1 = CS_DEFAULT;
dspi = spi_master_get_devdata(spi->master); dspi = spi_master_get_devdata(spi->master);
pdata = &dspi->pdata;
/* program delay transfers if tx_delay is non zero */ /* program delay transfers if tx_delay is non zero */
if (spicfg && spicfg->wdelay) if (spicfg && spicfg->wdelay)
...@@ -232,7 +230,8 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) ...@@ -232,7 +230,8 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
!(spi->mode & SPI_CS_HIGH)); !(spi->mode & SPI_CS_HIGH));
} else { } else {
if (value == BITBANG_CS_ACTIVE) { if (value == BITBANG_CS_ACTIVE) {
spidat1 |= SPIDAT1_CSHOLD_MASK; if (!(spi->mode & SPI_CS_WORD))
spidat1 |= SPIDAT1_CSHOLD_MASK;
spidat1 &= ~(0x1 << chip_sel); spidat1 &= ~(0x1 << chip_sel);
} }
} }
...@@ -421,26 +420,17 @@ static int davinci_spi_setup(struct spi_device *spi) ...@@ -421,26 +420,17 @@ static int davinci_spi_setup(struct spi_device *spi)
{ {
int retval = 0; int retval = 0;
struct davinci_spi *dspi; struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata;
struct spi_master *master = spi->master; struct spi_master *master = spi->master;
struct device_node *np = spi->dev.of_node; struct device_node *np = spi->dev.of_node;
bool internal_cs = true; bool internal_cs = true;
dspi = spi_master_get_devdata(spi->master); dspi = spi_master_get_devdata(spi->master);
pdata = &dspi->pdata;
if (!(spi->mode & SPI_NO_CS)) { if (!(spi->mode & SPI_NO_CS)) {
if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) { if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) {
retval = gpio_direction_output( retval = gpio_direction_output(
spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
internal_cs = false; internal_cs = false;
} else if (pdata->chip_sel &&
spi->chip_select < pdata->num_chipselect &&
pdata->chip_sel[spi->chip_select] != SPI_INTERN_CS) {
spi->cs_gpio = pdata->chip_sel[spi->chip_select];
retval = gpio_direction_output(
spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
internal_cs = false;
} }
if (retval) { if (retval) {
...@@ -449,8 +439,9 @@ static int davinci_spi_setup(struct spi_device *spi) ...@@ -449,8 +439,9 @@ static int davinci_spi_setup(struct spi_device *spi)
return retval; return retval;
} }
if (internal_cs) if (internal_cs) {
set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
}
} }
if (spi->mode & SPI_READY) if (spi->mode & SPI_READY)
...@@ -985,7 +976,7 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -985,7 +976,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
dspi->prescaler_limit = pdata->prescaler_limit; dspi->prescaler_limit = pdata->prescaler_limit;
dspi->version = pdata->version; dspi->version = pdata->version;
dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_WORD;
if (dspi->version == SPI_VERSION_2) if (dspi->version == SPI_VERSION_2)
dspi->bitbang.flags |= SPI_READY; dspi->bitbang.flags |= SPI_READY;
......
...@@ -34,8 +34,9 @@ struct dw_spi_mmio { ...@@ -34,8 +34,9 @@ struct dw_spi_mmio {
}; };
#define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24 #define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
#define OCELOT_IF_SI_OWNER_MASK GENMASK(5, 4)
#define OCELOT_IF_SI_OWNER_OFFSET 4 #define OCELOT_IF_SI_OWNER_OFFSET 4
#define JAGUAR2_IF_SI_OWNER_OFFSET 6
#define MSCC_IF_SI_OWNER_MASK GENMASK(1, 0)
#define MSCC_IF_SI_OWNER_SISL 0 #define MSCC_IF_SI_OWNER_SISL 0
#define MSCC_IF_SI_OWNER_SIBM 1 #define MSCC_IF_SI_OWNER_SIBM 1
#define MSCC_IF_SI_OWNER_SIMC 2 #define MSCC_IF_SI_OWNER_SIMC 2
...@@ -76,7 +77,8 @@ static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable) ...@@ -76,7 +77,8 @@ static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable)
} }
static int dw_spi_mscc_init(struct platform_device *pdev, static int dw_spi_mscc_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio) struct dw_spi_mmio *dwsmmio,
const char *cpu_syscon, u32 if_si_owner_offset)
{ {
struct dw_spi_mscc *dwsmscc; struct dw_spi_mscc *dwsmscc;
struct resource *res; struct resource *res;
...@@ -92,7 +94,7 @@ static int dw_spi_mscc_init(struct platform_device *pdev, ...@@ -92,7 +94,7 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
return PTR_ERR(dwsmscc->spi_mst); return PTR_ERR(dwsmscc->spi_mst);
} }
dwsmscc->syscon = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon"); dwsmscc->syscon = syscon_regmap_lookup_by_compatible(cpu_syscon);
if (IS_ERR(dwsmscc->syscon)) if (IS_ERR(dwsmscc->syscon))
return PTR_ERR(dwsmscc->syscon); return PTR_ERR(dwsmscc->syscon);
...@@ -101,8 +103,8 @@ static int dw_spi_mscc_init(struct platform_device *pdev, ...@@ -101,8 +103,8 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
/* Select the owner of the SI interface */ /* Select the owner of the SI interface */
regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL, regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL,
OCELOT_IF_SI_OWNER_MASK, MSCC_IF_SI_OWNER_MASK << if_si_owner_offset,
MSCC_IF_SI_OWNER_SIMC << OCELOT_IF_SI_OWNER_OFFSET); MSCC_IF_SI_OWNER_SIMC << if_si_owner_offset);
dwsmmio->dws.set_cs = dw_spi_mscc_set_cs; dwsmmio->dws.set_cs = dw_spi_mscc_set_cs;
dwsmmio->priv = dwsmscc; dwsmmio->priv = dwsmscc;
...@@ -110,6 +112,28 @@ static int dw_spi_mscc_init(struct platform_device *pdev, ...@@ -110,6 +112,28 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
return 0; return 0;
} }
static int dw_spi_mscc_ocelot_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio)
{
return dw_spi_mscc_init(pdev, dwsmmio, "mscc,ocelot-cpu-syscon",
OCELOT_IF_SI_OWNER_OFFSET);
}
static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio)
{
return dw_spi_mscc_init(pdev, dwsmmio, "mscc,jaguar2-cpu-syscon",
JAGUAR2_IF_SI_OWNER_OFFSET);
}
static int dw_spi_alpine_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio)
{
dwsmmio->dws.cs_override = 1;
return 0;
}
static int dw_spi_mmio_probe(struct platform_device *pdev) static int dw_spi_mmio_probe(struct platform_device *pdev)
{ {
int (*init_func)(struct platform_device *pdev, int (*init_func)(struct platform_device *pdev,
...@@ -212,7 +236,9 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) ...@@ -212,7 +236,9 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
static const struct of_device_id dw_spi_mmio_of_match[] = { static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "snps,dw-apb-ssi", }, { .compatible = "snps,dw-apb-ssi", },
{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_init}, { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
{ /* end of table */} { /* end of table */}
}; };
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
......
...@@ -144,6 +144,8 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable) ...@@ -144,6 +144,8 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
if (!enable) if (!enable)
dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select)); dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
else if (dws->cs_override)
dw_writel(dws, DW_SPI_SER, 0);
} }
EXPORT_SYMBOL_GPL(dw_spi_set_cs); EXPORT_SYMBOL_GPL(dw_spi_set_cs);
...@@ -308,15 +310,10 @@ static int dw_spi_transfer_one(struct spi_controller *master, ...@@ -308,15 +310,10 @@ static int dw_spi_transfer_one(struct spi_controller *master,
dws->current_freq = transfer->speed_hz; dws->current_freq = transfer->speed_hz;
spi_set_clk(dws, chip->clk_div); spi_set_clk(dws, chip->clk_div);
} }
if (transfer->bits_per_word == 8) {
dws->n_bytes = 1; dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
dws->dma_width = 1; dws->dma_width = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
} else if (transfer->bits_per_word == 16) {
dws->n_bytes = 2;
dws->dma_width = 2;
} else {
return -EINVAL;
}
/* Default SPI mode is SCPOL = 0, SCPH = 0 */ /* Default SPI mode is SCPOL = 0, SCPH = 0 */
cr0 = (transfer->bits_per_word - 1) cr0 = (transfer->bits_per_word - 1)
| (chip->type << SPI_FRF_OFFSET) | (chip->type << SPI_FRF_OFFSET)
...@@ -468,6 +465,10 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws) ...@@ -468,6 +465,10 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
dws->fifo_len = (fifo == 1) ? 0 : fifo; dws->fifo_len = (fifo == 1) ? 0 : fifo;
dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len); dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
} }
/* enable HW fixup for explicit CS deselect for Amazon's alpine chip */
if (dws->cs_override)
dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);
} }
int dw_spi_add_host(struct device *dev, struct dw_spi *dws) int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
...@@ -496,7 +497,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -496,7 +497,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
} }
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
master->bus_num = dws->bus_num; master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs; master->num_chipselect = dws->num_cs;
master->setup = dw_spi_setup; master->setup = dw_spi_setup;
...@@ -572,13 +573,8 @@ EXPORT_SYMBOL_GPL(dw_spi_suspend_host); ...@@ -572,13 +573,8 @@ EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
int dw_spi_resume_host(struct dw_spi *dws) int dw_spi_resume_host(struct dw_spi *dws)
{ {
int ret;
spi_hw_init(&dws->master->dev, dws); spi_hw_init(&dws->master->dev, dws);
ret = spi_controller_resume(dws->master); return spi_controller_resume(dws->master);
if (ret)
dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
return ret;
} }
EXPORT_SYMBOL_GPL(dw_spi_resume_host); EXPORT_SYMBOL_GPL(dw_spi_resume_host);
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define DW_SPI_IDR 0x58 #define DW_SPI_IDR 0x58
#define DW_SPI_VERSION 0x5c #define DW_SPI_VERSION 0x5c
#define DW_SPI_DR 0x60 #define DW_SPI_DR 0x60
#define DW_SPI_CS_OVERRIDE 0xf4
/* Bit fields in CTRLR0 */ /* Bit fields in CTRLR0 */
#define SPI_DFS_OFFSET 0 #define SPI_DFS_OFFSET 0
...@@ -109,6 +110,7 @@ struct dw_spi { ...@@ -109,6 +110,7 @@ struct dw_spi {
u32 fifo_len; /* depth of the FIFO buffer */ u32 fifo_len; /* depth of the FIFO buffer */
u32 max_freq; /* max bus freq supported */ u32 max_freq; /* max bus freq supported */
int cs_override;
u32 reg_io_width; /* DR I/O width in bytes */ u32 reg_io_width; /* DR I/O width in bytes */
u16 bus_num; u16 bus_num;
u16 num_cs; /* supported slave numbers */ u16 num_cs; /* supported slave numbers */
......
...@@ -246,6 +246,19 @@ static int ep93xx_spi_read_write(struct spi_master *master) ...@@ -246,6 +246,19 @@ static int ep93xx_spi_read_write(struct spi_master *master)
return -EINPROGRESS; return -EINPROGRESS;
} }
static enum dma_transfer_direction
ep93xx_dma_data_to_trans_dir(enum dma_data_direction dir)
{
switch (dir) {
case DMA_TO_DEVICE:
return DMA_MEM_TO_DEV;
case DMA_FROM_DEVICE:
return DMA_DEV_TO_MEM;
default:
return DMA_TRANS_NONE;
}
}
/** /**
* ep93xx_spi_dma_prepare() - prepares a DMA transfer * ep93xx_spi_dma_prepare() - prepares a DMA transfer
* @master: SPI master * @master: SPI master
...@@ -257,7 +270,7 @@ static int ep93xx_spi_read_write(struct spi_master *master) ...@@ -257,7 +270,7 @@ static int ep93xx_spi_read_write(struct spi_master *master)
*/ */
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
ep93xx_spi_dma_prepare(struct spi_master *master, ep93xx_spi_dma_prepare(struct spi_master *master,
enum dma_transfer_direction dir) enum dma_data_direction dir)
{ {
struct ep93xx_spi *espi = spi_master_get_devdata(master); struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct spi_transfer *xfer = master->cur_msg->state; struct spi_transfer *xfer = master->cur_msg->state;
...@@ -277,9 +290,9 @@ ep93xx_spi_dma_prepare(struct spi_master *master, ...@@ -277,9 +290,9 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
memset(&conf, 0, sizeof(conf)); memset(&conf, 0, sizeof(conf));
conf.direction = dir; conf.direction = ep93xx_dma_data_to_trans_dir(dir);
if (dir == DMA_DEV_TO_MEM) { if (dir == DMA_FROM_DEVICE) {
chan = espi->dma_rx; chan = espi->dma_rx;
buf = xfer->rx_buf; buf = xfer->rx_buf;
sgt = &espi->rx_sgt; sgt = &espi->rx_sgt;
...@@ -343,7 +356,8 @@ ep93xx_spi_dma_prepare(struct spi_master *master, ...@@ -343,7 +356,8 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
if (!nents) if (!nents)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir, DMA_CTRL_ACK); txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, conf.direction,
DMA_CTRL_ACK);
if (!txd) { if (!txd) {
dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir); dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -360,13 +374,13 @@ ep93xx_spi_dma_prepare(struct spi_master *master, ...@@ -360,13 +374,13 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
* unmapped. * unmapped.
*/ */
static void ep93xx_spi_dma_finish(struct spi_master *master, static void ep93xx_spi_dma_finish(struct spi_master *master,
enum dma_transfer_direction dir) enum dma_data_direction dir)
{ {
struct ep93xx_spi *espi = spi_master_get_devdata(master); struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct dma_chan *chan; struct dma_chan *chan;
struct sg_table *sgt; struct sg_table *sgt;
if (dir == DMA_DEV_TO_MEM) { if (dir == DMA_FROM_DEVICE) {
chan = espi->dma_rx; chan = espi->dma_rx;
sgt = &espi->rx_sgt; sgt = &espi->rx_sgt;
} else { } else {
...@@ -381,8 +395,8 @@ static void ep93xx_spi_dma_callback(void *callback_param) ...@@ -381,8 +395,8 @@ static void ep93xx_spi_dma_callback(void *callback_param)
{ {
struct spi_master *master = callback_param; struct spi_master *master = callback_param;
ep93xx_spi_dma_finish(master, DMA_MEM_TO_DEV); ep93xx_spi_dma_finish(master, DMA_TO_DEVICE);
ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);
spi_finalize_current_transfer(master); spi_finalize_current_transfer(master);
} }
...@@ -392,15 +406,15 @@ static int ep93xx_spi_dma_transfer(struct spi_master *master) ...@@ -392,15 +406,15 @@ static int ep93xx_spi_dma_transfer(struct spi_master *master)
struct ep93xx_spi *espi = spi_master_get_devdata(master); struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct dma_async_tx_descriptor *rxd, *txd; struct dma_async_tx_descriptor *rxd, *txd;
rxd = ep93xx_spi_dma_prepare(master, DMA_DEV_TO_MEM); rxd = ep93xx_spi_dma_prepare(master, DMA_FROM_DEVICE);
if (IS_ERR(rxd)) { if (IS_ERR(rxd)) {
dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd)); dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
return PTR_ERR(rxd); return PTR_ERR(rxd);
} }
txd = ep93xx_spi_dma_prepare(master, DMA_MEM_TO_DEV); txd = ep93xx_spi_dma_prepare(master, DMA_TO_DEVICE);
if (IS_ERR(txd)) { if (IS_ERR(txd)) {
ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);
dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd)); dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));
return PTR_ERR(txd); return PTR_ERR(txd);
} }
......
...@@ -798,10 +798,8 @@ static int of_fsl_espi_suspend(struct device *dev) ...@@ -798,10 +798,8 @@ static int of_fsl_espi_suspend(struct device *dev)
int ret; int ret;
ret = spi_master_suspend(master); ret = spi_master_suspend(master);
if (ret) { if (ret)
dev_warn(dev, "cannot suspend master\n");
return ret; return ret;
}
return pm_runtime_force_suspend(dev); return pm_runtime_force_suspend(dev);
} }
......
...@@ -276,7 +276,7 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi) ...@@ -276,7 +276,7 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
fsl_lpspi_set_watermark(fsl_lpspi); fsl_lpspi_set_watermark(fsl_lpspi);
temp = CFGR1_PCSCFG | CFGR1_MASTER | CFGR1_NOSTALL; temp = CFGR1_PCSCFG | CFGR1_MASTER;
if (fsl_lpspi->config.mode & SPI_CS_HIGH) if (fsl_lpspi->config.mode & SPI_CS_HIGH)
temp |= CFGR1_PCSPOL; temp |= CFGR1_PCSPOL;
writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1); writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1);
......
This diff is collapsed.
...@@ -295,9 +295,11 @@ static int spi_gpio_request(struct device *dev, ...@@ -295,9 +295,11 @@ static int spi_gpio_request(struct device *dev,
spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN); spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN);
if (IS_ERR(spi_gpio->miso)) if (IS_ERR(spi_gpio->miso))
return PTR_ERR(spi_gpio->miso); return PTR_ERR(spi_gpio->miso);
if (!spi_gpio->miso) /*
/* HW configuration without MISO pin */ * No setting SPI_MASTER_NO_RX here - if there is only a MOSI
*mflags |= SPI_MASTER_NO_RX; * pin connected the host can still do RX by changing the
* direction of the line.
*/
spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
if (IS_ERR(spi_gpio->sck)) if (IS_ERR(spi_gpio->sck))
...@@ -423,7 +425,7 @@ static int spi_gpio_probe(struct platform_device *pdev) ...@@ -423,7 +425,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
spi_gpio->bitbang.chipselect = spi_gpio_chipselect; spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction; spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction;
if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) { if ((master_flags & SPI_MASTER_NO_TX) == 0) {
spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0; spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1; spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;
spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2; spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;
...@@ -447,10 +449,8 @@ static int spi_gpio_probe(struct platform_device *pdev) ...@@ -447,10 +449,8 @@ static int spi_gpio_probe(struct platform_device *pdev)
static int spi_gpio_remove(struct platform_device *pdev) static int spi_gpio_remove(struct platform_device *pdev)
{ {
struct spi_gpio *spi_gpio; struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
spi_gpio = platform_get_drvdata(pdev); spi_gpio = platform_get_drvdata(pdev);
pdata = dev_get_platdata(&pdev->dev);
/* stop() unregisters child devices too */ /* stop() unregisters child devices too */
spi_bitbang_stop(&spi_gpio->bitbang); spi_bitbang_stop(&spi_gpio->bitbang);
......
...@@ -63,6 +63,7 @@ struct spi_imx_devtype_data { ...@@ -63,6 +63,7 @@ struct spi_imx_devtype_data {
void (*trigger)(struct spi_imx_data *); void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *);
void (*reset)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *);
void (*setup_wml)(struct spi_imx_data *);
void (*disable)(struct spi_imx_data *); void (*disable)(struct spi_imx_data *);
bool has_dmamode; bool has_dmamode;
bool has_slavemode; bool has_slavemode;
...@@ -216,7 +217,6 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, ...@@ -216,7 +217,6 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *transfer) struct spi_transfer *transfer)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(master); struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
unsigned int bytes_per_word, i;
if (!master->dma_rx) if (!master->dma_rx)
return false; return false;
...@@ -224,14 +224,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, ...@@ -224,14 +224,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
if (spi_imx->slave_mode) if (spi_imx->slave_mode)
return false; return false;
bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word); if (transfer->len < spi_imx->devtype_data->fifo_size)
return false;
for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
if (!(transfer->len % (i * bytes_per_word)))
break;
}
spi_imx->wml = i;
spi_imx->dynamic_burst = 0; spi_imx->dynamic_burst = 0;
return true; return true;
...@@ -583,18 +578,21 @@ static int mx51_ecspi_config(struct spi_device *spi) ...@@ -583,18 +578,21 @@ static int mx51_ecspi_config(struct spi_device *spi)
else /* SCLK is _very_ slow */ else /* SCLK is _very_ slow */
usleep_range(delay, delay + 10); usleep_range(delay, delay + 10);
return 0;
}
static void mx51_setup_wml(struct spi_imx_data *spi_imx)
{
/* /*
* Configure the DMA register: setup the watermark * Configure the DMA register: setup the watermark
* and enable DMA request. * and enable DMA request.
*/ */
writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml) | writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
MX51_ECSPI_DMA_TX_WML(spi_imx->wml) | MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |
MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) | MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN | MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA); MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
return 0;
} }
static int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx) static int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx)
...@@ -931,6 +929,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { ...@@ -931,6 +929,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.trigger = mx51_ecspi_trigger, .trigger = mx51_ecspi_trigger,
.rx_available = mx51_ecspi_rx_available, .rx_available = mx51_ecspi_rx_available,
.reset = mx51_ecspi_reset, .reset = mx51_ecspi_reset,
.setup_wml = mx51_setup_wml,
.fifo_size = 64, .fifo_size = 64,
.has_dmamode = true, .has_dmamode = true,
.dynamic_burst = true, .dynamic_burst = true,
...@@ -1138,7 +1137,6 @@ static int spi_imx_setupxfer(struct spi_device *spi, ...@@ -1138,7 +1137,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
int ret;
if (!t) if (!t)
return 0; return 0;
...@@ -1179,12 +1177,6 @@ static int spi_imx_setupxfer(struct spi_device *spi, ...@@ -1179,12 +1177,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,
else else
spi_imx->usedma = 0; spi_imx->usedma = 0;
if (spi_imx->usedma) {
ret = spi_imx_dma_configure(spi->master);
if (ret)
return ret;
}
if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) { if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
spi_imx->rx = mx53_ecspi_rx_slave; spi_imx->rx = mx53_ecspi_rx_slave;
spi_imx->tx = mx53_ecspi_tx_slave; spi_imx->tx = mx53_ecspi_tx_slave;
...@@ -1289,6 +1281,31 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, ...@@ -1289,6 +1281,31 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
unsigned long timeout; unsigned long timeout;
struct spi_master *master = spi_imx->bitbang.master; struct spi_master *master = spi_imx->bitbang.master;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
unsigned int bytes_per_word, i;
int ret;
/* Get the right burst length from the last sg to ensure no tail data */
bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
break;
}
/* Use 1 as wml in case no available burst length got */
if (i == 0)
i = 1;
spi_imx->wml = i;
ret = spi_imx_dma_configure(master);
if (ret)
return ret;
if (!spi_imx->devtype_data->setup_wml) {
dev_err(spi_imx->dev, "No setup_wml()?\n");
return -EINVAL;
}
spi_imx->devtype_data->setup_wml(spi_imx);
/* /*
* The TX DMA setup starts the transfer, so make sure RX is configured * The TX DMA setup starts the transfer, so make sure RX is configured
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "internals.h" #include "internals.h"
#define SPI_MEM_MAX_BUSWIDTH 4
/** /**
* spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a
* memory operation * memory operation
...@@ -149,6 +151,44 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem, ...@@ -149,6 +151,44 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem,
} }
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
static bool spi_mem_buswidth_is_valid(u8 buswidth)
{
if (hweight8(buswidth) > 1 || buswidth > SPI_MEM_MAX_BUSWIDTH)
return false;
return true;
}
static int spi_mem_check_op(const struct spi_mem_op *op)
{
if (!op->cmd.buswidth)
return -EINVAL;
if ((op->addr.nbytes && !op->addr.buswidth) ||
(op->dummy.nbytes && !op->dummy.buswidth) ||
(op->data.nbytes && !op->data.buswidth))
return -EINVAL;
if (!spi_mem_buswidth_is_valid(op->cmd.buswidth) ||
!spi_mem_buswidth_is_valid(op->addr.buswidth) ||
!spi_mem_buswidth_is_valid(op->dummy.buswidth) ||
!spi_mem_buswidth_is_valid(op->data.buswidth))
return -EINVAL;
return 0;
}
static bool spi_mem_internal_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct spi_controller *ctlr = mem->spi->controller;
if (ctlr->mem_ops && ctlr->mem_ops->supports_op)
return ctlr->mem_ops->supports_op(mem, op);
return spi_mem_default_supports_op(mem, op);
}
/** /**
* spi_mem_supports_op() - Check if a memory device and the controller it is * spi_mem_supports_op() - Check if a memory device and the controller it is
* connected to support a specific memory operation * connected to support a specific memory operation
...@@ -166,12 +206,10 @@ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); ...@@ -166,12 +206,10 @@ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
*/ */
bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
{ {
struct spi_controller *ctlr = mem->spi->controller; if (spi_mem_check_op(op))
return false;
if (ctlr->mem_ops && ctlr->mem_ops->supports_op)
return ctlr->mem_ops->supports_op(mem, op);
return spi_mem_default_supports_op(mem, op); return spi_mem_internal_supports_op(mem, op);
} }
EXPORT_SYMBOL_GPL(spi_mem_supports_op); EXPORT_SYMBOL_GPL(spi_mem_supports_op);
...@@ -196,7 +234,11 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -196,7 +234,11 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
u8 *tmpbuf; u8 *tmpbuf;
int ret; int ret;
if (!spi_mem_supports_op(mem, op)) ret = spi_mem_check_op(op);
if (ret)
return ret;
if (!spi_mem_internal_supports_op(mem, op))
return -ENOTSUPP; return -ENOTSUPP;
if (ctlr->mem_ops) { if (ctlr->mem_ops) {
...@@ -346,10 +388,25 @@ EXPORT_SYMBOL_GPL(spi_mem_get_name); ...@@ -346,10 +388,25 @@ EXPORT_SYMBOL_GPL(spi_mem_get_name);
int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{ {
struct spi_controller *ctlr = mem->spi->controller; struct spi_controller *ctlr = mem->spi->controller;
size_t len;
len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size) if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size)
return ctlr->mem_ops->adjust_op_size(mem, op); return ctlr->mem_ops->adjust_op_size(mem, op);
if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) {
if (len > spi_max_transfer_size(mem->spi))
return -EINVAL;
op->data.nbytes = min3((size_t)op->data.nbytes,
spi_max_transfer_size(mem->spi),
spi_max_message_size(mem->spi) -
len);
if (!op->data.nbytes)
return -EINVAL;
}
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
......
...@@ -98,6 +98,7 @@ struct mtk_spi { ...@@ -98,6 +98,7 @@ struct mtk_spi {
struct clk *parent_clk, *sel_clk, *spi_clk; struct clk *parent_clk, *sel_clk, *spi_clk;
struct spi_transfer *cur_transfer; struct spi_transfer *cur_transfer;
u32 xfer_len; u32 xfer_len;
u32 num_xfered;
struct scatterlist *tx_sgl, *rx_sgl; struct scatterlist *tx_sgl, *rx_sgl;
u32 tx_sgl_len, rx_sgl_len; u32 tx_sgl_len, rx_sgl_len;
const struct mtk_spi_compatible *dev_comp; const struct mtk_spi_compatible *dev_comp;
...@@ -385,6 +386,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master, ...@@ -385,6 +386,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master,
mdata->cur_transfer = xfer; mdata->cur_transfer = xfer;
mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len); mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len);
mdata->num_xfered = 0;
mtk_spi_prepare_transfer(master, xfer); mtk_spi_prepare_transfer(master, xfer);
mtk_spi_setup_packet(master); mtk_spi_setup_packet(master);
...@@ -415,6 +417,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master, ...@@ -415,6 +417,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master,
mdata->tx_sgl_len = 0; mdata->tx_sgl_len = 0;
mdata->rx_sgl_len = 0; mdata->rx_sgl_len = 0;
mdata->cur_transfer = xfer; mdata->cur_transfer = xfer;
mdata->num_xfered = 0;
mtk_spi_prepare_transfer(master, xfer); mtk_spi_prepare_transfer(master, xfer);
...@@ -482,7 +485,7 @@ static int mtk_spi_setup(struct spi_device *spi) ...@@ -482,7 +485,7 @@ static int mtk_spi_setup(struct spi_device *spi)
static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
{ {
u32 cmd, reg_val, cnt, remainder; u32 cmd, reg_val, cnt, remainder, len;
struct spi_master *master = dev_id; struct spi_master *master = dev_id;
struct mtk_spi *mdata = spi_master_get_devdata(master); struct mtk_spi *mdata = spi_master_get_devdata(master);
struct spi_transfer *trans = mdata->cur_transfer; struct spi_transfer *trans = mdata->cur_transfer;
...@@ -497,36 +500,38 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) ...@@ -497,36 +500,38 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
if (trans->rx_buf) { if (trans->rx_buf) {
cnt = mdata->xfer_len / 4; cnt = mdata->xfer_len / 4;
ioread32_rep(mdata->base + SPI_RX_DATA_REG, ioread32_rep(mdata->base + SPI_RX_DATA_REG,
trans->rx_buf, cnt); trans->rx_buf + mdata->num_xfered, cnt);
remainder = mdata->xfer_len % 4; remainder = mdata->xfer_len % 4;
if (remainder > 0) { if (remainder > 0) {
reg_val = readl(mdata->base + SPI_RX_DATA_REG); reg_val = readl(mdata->base + SPI_RX_DATA_REG);
memcpy(trans->rx_buf + (cnt * 4), memcpy(trans->rx_buf +
&reg_val, remainder); mdata->num_xfered +
(cnt * 4),
&reg_val,
remainder);
} }
} }
trans->len -= mdata->xfer_len; mdata->num_xfered += mdata->xfer_len;
if (!trans->len) { if (mdata->num_xfered == trans->len) {
spi_finalize_current_transfer(master); spi_finalize_current_transfer(master);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
if (trans->tx_buf) len = trans->len - mdata->num_xfered;
trans->tx_buf += mdata->xfer_len; mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len);
if (trans->rx_buf)
trans->rx_buf += mdata->xfer_len;
mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, trans->len);
mtk_spi_setup_packet(master); mtk_spi_setup_packet(master);
cnt = trans->len / 4; cnt = len / 4;
iowrite32_rep(mdata->base + SPI_TX_DATA_REG, trans->tx_buf, cnt); iowrite32_rep(mdata->base + SPI_TX_DATA_REG,
trans->tx_buf + mdata->num_xfered, cnt);
remainder = trans->len % 4; remainder = len % 4;
if (remainder > 0) { if (remainder > 0) {
reg_val = 0; reg_val = 0;
memcpy(&reg_val, trans->tx_buf + (cnt * 4), remainder); memcpy(&reg_val,
trans->tx_buf + (cnt * 4) + mdata->num_xfered,
remainder);
writel(reg_val, mdata->base + SPI_TX_DATA_REG); writel(reg_val, mdata->base + SPI_TX_DATA_REG);
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/gcd.h> #include <linux/gcd.h>
#include <linux/iopoll.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/gpio.h> #include <linux/gpio.h>
...@@ -126,6 +127,7 @@ struct omap2_mcspi_regs { ...@@ -126,6 +127,7 @@ struct omap2_mcspi_regs {
}; };
struct omap2_mcspi { struct omap2_mcspi {
struct completion txdone;
struct spi_master *master; struct spi_master *master;
/* Virtual base address of the controller */ /* Virtual base address of the controller */
void __iomem *base; void __iomem *base;
...@@ -135,6 +137,7 @@ struct omap2_mcspi { ...@@ -135,6 +137,7 @@ struct omap2_mcspi {
struct device *dev; struct device *dev;
struct omap2_mcspi_regs ctx; struct omap2_mcspi_regs ctx;
int fifo_depth; int fifo_depth;
bool slave_aborted;
unsigned int pin_dir:1; unsigned int pin_dir:1;
}; };
...@@ -274,19 +277,23 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) ...@@ -274,19 +277,23 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
} }
} }
static void omap2_mcspi_set_master_mode(struct spi_master *master) static void omap2_mcspi_set_mode(struct spi_master *master)
{ {
struct omap2_mcspi *mcspi = spi_master_get_devdata(master); struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_regs *ctx = &mcspi->ctx;
u32 l; u32 l;
/* /*
* Setup when switching from (reset default) slave mode * Choose master or slave mode
* to single-channel master mode
*/ */
l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL); l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS); l &= ~(OMAP2_MCSPI_MODULCTRL_STEST);
l |= OMAP2_MCSPI_MODULCTRL_SINGLE; if (spi_controller_is_slave(master)) {
l |= (OMAP2_MCSPI_MODULCTRL_MS);
} else {
l &= ~(OMAP2_MCSPI_MODULCTRL_MS);
l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
}
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l); mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
ctx->modulctrl = l; ctx->modulctrl = l;
...@@ -299,7 +306,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, ...@@ -299,7 +306,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi; struct omap2_mcspi *mcspi;
unsigned int wcnt; unsigned int wcnt;
int max_fifo_depth, fifo_depth, bytes_per_word; int max_fifo_depth, bytes_per_word;
u32 chconf, xferlevel; u32 chconf, xferlevel;
mcspi = spi_master_get_devdata(master); mcspi = spi_master_get_devdata(master);
...@@ -315,10 +322,6 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, ...@@ -315,10 +322,6 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
else else
max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH; max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH;
fifo_depth = gcd(t->len, max_fifo_depth);
if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0)
goto disable_fifo;
wcnt = t->len / bytes_per_word; wcnt = t->len / bytes_per_word;
if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
goto disable_fifo; goto disable_fifo;
...@@ -326,16 +329,17 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, ...@@ -326,16 +329,17 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
xferlevel = wcnt << 16; xferlevel = wcnt << 16;
if (t->rx_buf != NULL) { if (t->rx_buf != NULL) {
chconf |= OMAP2_MCSPI_CHCONF_FFER; chconf |= OMAP2_MCSPI_CHCONF_FFER;
xferlevel |= (fifo_depth - 1) << 8; xferlevel |= (bytes_per_word - 1) << 8;
} }
if (t->tx_buf != NULL) { if (t->tx_buf != NULL) {
chconf |= OMAP2_MCSPI_CHCONF_FFET; chconf |= OMAP2_MCSPI_CHCONF_FFET;
xferlevel |= fifo_depth - 1; xferlevel |= bytes_per_word - 1;
} }
mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel); mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
mcspi_write_chconf0(spi, chconf); mcspi_write_chconf0(spi, chconf);
mcspi->fifo_depth = fifo_depth; mcspi->fifo_depth = max_fifo_depth;
return; return;
} }
...@@ -353,18 +357,22 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, ...@@ -353,18 +357,22 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
{ {
unsigned long timeout; u32 val;
timeout = jiffies + msecs_to_jiffies(1000); return readl_poll_timeout(reg, val, val & bit, 1, MSEC_PER_SEC);
while (!(readl_relaxed(reg) & bit)) { }
if (time_after(jiffies, timeout)) {
if (!(readl_relaxed(reg) & bit)) static int mcspi_wait_for_completion(struct omap2_mcspi *mcspi,
return -ETIMEDOUT; struct completion *x)
else {
return 0; if (spi_controller_is_slave(mcspi->master)) {
} if (wait_for_completion_interruptible(x) ||
cpu_relax(); mcspi->slave_aborted)
return -EINTR;
} else {
wait_for_completion(x);
} }
return 0; return 0;
} }
...@@ -517,7 +525,12 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, ...@@ -517,7 +525,12 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
dma_async_issue_pending(mcspi_dma->dma_rx); dma_async_issue_pending(mcspi_dma->dma_rx);
omap2_mcspi_set_dma_req(spi, 1, 1); omap2_mcspi_set_dma_req(spi, 1, 1);
wait_for_completion(&mcspi_dma->dma_rx_completion); ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion);
if (ret || mcspi->slave_aborted) {
dmaengine_terminate_sync(mcspi_dma->dma_rx);
omap2_mcspi_set_dma_req(spi, 1, 0);
return 0;
}
for (x = 0; x < nb_sizes; x++) for (x = 0; x < nb_sizes; x++)
kfree(sg_out[x]); kfree(sg_out[x]);
...@@ -585,7 +598,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -585,7 +598,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
struct dma_slave_config cfg; struct dma_slave_config cfg;
enum dma_slave_buswidth width; enum dma_slave_buswidth width;
unsigned es; unsigned es;
u32 burst;
void __iomem *chstat_reg; void __iomem *chstat_reg;
void __iomem *irqstat_reg; void __iomem *irqstat_reg;
int wait_res; int wait_res;
...@@ -605,34 +617,49 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -605,34 +617,49 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
} }
count = xfer->len; count = xfer->len;
burst = 1;
if (mcspi->fifo_depth > 0) {
if (count > mcspi->fifo_depth)
burst = mcspi->fifo_depth / es;
else
burst = count / es;
}
memset(&cfg, 0, sizeof(cfg)); memset(&cfg, 0, sizeof(cfg));
cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
cfg.src_addr_width = width; cfg.src_addr_width = width;
cfg.dst_addr_width = width; cfg.dst_addr_width = width;
cfg.src_maxburst = burst; cfg.src_maxburst = es;
cfg.dst_maxburst = burst; cfg.dst_maxburst = es;
rx = xfer->rx_buf; rx = xfer->rx_buf;
tx = xfer->tx_buf; tx = xfer->tx_buf;
if (tx != NULL) mcspi->slave_aborted = false;
reinit_completion(&mcspi_dma->dma_tx_completion);
reinit_completion(&mcspi_dma->dma_rx_completion);
reinit_completion(&mcspi->txdone);
if (tx) {
/* Enable EOW IRQ to know end of tx in slave mode */
if (spi_controller_is_slave(spi->master))
mcspi_write_reg(spi->master,
OMAP2_MCSPI_IRQENABLE,
OMAP2_MCSPI_IRQSTATUS_EOW);
omap2_mcspi_tx_dma(spi, xfer, cfg); omap2_mcspi_tx_dma(spi, xfer, cfg);
}
if (rx != NULL) if (rx != NULL)
count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
if (tx != NULL) { if (tx != NULL) {
wait_for_completion(&mcspi_dma->dma_tx_completion); int ret;
ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion);
if (ret || mcspi->slave_aborted) {
dmaengine_terminate_sync(mcspi_dma->dma_tx);
omap2_mcspi_set_dma_req(spi, 0, 0);
return 0;
}
if (spi_controller_is_slave(mcspi->master)) {
ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone);
if (ret || mcspi->slave_aborted)
return 0;
}
if (mcspi->fifo_depth > 0) { if (mcspi->fifo_depth > 0) {
irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
...@@ -1089,6 +1116,36 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) ...@@ -1089,6 +1116,36 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
gpio_free(spi->cs_gpio); gpio_free(spi->cs_gpio);
} }
static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
{
struct omap2_mcspi *mcspi = data;
u32 irqstat;
irqstat = mcspi_read_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS);
if (!irqstat)
return IRQ_NONE;
/* Disable IRQ and wakeup slave xfer task */
mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQENABLE, 0);
if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW)
complete(&mcspi->txdone);
return IRQ_HANDLED;
}
static int omap2_mcspi_slave_abort(struct spi_master *master)
{
struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels;
mcspi->slave_aborted = true;
complete(&mcspi_dma->dma_rx_completion);
complete(&mcspi_dma->dma_tx_completion);
complete(&mcspi->txdone);
return 0;
}
static int omap2_mcspi_transfer_one(struct spi_master *master, static int omap2_mcspi_transfer_one(struct spi_master *master,
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
...@@ -1255,10 +1312,20 @@ static bool omap2_mcspi_can_dma(struct spi_master *master, ...@@ -1255,10 +1312,20 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
struct omap2_mcspi_dma *mcspi_dma =
&mcspi->dma_channels[spi->chip_select];
if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx)
return false;
if (spi_controller_is_slave(master))
return true;
return (xfer->len >= DMA_MIN_BYTES); return (xfer->len >= DMA_MIN_BYTES);
} }
static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
{ {
struct spi_master *master = mcspi->master; struct spi_master *master = mcspi->master;
struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_regs *ctx = &mcspi->ctx;
...@@ -1275,7 +1342,7 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) ...@@ -1275,7 +1342,7 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
OMAP2_MCSPI_WAKEUPENABLE_WKEN); OMAP2_MCSPI_WAKEUPENABLE_WKEN);
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
omap2_mcspi_set_master_mode(master); omap2_mcspi_set_mode(master);
pm_runtime_mark_last_busy(mcspi->dev); pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev); pm_runtime_put_autosuspend(mcspi->dev);
return 0; return 0;
...@@ -1350,11 +1417,12 @@ static int omap2_mcspi_probe(struct platform_device *pdev) ...@@ -1350,11 +1417,12 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match; const struct of_device_id *match;
master = spi_alloc_master(&pdev->dev, sizeof *mcspi); if (of_property_read_bool(node, "spi-slave"))
if (master == NULL) { master = spi_alloc_slave(&pdev->dev, sizeof(*mcspi));
dev_dbg(&pdev->dev, "master allocation failed\n"); else
master = spi_alloc_master(&pdev->dev, sizeof(*mcspi));
if (!master)
return -ENOMEM; return -ENOMEM;
}
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
...@@ -1366,6 +1434,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) ...@@ -1366,6 +1434,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->transfer_one = omap2_mcspi_transfer_one; master->transfer_one = omap2_mcspi_transfer_one;
master->set_cs = omap2_mcspi_set_cs; master->set_cs = omap2_mcspi_set_cs;
master->cleanup = omap2_mcspi_cleanup; master->cleanup = omap2_mcspi_cleanup;
master->slave_abort = omap2_mcspi_slave_abort;
master->dev.of_node = node; master->dev.of_node = node;
master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
...@@ -1417,15 +1486,31 @@ static int omap2_mcspi_probe(struct platform_device *pdev) ...@@ -1417,15 +1486,31 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i); sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
} }
status = platform_get_irq(pdev, 0);
if (status == -EPROBE_DEFER)
goto free_master;
if (status < 0) {
dev_err(&pdev->dev, "no irq resource found\n");
goto free_master;
}
init_completion(&mcspi->txdone);
status = devm_request_irq(&pdev->dev, status,
omap2_mcspi_irq_handler, 0, pdev->name,
mcspi);
if (status) {
dev_err(&pdev->dev, "Cannot request IRQ");
goto free_master;
}
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
status = omap2_mcspi_master_setup(mcspi); status = omap2_mcspi_controller_setup(mcspi);
if (status < 0) if (status < 0)
goto disable_pm; goto disable_pm;
status = devm_spi_register_master(&pdev->dev, master); status = devm_spi_register_controller(&pdev->dev, master);
if (status < 0) if (status < 0)
goto disable_pm; goto disable_pm;
......
...@@ -431,6 +431,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -431,6 +431,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
int word_len; int word_len;
struct orion_spi *orion_spi; struct orion_spi *orion_spi;
int cs = spi->chip_select; int cs = spi->chip_select;
void __iomem *vaddr;
word_len = spi->bits_per_word; word_len = spi->bits_per_word;
count = xfer->len; count = xfer->len;
...@@ -441,8 +442,9 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -441,8 +442,9 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
* Use SPI direct write mode if base address is available. Otherwise * Use SPI direct write mode if base address is available. Otherwise
* fall back to PIO mode for this transfer. * fall back to PIO mode for this transfer.
*/ */
if ((orion_spi->child[cs].direct_access.vaddr) && (xfer->tx_buf) && vaddr = orion_spi->child[cs].direct_access.vaddr;
(word_len == 8)) {
if (vaddr && xfer->tx_buf && word_len == 8) {
unsigned int cnt = count / 4; unsigned int cnt = count / 4;
unsigned int rem = count % 4; unsigned int rem = count % 4;
...@@ -450,13 +452,11 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -450,13 +452,11 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
* Send the TX-data to the SPI device via the direct * Send the TX-data to the SPI device via the direct
* mapped address window * mapped address window
*/ */
iowrite32_rep(orion_spi->child[cs].direct_access.vaddr, iowrite32_rep(vaddr, xfer->tx_buf, cnt);
xfer->tx_buf, cnt);
if (rem) { if (rem) {
u32 *buf = (u32 *)xfer->tx_buf; u32 *buf = (u32 *)xfer->tx_buf;
iowrite8_rep(orion_spi->child[cs].direct_access.vaddr, iowrite8_rep(vaddr, &buf[cnt], rem);
&buf[cnt], rem);
} }
return count; return count;
...@@ -683,6 +683,7 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -683,6 +683,7 @@ static int orion_spi_probe(struct platform_device *pdev)
} }
for_each_available_child_of_node(pdev->dev.of_node, np) { for_each_available_child_of_node(pdev->dev.of_node, np) {
struct orion_direct_acc *dir_acc;
u32 cs; u32 cs;
int cs_gpio; int cs_gpio;
...@@ -750,14 +751,13 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -750,14 +751,13 @@ static int orion_spi_probe(struct platform_device *pdev)
* This needs to get extended for the direct SPI-NOR / SPI-NAND * This needs to get extended for the direct SPI-NOR / SPI-NAND
* support, once this gets implemented. * support, once this gets implemented.
*/ */
spi->child[cs].direct_access.vaddr = devm_ioremap(&pdev->dev, dir_acc = &spi->child[cs].direct_access;
r->start, dir_acc->vaddr = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
PAGE_SIZE); if (!dir_acc->vaddr) {
if (!spi->child[cs].direct_access.vaddr) {
status = -ENOMEM; status = -ENOMEM;
goto out_rel_axi_clk; goto out_rel_axi_clk;
} }
spi->child[cs].direct_access.size = PAGE_SIZE; dir_acc->size = PAGE_SIZE;
dev_info(&pdev->dev, "CS%d configured for direct access\n", cs); dev_info(&pdev->dev, "CS%d configured for direct access\n", cs);
} }
......
...@@ -468,7 +468,7 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi) ...@@ -468,7 +468,7 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi)
/* allocate coherent DMAable memory for hardware buffer descriptors. */ /* allocate coherent DMAable memory for hardware buffer descriptors. */
sqi->bd = dma_zalloc_coherent(&sqi->master->dev, sqi->bd = dma_zalloc_coherent(&sqi->master->dev,
sizeof(*bd) * PESQI_BD_COUNT, sizeof(*bd) * PESQI_BD_COUNT,
&sqi->bd_dma, GFP_DMA32); &sqi->bd_dma, GFP_KERNEL);
if (!sqi->bd) { if (!sqi->bd) {
dev_err(&sqi->master->dev, "failed allocating dma buffer\n"); dev_err(&sqi->master->dev, "failed allocating dma buffer\n");
return -ENOMEM; return -ENOMEM;
...@@ -656,7 +656,7 @@ static int pic32_sqi_probe(struct platform_device *pdev) ...@@ -656,7 +656,7 @@ static int pic32_sqi_probe(struct platform_device *pdev)
master->max_speed_hz = clk_get_rate(sqi->base_clk); master->max_speed_hz = clk_get_rate(sqi->base_clk);
master->dma_alignment = 32; master->dma_alignment = 32;
master->max_dma_len = PESQI_BD_BUF_LEN_MAX; master->max_dma_len = PESQI_BD_BUF_LEN_MAX;
master->dev.of_node = of_node_get(pdev->dev.of_node); master->dev.of_node = pdev->dev.of_node;
master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL | master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL |
SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD; SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
master->flags = SPI_MASTER_HALF_DUPLEX; master->flags = SPI_MASTER_HALF_DUPLEX;
......
...@@ -320,7 +320,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s, ...@@ -320,7 +320,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
desc_rx = dmaengine_prep_slave_sg(master->dma_rx, desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
xfer->rx_sg.sgl, xfer->rx_sg.sgl,
xfer->rx_sg.nents, xfer->rx_sg.nents,
DMA_FROM_DEVICE, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx) { if (!desc_rx) {
ret = -EINVAL; ret = -EINVAL;
...@@ -330,7 +330,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s, ...@@ -330,7 +330,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
desc_tx = dmaengine_prep_slave_sg(master->dma_tx, desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
xfer->tx_sg.sgl, xfer->tx_sg.sgl,
xfer->tx_sg.nents, xfer->tx_sg.nents,
DMA_TO_DEVICE, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) { if (!desc_tx) {
ret = -EINVAL; ret = -EINVAL;
...@@ -774,7 +774,7 @@ static int pic32_spi_probe(struct platform_device *pdev) ...@@ -774,7 +774,7 @@ static int pic32_spi_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_master; goto err_master;
master->dev.of_node = of_node_get(pdev->dev.of_node); master->dev.of_node = pdev->dev.of_node;
master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH; master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH;
master->num_chipselect = 1; /* single chip-select */ master->num_chipselect = 1; /* single chip-select */
master->max_speed_hz = clk_get_rate(pic32s->clk); master->max_speed_hz = clk_get_rate(pic32s->clk);
......
...@@ -1490,10 +1490,8 @@ static void do_polling_transfer(struct pl022 *pl022) ...@@ -1490,10 +1490,8 @@ static void do_polling_transfer(struct pl022 *pl022)
struct spi_message *message = NULL; struct spi_message *message = NULL;
struct spi_transfer *transfer = NULL; struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL; struct spi_transfer *previous = NULL;
struct chip_data *chip;
unsigned long time, timeout; unsigned long time, timeout;
chip = pl022->cur_chip;
message = pl022->cur_msg; message = pl022->cur_msg;
while (message->state != STATE_DONE) { while (message->state != STATE_DONE) {
...@@ -2325,10 +2323,8 @@ static int pl022_suspend(struct device *dev) ...@@ -2325,10 +2323,8 @@ static int pl022_suspend(struct device *dev)
int ret; int ret;
ret = spi_master_suspend(pl022->master); ret = spi_master_suspend(pl022->master);
if (ret) { if (ret)
dev_warn(dev, "cannot suspend master\n");
return ret; return ret;
}
ret = pm_runtime_force_suspend(dev); ret = pm_runtime_force_suspend(dev);
if (ret) { if (ret) {
...@@ -2353,9 +2349,7 @@ static int pl022_resume(struct device *dev) ...@@ -2353,9 +2349,7 @@ static int pl022_resume(struct device *dev)
/* Start the queue running */ /* Start the queue running */
ret = spi_master_resume(pl022->master); ret = spi_master_resume(pl022->master);
if (ret) if (!ret)
dev_err(dev, "problem starting queue (%d)\n", ret);
else
dev_dbg(dev, "resumed\n"); dev_dbg(dev, "resumed\n");
return ret; return ret;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/of_device.h>
#include "spi-pxa2xx.h" #include "spi-pxa2xx.h"
...@@ -665,9 +666,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) ...@@ -665,9 +666,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
bytes_left = drv_data->rx_end - drv_data->rx; bytes_left = drv_data->rx_end - drv_data->rx;
switch (drv_data->n_bytes) { switch (drv_data->n_bytes) {
case 4: case 4:
bytes_left >>= 1; bytes_left >>= 2;
break;
case 2: case 2:
bytes_left >>= 1; bytes_left >>= 1;
break;
} }
rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data); rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data);
...@@ -1333,9 +1336,6 @@ static void cleanup(struct spi_device *spi) ...@@ -1333,9 +1336,6 @@ static void cleanup(struct spi_device *spi)
kfree(chip); kfree(chip);
} }
#ifdef CONFIG_PCI
#ifdef CONFIG_ACPI
static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "INT33C0", LPSS_LPT_SSP }, { "INT33C0", LPSS_LPT_SSP },
{ "INT33C1", LPSS_LPT_SSP }, { "INT33C1", LPSS_LPT_SSP },
...@@ -1347,23 +1347,6 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { ...@@ -1347,23 +1347,6 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
}; };
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
{
unsigned int devid;
int port_id = -1;
if (adev && adev->pnp.unique_id &&
!kstrtouint(adev->pnp.unique_id, 0, &devid))
port_id = devid;
return port_id;
}
#else /* !CONFIG_ACPI */
static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
{
return -1;
}
#endif
/* /*
* PCI IDs of compound devices that integrate both host controller and private * PCI IDs of compound devices that integrate both host controller and private
* integrated DMA engine. Please note these are not used in module * integrated DMA engine. Please note these are not used in module
...@@ -1410,6 +1393,37 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { ...@@ -1410,6 +1393,37 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
{ }, { },
}; };
static const struct of_device_id pxa2xx_spi_of_match[] = {
{ .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP },
{},
};
MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
#ifdef CONFIG_ACPI
static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
{
unsigned int devid;
int port_id = -1;
if (adev && adev->pnp.unique_id &&
!kstrtouint(adev->pnp.unique_id, 0, &devid))
port_id = devid;
return port_id;
}
#else /* !CONFIG_ACPI */
static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
{
return -1;
}
#endif /* CONFIG_ACPI */
#ifdef CONFIG_PCI
static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
{ {
struct device *dev = param; struct device *dev = param;
...@@ -1420,6 +1434,8 @@ static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) ...@@ -1420,6 +1434,8 @@ static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
return true; return true;
} }
#endif /* CONFIG_PCI */
static struct pxa2xx_spi_master * static struct pxa2xx_spi_master *
pxa2xx_spi_init_pdata(struct platform_device *pdev) pxa2xx_spi_init_pdata(struct platform_device *pdev)
{ {
...@@ -1429,11 +1445,15 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) ...@@ -1429,11 +1445,15 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
struct resource *res; struct resource *res;
const struct acpi_device_id *adev_id = NULL; const struct acpi_device_id *adev_id = NULL;
const struct pci_device_id *pcidev_id = NULL; const struct pci_device_id *pcidev_id = NULL;
int type; const struct of_device_id *of_id = NULL;
enum pxa_ssp_type type;
adev = ACPI_COMPANION(&pdev->dev); adev = ACPI_COMPANION(&pdev->dev);
if (dev_is_pci(pdev->dev.parent)) if (pdev->dev.of_node)
of_id = of_match_device(pdev->dev.driver->of_match_table,
&pdev->dev);
else if (dev_is_pci(pdev->dev.parent))
pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match,
to_pci_dev(pdev->dev.parent)); to_pci_dev(pdev->dev.parent));
else if (adev) else if (adev)
...@@ -1443,9 +1463,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) ...@@ -1443,9 +1463,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
return NULL; return NULL;
if (adev_id) if (adev_id)
type = (int)adev_id->driver_data; type = (enum pxa_ssp_type)adev_id->driver_data;
else if (pcidev_id) else if (pcidev_id)
type = (int)pcidev_id->driver_data; type = (enum pxa_ssp_type)pcidev_id->driver_data;
else if (of_id)
type = (enum pxa_ssp_type)of_id->data;
else else
return NULL; return NULL;
...@@ -1464,11 +1486,13 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) ...@@ -1464,11 +1486,13 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
if (IS_ERR(ssp->mmio_base)) if (IS_ERR(ssp->mmio_base))
return NULL; return NULL;
#ifdef CONFIG_PCI
if (pcidev_id) { if (pcidev_id) {
pdata->tx_param = pdev->dev.parent; pdata->tx_param = pdev->dev.parent;
pdata->rx_param = pdev->dev.parent; pdata->rx_param = pdev->dev.parent;
pdata->dma_filter = pxa2xx_spi_idma_filter; pdata->dma_filter = pxa2xx_spi_idma_filter;
} }
#endif
ssp->clk = devm_clk_get(&pdev->dev, NULL); ssp->clk = devm_clk_get(&pdev->dev, NULL);
ssp->irq = platform_get_irq(pdev, 0); ssp->irq = platform_get_irq(pdev, 0);
...@@ -1482,14 +1506,6 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev) ...@@ -1482,14 +1506,6 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
return pdata; return pdata;
} }
#else /* !CONFIG_PCI */
static inline struct pxa2xx_spi_master *
pxa2xx_spi_init_pdata(struct platform_device *pdev)
{
return NULL;
}
#endif
static int pxa2xx_spi_fw_translate_cs(struct spi_controller *master, static int pxa2xx_spi_fw_translate_cs(struct spi_controller *master,
unsigned int cs) unsigned int cs)
{ {
...@@ -1764,14 +1780,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev) ...@@ -1764,14 +1780,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
return 0; return 0;
} }
static void pxa2xx_spi_shutdown(struct platform_device *pdev)
{
int status = 0;
if ((status = pxa2xx_spi_remove(pdev)) != 0)
dev_err(&pdev->dev, "shutdown failed with %d\n", status);
}
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int pxa2xx_spi_suspend(struct device *dev) static int pxa2xx_spi_suspend(struct device *dev)
{ {
...@@ -1808,13 +1816,7 @@ static int pxa2xx_spi_resume(struct device *dev) ...@@ -1808,13 +1816,7 @@ static int pxa2xx_spi_resume(struct device *dev)
lpss_ssp_setup(drv_data); lpss_ssp_setup(drv_data);
/* Start the queue running */ /* Start the queue running */
status = spi_controller_resume(drv_data->master); return spi_controller_resume(drv_data->master);
if (status != 0) {
dev_err(dev, "problem starting queue (%d)\n", status);
return status;
}
return 0;
} }
#endif #endif
...@@ -1848,10 +1850,10 @@ static struct platform_driver driver = { ...@@ -1848,10 +1850,10 @@ static struct platform_driver driver = {
.name = "pxa2xx-spi", .name = "pxa2xx-spi",
.pm = &pxa2xx_spi_pm_ops, .pm = &pxa2xx_spi_pm_ops,
.acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match), .acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match),
.of_match_table = of_match_ptr(pxa2xx_spi_of_match),
}, },
.probe = pxa2xx_spi_probe, .probe = pxa2xx_spi_probe,
.remove = pxa2xx_spi_remove, .remove = pxa2xx_spi_remove,
.shutdown = pxa2xx_spi_shutdown,
}; };
static int __init pxa2xx_spi_init(void) static int __init pxa2xx_spi_init(void)
......
This diff is collapsed.
...@@ -159,7 +159,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev) ...@@ -159,7 +159,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
master->bus_num = 0; master->bus_num = 0;
master->num_chipselect = 3; master->num_chipselect = 3;
master->mode_bits = SPI_TX_DUAL; master->mode_bits = SPI_TX_DUAL;
master->bits_per_word_mask = BIT(7); master->bits_per_word_mask = SPI_BPW_MASK(8);
master->flags = SPI_MASTER_MUST_TX; master->flags = SPI_MASTER_MUST_TX;
master->transfer_one = rb4xx_transfer_one; master->transfer_one = rb4xx_transfer_one;
master->set_cs = rb4xx_set_cs; master->set_cs = rb4xx_set_cs;
......
...@@ -164,7 +164,6 @@ enum rockchip_ssi_type { ...@@ -164,7 +164,6 @@ enum rockchip_ssi_type {
struct rockchip_spi_dma_data { struct rockchip_spi_dma_data {
struct dma_chan *ch; struct dma_chan *ch;
enum dma_transfer_direction direction;
dma_addr_t addr; dma_addr_t addr;
}; };
...@@ -202,12 +201,11 @@ struct rockchip_spi { ...@@ -202,12 +201,11 @@ struct rockchip_spi {
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
u32 use_dma; bool use_dma;
struct sg_table tx_sg; struct sg_table tx_sg;
struct sg_table rx_sg; struct sg_table rx_sg;
struct rockchip_spi_dma_data dma_rx; struct rockchip_spi_dma_data dma_rx;
struct rockchip_spi_dma_data dma_tx; struct rockchip_spi_dma_data dma_tx;
struct dma_slave_caps dma_caps;
}; };
static inline void spi_enable_chip(struct rockchip_spi *rs, int enable) static inline void spi_enable_chip(struct rockchip_spi *rs, int enable)
...@@ -381,6 +379,8 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs) ...@@ -381,6 +379,8 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
{ {
int remain = 0; int remain = 0;
spi_enable_chip(rs, 1);
do { do {
if (rs->tx) { if (rs->tx) {
remain = rs->tx_end - rs->tx; remain = rs->tx_end - rs->tx;
...@@ -455,19 +455,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) ...@@ -455,19 +455,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
rxdesc = NULL; rxdesc = NULL;
if (rs->rx) { if (rs->rx) {
rxconf.direction = rs->dma_rx.direction; rxconf.direction = DMA_DEV_TO_MEM;
rxconf.src_addr = rs->dma_rx.addr; rxconf.src_addr = rs->dma_rx.addr;
rxconf.src_addr_width = rs->n_bytes; rxconf.src_addr_width = rs->n_bytes;
if (rs->dma_caps.max_burst > 4) rxconf.src_maxburst = 1;
rxconf.src_maxburst = 4;
else
rxconf.src_maxburst = 1;
dmaengine_slave_config(rs->dma_rx.ch, &rxconf); dmaengine_slave_config(rs->dma_rx.ch, &rxconf);
rxdesc = dmaengine_prep_slave_sg( rxdesc = dmaengine_prep_slave_sg(
rs->dma_rx.ch, rs->dma_rx.ch,
rs->rx_sg.sgl, rs->rx_sg.nents, rs->rx_sg.sgl, rs->rx_sg.nents,
rs->dma_rx.direction, DMA_PREP_INTERRUPT); DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!rxdesc) if (!rxdesc)
return -EINVAL; return -EINVAL;
...@@ -477,19 +474,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) ...@@ -477,19 +474,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
txdesc = NULL; txdesc = NULL;
if (rs->tx) { if (rs->tx) {
txconf.direction = rs->dma_tx.direction; txconf.direction = DMA_MEM_TO_DEV;
txconf.dst_addr = rs->dma_tx.addr; txconf.dst_addr = rs->dma_tx.addr;
txconf.dst_addr_width = rs->n_bytes; txconf.dst_addr_width = rs->n_bytes;
if (rs->dma_caps.max_burst > 4) txconf.dst_maxburst = rs->fifo_len / 2;
txconf.dst_maxburst = 4;
else
txconf.dst_maxburst = 1;
dmaengine_slave_config(rs->dma_tx.ch, &txconf); dmaengine_slave_config(rs->dma_tx.ch, &txconf);
txdesc = dmaengine_prep_slave_sg( txdesc = dmaengine_prep_slave_sg(
rs->dma_tx.ch, rs->dma_tx.ch,
rs->tx_sg.sgl, rs->tx_sg.nents, rs->tx_sg.sgl, rs->tx_sg.nents,
rs->dma_tx.direction, DMA_PREP_INTERRUPT); DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!txdesc) { if (!txdesc) {
if (rxdesc) if (rxdesc)
dmaengine_terminate_sync(rs->dma_rx.ch); dmaengine_terminate_sync(rs->dma_rx.ch);
...@@ -509,6 +503,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) ...@@ -509,6 +503,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
dma_async_issue_pending(rs->dma_rx.ch); dma_async_issue_pending(rs->dma_rx.ch);
} }
spi_enable_chip(rs, 1);
if (txdesc) { if (txdesc) {
spin_lock_irqsave(&rs->lock, flags); spin_lock_irqsave(&rs->lock, flags);
rs->state |= TXBUSY; rs->state |= TXBUSY;
...@@ -517,7 +513,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs) ...@@ -517,7 +513,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
dma_async_issue_pending(rs->dma_tx.ch); dma_async_issue_pending(rs->dma_tx.ch);
} }
return 0; /* 1 means the transfer is in progress */
return 1;
} }
static void rockchip_spi_config(struct rockchip_spi *rs) static void rockchip_spi_config(struct rockchip_spi *rs)
...@@ -581,7 +578,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs) ...@@ -581,7 +578,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMATDLR); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
...@@ -600,7 +597,6 @@ static int rockchip_spi_transfer_one( ...@@ -600,7 +597,6 @@ static int rockchip_spi_transfer_one(
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
int ret = 0;
struct rockchip_spi *rs = spi_master_get_devdata(master); struct rockchip_spi *rs = spi_master_get_devdata(master);
WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
...@@ -638,30 +634,16 @@ static int rockchip_spi_transfer_one( ...@@ -638,30 +634,16 @@ static int rockchip_spi_transfer_one(
/* we need prepare dma before spi was enabled */ /* we need prepare dma before spi was enabled */
if (master->can_dma && master->can_dma(master, spi, xfer)) if (master->can_dma && master->can_dma(master, spi, xfer))
rs->use_dma = 1; rs->use_dma = true;
else else
rs->use_dma = 0; rs->use_dma = false;
rockchip_spi_config(rs); rockchip_spi_config(rs);
if (rs->use_dma) { if (rs->use_dma)
if (rs->tmode == CR0_XFM_RO) { return rockchip_spi_prepare_dma(rs);
/* rx: dma must be prepared first */
ret = rockchip_spi_prepare_dma(rs);
spi_enable_chip(rs, 1);
} else {
/* tx or tr: spi must be enabled first */
spi_enable_chip(rs, 1);
ret = rockchip_spi_prepare_dma(rs);
}
/* successful DMA prepare means the transfer is in progress */
ret = ret ? ret : 1;
} else {
spi_enable_chip(rs, 1);
ret = rockchip_spi_pio_transfer(rs);
}
return ret; return rockchip_spi_pio_transfer(rs);
} }
static bool rockchip_spi_can_dma(struct spi_master *master, static bool rockchip_spi_can_dma(struct spi_master *master,
...@@ -783,11 +765,8 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -783,11 +765,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)
} }
if (rs->dma_tx.ch && rs->dma_rx.ch) { if (rs->dma_tx.ch && rs->dma_rx.ch) {
dma_get_slave_caps(rs->dma_rx.ch, &(rs->dma_caps));
rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR); rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR); rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
rs->dma_tx.direction = DMA_MEM_TO_DEV;
rs->dma_rx.direction = DMA_DEV_TO_MEM;
master->can_dma = rockchip_spi_can_dma; master->can_dma = rockchip_spi_can_dma;
master->dma_tx = rs->dma_tx.ch; master->dma_tx = rs->dma_tx.ch;
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* SH RSPI driver * SH RSPI driver
* *
...@@ -6,15 +7,6 @@ ...@@ -6,15 +7,6 @@
* *
* Based on spi-sh.c: * Based on spi-sh.c:
* Copyright (C) 2011 Renesas Solutions Corp. * Copyright (C) 2011 Renesas Solutions Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/module.h> #include <linux/module.h>
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* SuperH HSPI bus driver * SuperH HSPI bus driver
* *
...@@ -7,15 +8,6 @@ ...@@ -7,15 +8,6 @@
* Based on pxa2xx_spi.c: * Based on pxa2xx_spi.c:
* Copyright (C) 2011 Renesas Solutions Corp. * Copyright (C) 2011 Renesas Solutions Corp.
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/clk.h> #include <linux/clk.h>
...@@ -316,6 +308,6 @@ static struct platform_driver hspi_driver = { ...@@ -316,6 +308,6 @@ static struct platform_driver hspi_driver = {
module_platform_driver(hspi_driver); module_platform_driver(hspi_driver);
MODULE_DESCRIPTION("SuperH HSPI bus driver"); MODULE_DESCRIPTION("SuperH HSPI bus driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_ALIAS("platform:sh-hspi"); MODULE_ALIAS("platform:sh-hspi");
// SPDX-License-Identifier: GPL-2.0
/* /*
* SuperH MSIOF SPI Master Interface * SuperH MSIOF SPI Master Interface
* *
* Copyright (c) 2009 Magnus Damm * Copyright (c) 2009 Magnus Damm
* Copyright (C) 2014 Renesas Electronics Corporation * Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2014-2017 Glider bvba * Copyright (C) 2014-2017 Glider bvba
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/ */
#include <linux/bitmap.h> #include <linux/bitmap.h>
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* SH SPI bus driver * SH SPI bus driver
* *
...@@ -5,15 +6,6 @@ ...@@ -5,15 +6,6 @@
* *
* Based on pxa2xx_spi.c: * Based on pxa2xx_spi.c:
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -522,6 +514,6 @@ static struct platform_driver spi_sh_driver = { ...@@ -522,6 +514,6 @@ static struct platform_driver spi_sh_driver = {
module_platform_driver(spi_sh_driver); module_platform_driver(spi_sh_driver);
MODULE_DESCRIPTION("SH SPI bus driver"); MODULE_DESCRIPTION("SH SPI bus driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Yoshihiro Shimoda"); MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_ALIAS("platform:sh_spi"); MODULE_ALIAS("platform:sh_spi");
This diff is collapsed.
...@@ -60,6 +60,7 @@ static void spi_slave_system_control_complete(void *arg) ...@@ -60,6 +60,7 @@ static void spi_slave_system_control_complete(void *arg)
case CMD_REBOOT: case CMD_REBOOT:
dev_info(&priv->spi->dev, "Rebooting system...\n"); dev_info(&priv->spi->dev, "Rebooting system...\n");
kernel_restart(NULL); kernel_restart(NULL);
break;
case CMD_POWEROFF: case CMD_POWEROFF:
dev_info(&priv->spi->dev, "Powering off system...\n"); dev_info(&priv->spi->dev, "Powering off system...\n");
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* SPI init/core code * SPI init/core code
* *
* Copyright (C) 2005 David Brownell * Copyright (C) 2005 David Brownell
* Copyright (C) 2008 Secret Lab Technologies Ltd. * Copyright (C) 2008 Secret Lab Technologies Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -60,6 +51,7 @@ static void spidev_release(struct device *dev) ...@@ -60,6 +51,7 @@ static void spidev_release(struct device *dev)
spi->controller->cleanup(spi); spi->controller->cleanup(spi);
spi_controller_put(spi->controller); spi_controller_put(spi->controller);
kfree(spi->driver_override);
kfree(spi); kfree(spi);
} }
...@@ -77,6 +69,51 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf) ...@@ -77,6 +69,51 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
} }
static DEVICE_ATTR_RO(modalias); static DEVICE_ATTR_RO(modalias);
static ssize_t driver_override_store(struct device *dev,
struct device_attribute *a,
const char *buf, size_t count)
{
struct spi_device *spi = to_spi_device(dev);
const char *end = memchr(buf, '\n', count);
const size_t len = end ? end - buf : count;
const char *driver_override, *old;
/* We need to keep extra room for a newline when displaying value */
if (len >= (PAGE_SIZE - 1))
return -EINVAL;
driver_override = kstrndup(buf, len, GFP_KERNEL);
if (!driver_override)
return -ENOMEM;
device_lock(dev);
old = spi->driver_override;
if (len) {
spi->driver_override = driver_override;
} else {
/* Emptry string, disable driver override */
spi->driver_override = NULL;
kfree(driver_override);
}
device_unlock(dev);
kfree(old);
return count;
}
static ssize_t driver_override_show(struct device *dev,
struct device_attribute *a, char *buf)
{
const struct spi_device *spi = to_spi_device(dev);
ssize_t len;
device_lock(dev);
len = snprintf(buf, PAGE_SIZE, "%s\n", spi->driver_override ? : "");
device_unlock(dev);
return len;
}
static DEVICE_ATTR_RW(driver_override);
#define SPI_STATISTICS_ATTRS(field, file) \ #define SPI_STATISTICS_ATTRS(field, file) \
static ssize_t spi_controller_##field##_show(struct device *dev, \ static ssize_t spi_controller_##field##_show(struct device *dev, \
struct device_attribute *attr, \ struct device_attribute *attr, \
...@@ -158,6 +195,7 @@ SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu"); ...@@ -158,6 +195,7 @@ SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");
static struct attribute *spi_dev_attrs[] = { static struct attribute *spi_dev_attrs[] = {
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
&dev_attr_driver_override.attr,
NULL, NULL,
}; };
...@@ -305,6 +343,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) ...@@ -305,6 +343,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
const struct spi_device *spi = to_spi_device(dev); const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv); const struct spi_driver *sdrv = to_spi_driver(drv);
/* Check override first, and if set, only use the named driver */
if (spi->driver_override)
return strcmp(spi->driver_override, drv->name) == 0;
/* Attempt an OF style match */ /* Attempt an OF style match */
if (of_driver_match_device(dev, drv)) if (of_driver_match_device(dev, drv))
return 1; return 1;
...@@ -733,7 +775,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable) ...@@ -733,7 +775,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
enable = !enable; enable = !enable;
if (gpio_is_valid(spi->cs_gpio)) { if (gpio_is_valid(spi->cs_gpio)) {
gpio_set_value(spi->cs_gpio, !enable); /* Honour the SPI_NO_CS flag */
if (!(spi->mode & SPI_NO_CS))
gpio_set_value(spi->cs_gpio, !enable);
/* Some SPI masters need both GPIO CS & slave_select */ /* Some SPI masters need both GPIO CS & slave_select */
if ((spi->controller->flags & SPI_MASTER_GPIO_SS) && if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&
spi->controller->set_cs) spi->controller->set_cs)
...@@ -2783,8 +2827,10 @@ int spi_setup(struct spi_device *spi) ...@@ -2783,8 +2827,10 @@ int spi_setup(struct spi_device *spi)
return -EINVAL; return -EINVAL;
/* help drivers fail *cleanly* when they need options /* help drivers fail *cleanly* when they need options
* that aren't supported with their current controller * that aren't supported with their current controller
* SPI_CS_WORD has a fallback software implementation,
* so it is ignored here.
*/ */
bad_bits = spi->mode & ~spi->controller->mode_bits; bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD);
ugly_bits = bad_bits & ugly_bits = bad_bits &
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD); (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
if (ugly_bits) { if (ugly_bits) {
...@@ -2838,6 +2884,35 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) ...@@ -2838,6 +2884,35 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
if (list_empty(&message->transfers)) if (list_empty(&message->transfers))
return -EINVAL; return -EINVAL;
/* If an SPI controller does not support toggling the CS line on each
* transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
* for the CS line, we can emulate the CS-per-word hardware function by
* splitting transfers into one-word transfers and ensuring that
* cs_change is set for each transfer.
*/
if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
gpio_is_valid(spi->cs_gpio))) {
size_t maxsize;
int ret;
maxsize = (spi->bits_per_word + 7) / 8;
/* spi_split_transfers_maxsize() requires message->spi */
message->spi = spi;
ret = spi_split_transfers_maxsize(ctlr, message, maxsize,
GFP_KERNEL);
if (ret)
return ret;
list_for_each_entry(xfer, &message->transfers, transfer_list) {
/* don't change cs_change on the last entry in the list */
if (list_is_last(&xfer->transfer_list, &message->transfers))
break;
xfer->cs_change = 1;
}
}
/* Half-duplex links include original MicroWire, and ones with /* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where * only one data pin like SPI_3WIRE (switches direction) or where
* either MOSI or MISO is missing. They can also be caused by * either MOSI or MISO is missing. They can also be caused by
......
...@@ -669,6 +669,7 @@ static const struct of_device_id spidev_dt_ids[] = { ...@@ -669,6 +669,7 @@ static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "lineartechnology,ltc2488" }, { .compatible = "lineartechnology,ltc2488" },
{ .compatible = "ge,achc" }, { .compatible = "ge,achc" },
{ .compatible = "semtech,sx1301" }, { .compatible = "semtech,sx1301" },
{ .compatible = "lwn,bk4" },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, spidev_dt_ids); MODULE_DEVICE_TABLE(of, spidev_dt_ids);
...@@ -724,11 +725,9 @@ static int spidev_probe(struct spi_device *spi) ...@@ -724,11 +725,9 @@ static int spidev_probe(struct spi_device *spi)
* compatible string, it is a Linux implementation thing * compatible string, it is a Linux implementation thing
* rather than a description of the hardware. * rather than a description of the hardware.
*/ */
if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) { WARN(spi->dev.of_node &&
dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n"); of_device_is_compatible(spi->dev.of_node, "spidev"),
WARN_ON(spi->dev.of_node && "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
!of_match_device(spidev_dt_ids, &spi->dev));
}
spidev_probe_acpi(spi); spidev_probe_acpi(spi);
......
...@@ -1705,6 +1705,10 @@ static inline int pci_irqd_intx_xlate(struct irq_domain *d, ...@@ -1705,6 +1705,10 @@ static inline int pci_irqd_intx_xlate(struct irq_domain *d,
unsigned long *out_hwirq, unsigned long *out_hwirq,
unsigned int *out_type) unsigned int *out_type)
{ return -EINVAL; } { return -EINVAL; }
static inline const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
struct pci_dev *dev)
{ return NULL; }
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
/* Include architecture-dependent settings and functions */ /* Include architecture-dependent settings and functions */
......
...@@ -36,9 +36,6 @@ enum { ...@@ -36,9 +36,6 @@ enum {
* @num_chipselect: number of chipselects supported by this SPI master * @num_chipselect: number of chipselects supported by this SPI master
* @intr_line: interrupt line used to connect the SPI IP to the ARM interrupt * @intr_line: interrupt line used to connect the SPI IP to the ARM interrupt
* controller withn the SoC. Possible values are 0 and 1. * controller withn the SoC. Possible values are 0 and 1.
* @chip_sel: list of GPIOs which can act as chip-selects for the SPI.
* SPI_INTERN_CS denotes internal SPI chip-select. Not necessary
* to populate if all chip-selects are internal.
* @cshold_bug: set this to true if the SPI controller on your chip requires * @cshold_bug: set this to true if the SPI controller on your chip requires
* a write to CSHOLD bit in between transfers (like in DM355). * a write to CSHOLD bit in between transfers (like in DM355).
* @dma_event_q: DMA event queue to use if SPI_IO_TYPE_DMA is used for any * @dma_event_q: DMA event queue to use if SPI_IO_TYPE_DMA is used for any
...@@ -48,7 +45,6 @@ struct davinci_spi_platform_data { ...@@ -48,7 +45,6 @@ struct davinci_spi_platform_data {
u8 version; u8 version;
u8 num_chipselect; u8 num_chipselect;
u8 intr_line; u8 intr_line;
u8 *chip_sel;
u8 prescaler_limit; u8 prescaler_limit;
bool cshold_bug; bool cshold_bug;
enum dma_event_q dma_event_q; enum dma_event_q dma_event_q;
......
...@@ -196,6 +196,7 @@ enum pxa_ssp_type { ...@@ -196,6 +196,7 @@ enum pxa_ssp_type {
PXA27x_SSP, PXA27x_SSP,
PXA3xx_SSP, PXA3xx_SSP,
PXA168_SSP, PXA168_SSP,
MMP2_SSP,
PXA910_SSP, PXA910_SSP,
CE4100_SSP, CE4100_SSP,
QUARK_X1000_SSP, QUARK_X1000_SSP,
...@@ -217,7 +218,7 @@ struct ssp_device { ...@@ -217,7 +218,7 @@ struct ssp_device {
const char *label; const char *label;
int port_id; int port_id;
int type; enum pxa_ssp_type type;
int use_count; int use_count;
int irq; int irq;
......
...@@ -225,19 +225,14 @@ struct geni_se { ...@@ -225,19 +225,14 @@ struct geni_se {
#define HW_VER_MINOR_SHFT 16 #define HW_VER_MINOR_SHFT 16
#define HW_VER_STEP_MASK GENMASK(15, 0) #define HW_VER_STEP_MASK GENMASK(15, 0)
#define GENI_SE_VERSION_MAJOR(ver) ((ver & HW_VER_MAJOR_MASK) >> HW_VER_MAJOR_SHFT)
#define GENI_SE_VERSION_MINOR(ver) ((ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT)
#define GENI_SE_VERSION_STEP(ver) (ver & HW_VER_STEP_MASK)
#if IS_ENABLED(CONFIG_QCOM_GENI_SE) #if IS_ENABLED(CONFIG_QCOM_GENI_SE)
u32 geni_se_get_qup_hw_version(struct geni_se *se); u32 geni_se_get_qup_hw_version(struct geni_se *se);
#define geni_se_get_wrapper_version(se, major, minor, step) do { \
u32 ver; \
\
ver = geni_se_get_qup_hw_version(se); \
major = (ver & HW_VER_MAJOR_MASK) >> HW_VER_MAJOR_SHFT; \
minor = (ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT; \
step = version & HW_VER_STEP_MASK; \
} while (0)
/** /**
* geni_se_read_proto() - Read the protocol configured for a serial engine * geni_se_read_proto() - Read the protocol configured for a serial engine
* @se: Pointer to the concerned serial engine. * @se: Pointer to the concerned serial engine.
......
/* /* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright (C) 2005 David Brownell
* *
* This program is free software; you can redistribute it and/or modify * Copyright (C) 2005 David Brownell
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#ifndef __LINUX_SPI_H #ifndef __LINUX_SPI_H
...@@ -163,10 +154,12 @@ struct spi_device { ...@@ -163,10 +154,12 @@ struct spi_device {
#define SPI_TX_QUAD 0x200 /* transmit with 4 wires */ #define SPI_TX_QUAD 0x200 /* transmit with 4 wires */
#define SPI_RX_DUAL 0x400 /* receive with 2 wires */ #define SPI_RX_DUAL 0x400 /* receive with 2 wires */
#define SPI_RX_QUAD 0x800 /* receive with 4 wires */ #define SPI_RX_QUAD 0x800 /* receive with 4 wires */
#define SPI_CS_WORD 0x1000 /* toggle cs after each word */
int irq; int irq;
void *controller_state; void *controller_state;
void *controller_data; void *controller_data;
char modalias[SPI_NAME_SIZE]; char modalias[SPI_NAME_SIZE];
const char *driver_override;
int cs_gpio; /* chip select gpio */ int cs_gpio; /* chip select gpio */
/* the statistics */ /* the statistics */
...@@ -177,7 +170,6 @@ struct spi_device { ...@@ -177,7 +170,6 @@ struct spi_device {
* the controller talks to each chip, like: * the controller talks to each chip, like:
* - memory packing (12 bit samples into low bits, others zeroed) * - memory packing (12 bit samples into low bits, others zeroed)
* - priority * - priority
* - drop chipselect after each word
* - chipselect delays * - chipselect delays
* - ... * - ...
*/ */
...@@ -711,6 +703,8 @@ extern void spi_res_release(struct spi_controller *ctlr, ...@@ -711,6 +703,8 @@ extern void spi_res_release(struct spi_controller *ctlr,
* @delay_usecs: microseconds to delay after this transfer before * @delay_usecs: microseconds to delay after this transfer before
* (optionally) changing the chipselect status, then starting * (optionally) changing the chipselect status, then starting
* the next transfer or completing this @spi_message. * the next transfer or completing this @spi_message.
* @word_delay: clock cycles to inter word delay after each word size
* (set by bits_per_word) transmission.
* @transfer_list: transfers are sequenced through @spi_message.transfers * @transfer_list: transfers are sequenced through @spi_message.transfers
* @tx_sg: Scatterlist for transmit, currently not for client use * @tx_sg: Scatterlist for transmit, currently not for client use
* @rx_sg: Scatterlist for receive, currently not for client use * @rx_sg: Scatterlist for receive, currently not for client use
...@@ -793,6 +787,7 @@ struct spi_transfer { ...@@ -793,6 +787,7 @@ struct spi_transfer {
u8 bits_per_word; u8 bits_per_word;
u16 delay_usecs; u16 delay_usecs;
u32 speed_hz; u32 speed_hz;
u16 word_delay;
struct list_head transfer_list; struct list_head transfer_list;
}; };
......
...@@ -73,12 +73,12 @@ static void hex_dump(const void *src, size_t length, size_t line_size, ...@@ -73,12 +73,12 @@ static void hex_dump(const void *src, size_t length, size_t line_size,
while (i++ % line_size) while (i++ % line_size)
printf("__ "); printf("__ ");
} }
printf(" | "); /* right close */ printf(" |");
while (line < address) { while (line < address) {
c = *line++; c = *line++;
printf("%c", (c < 33 || c == 255) ? 0x2E : c); printf("%c", (c < 32 || c > 126) ? '.' : c);
} }
printf("\n"); printf("|\n");
if (length > 0) if (length > 0)
printf("%s | ", prefix); printf("%s | ", prefix);
} }
......
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