Commit 5a602e15 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull spi updates from Mark Brown:
 "No framework updates for the SPI API this time around aside from one
  small fix, just driver improvments.  Some highlights include:

   - New driver support for CSR USP, Mikrotik RB4xx and Zynq GQSPI
     controllers.

   - Modernisation of the OMAP McSPI controller driver, moving it to
     current APIs to enable support for a wider range of client drivers.

   - DMA support for the bcm2835 controller"

* tag 'spi-v4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (60 commits)
  spi: zynq: Remove execute bit
  spi: atmel: add support to FIFOs
  spi: atmel: update DT bindings documentation
  spi: spi-fsl-dspi: Update DT binding documentation
  spi: pxa2xx: Constify ACPI device ids
  spi: Add support for Zynq Ultrascale+ MPSoC GQSPI controller
  spi: zynq: Add DT bindings documentation for Zynq Ultrascale+ MPSoC GQSPI controller
  spi: fsl-dspi: Use pinctrl PM helpers
  spi: davinci: change the lower limit of pre-scale divider to 1
  spi: spi-fsl-dspi: Change the way of increasing spi_message->actual_length
  spi: spi-fsl-dspi: Enable TCF interrupt mode support
  spi: atmel: add support for the internal chip-select of the spi controller
  spi: spi-pxa2xx: remove legacy PXA DMA bits
  spi: pxa2xx: Make LPSS SPI general register optional
  spi: pxa2xx: Prepare for new Intel LPSS SPI type
  spi: pxa2xx: Differentiate Intel LPSS types
  spi: restore rx/tx_buf in case of unset CONFIG_HAS_DMA
  spi: rspi: Re-do the returning value of qspi_transfer_out_in
  spi: rspi: modify the name of "qspi_trigger_transfer_out_int" function
  spi: orion: Fix extended baud rates for each Armada SoCs
  ...
parents e12bdf0d fda052b0
Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller
Required properties:
- compatible: has to be "qca,<soc-type>-spi", "qca,ar7100-spi" as fallback.
- reg: Base address and size of the controllers memory area
- clocks: phandle to the AHB clock.
- clock-names: has to be "ahb".
- #address-cells: <1>, as required by generic SPI binding.
- #size-cells: <0>, also as required by generic SPI binding.
Child nodes as per the generic SPI binding.
Example:
spi@1F000000 {
compatible = "qca,ar9132-spi", "qca,ar7100-spi";
reg = <0x1F000000 0x10>;
clocks = <&pll 2>;
clock-names = "ahb";
#address-cells = <1>;
#size-cells = <0>;
};
ARM Freescale DSPI controller ARM Freescale DSPI controller
Required properties: Required properties:
- compatible : "fsl,vf610-dspi" - compatible : "fsl,vf610-dspi", "fsl,ls1021a-v1.0-dspi", "fsl,ls2085a-dspi"
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt - interrupts : Should contain SPI controller interrupt
- clocks: from common clock binding: handle to dspi clock. - clocks: from common clock binding: handle to dspi clock.
......
Marvell Orion SPI device Marvell Orion SPI device
Required properties: Required properties:
- compatible : should be "marvell,orion-spi" or "marvell,armada-370-spi". - compatible : should be on of the following:
- "marvell,orion-spi" for the Orion, mv78x00, Kirkwood and Dove SoCs
- "marvell,armada-370-spi", for the Armada 370 SoCs
- "marvell,armada-375-spi", for the Armada 375 SoCs
- "marvell,armada-380-spi", for the Armada 38x SoCs
- "marvell,armada-390-spi", for the Armada 39x SoCs
- "marvell,armada-xp-spi", for the Armada XP SoCs
- reg : offset and length of the register set for the device - reg : offset and length of the register set for the device
- cell-index : Which of multiple SPI controllers is this. - cell-index : Which of multiple SPI controllers is this.
Optional properties: Optional properties:
......
* CSR SiRFprimaII Serial Peripheral Interface * CSR SiRFprimaII Serial Peripheral Interface
Required properties: Required properties:
- compatible : Should be "sirf,prima2-spi" - compatible : Should be "sirf,prima2-spi", "sirf,prima2-usp"
or "sirf,atlas7-usp"
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- interrupts : Should contain SPI interrupt - interrupts : Should contain SPI interrupt
- resets: phandle to the reset controller asserting this device in - resets: phandle to the reset controller asserting this device in
......
Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings
-------------------------------------------------------------------
Required properties:
- compatible : Should be "xlnx,zynqmp-qspi-1.0".
- reg : Physical base address and size of GQSPI registers map.
- interrupts : Property with a value describing the interrupt
number.
- interrupt-parent : Must be core interrupt controller.
- clock-names : List of input clock names - "ref_clk", "pclk"
(See clock bindings for details).
- clocks : Clock phandles (see clock bindings for details).
Optional properties:
- num-cs : Number of chip selects used.
Example:
qspi: spi@ff0f0000 {
compatible = "xlnx,zynqmp-qspi-1.0";
clock-names = "ref_clk", "pclk";
clocks = <&misc_clk &misc_clk>;
interrupts = <0 15 4>;
interrupt-parent = <&gic>;
num-cs = <1>;
reg = <0x0 0xff0f0000 0x1000>,<0x0 0xc0000000 0x8000000>;
};
...@@ -4,11 +4,16 @@ Required properties: ...@@ -4,11 +4,16 @@ Required properties:
- compatible : should be "atmel,at91rm9200-spi". - compatible : should be "atmel,at91rm9200-spi".
- reg: Address and length of the register set for the device - reg: Address and length of the register set for the device
- interrupts: Should contain spi interrupt - interrupts: Should contain spi interrupt
- cs-gpios: chipselects - cs-gpios: chipselects (optional for SPI controller version >= 2 with the
Chip Select Active After Transfer feature).
- clock-names: tuple listing input clock names. - clock-names: tuple listing input clock names.
Required elements: "spi_clk" Required elements: "spi_clk"
- clocks: phandles to input clocks. - clocks: phandles to input clocks.
Optional properties:
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
capable SPI controllers.
Example: Example:
spi1: spi@fffcc000 { spi1: spi@fffcc000 {
...@@ -20,6 +25,7 @@ spi1: spi@fffcc000 { ...@@ -20,6 +25,7 @@ spi1: spi@fffcc000 {
clocks = <&spi1_clk>; clocks = <&spi1_clk>;
clock-names = "spi_clk"; clock-names = "spi_clk";
cs-gpios = <&pioB 3 0>; cs-gpios = <&pioB 3 0>;
atmel,fifo-size = <32>;
status = "okay"; status = "okay";
mmc-slot@0 { mmc-slot@0 {
......
...@@ -4,9 +4,9 @@ Required properties: ...@@ -4,9 +4,9 @@ Required properties:
- compatible : "arm,pl022", "arm,primecell" - compatible : "arm,pl022", "arm,primecell"
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt - interrupts : Should contain SPI controller interrupt
- num-cs : total number of chipselects
Optional properties: Optional properties:
- num-cs : total number of chipselects
- cs-gpios : should specify GPIOs used for chipselects. - cs-gpios : should specify GPIOs used for chipselects.
The gpios will be referred to as reg = <index> in the SPI child nodes. The gpios will be referred to as reg = <index> in the SPI child nodes.
If unspecified, a single SPI device without a chip select can be used. If unspecified, a single SPI device without a chip select can be used.
......
...@@ -16,8 +16,4 @@ struct ath79_spi_platform_data { ...@@ -16,8 +16,4 @@ struct ath79_spi_platform_data {
unsigned num_chipselect; unsigned num_chipselect;
}; };
struct ath79_spi_controller_data {
unsigned gpio;
};
#endif /* _ATH79_SPI_PLATFORM_H */ #endif /* _ATH79_SPI_PLATFORM_H */
...@@ -77,6 +77,7 @@ config SPI_ATMEL ...@@ -77,6 +77,7 @@ config SPI_ATMEL
config SPI_BCM2835 config SPI_BCM2835
tristate "BCM2835 SPI controller" tristate "BCM2835 SPI controller"
depends on GPIOLIB
depends on ARCH_BCM2835 || COMPILE_TEST depends on ARCH_BCM2835 || COMPILE_TEST
depends on GPIOLIB depends on GPIOLIB
help help
...@@ -221,7 +222,7 @@ config SPI_FALCON ...@@ -221,7 +222,7 @@ config SPI_FALCON
config SPI_GPIO config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master" tristate "GPIO-based bitbanging SPI Master"
depends on GPIOLIB depends on GPIOLIB || COMPILE_TEST
select SPI_BITBANG select SPI_BITBANG
help help
This simple GPIO bitbanging SPI master uses the arch-neutral GPIO This simple GPIO bitbanging SPI master uses the arch-neutral GPIO
...@@ -327,7 +328,7 @@ config SPI_MESON_SPIFC ...@@ -327,7 +328,7 @@ config SPI_MESON_SPIFC
config SPI_OC_TINY config SPI_OC_TINY
tristate "OpenCores tiny SPI" tristate "OpenCores tiny SPI"
depends on GPIOLIB depends on GPIOLIB || COMPILE_TEST
select SPI_BITBANG select SPI_BITBANG
help help
This is the driver for OpenCores tiny SPI master controller. This is the driver for OpenCores tiny SPI master controller.
...@@ -394,16 +395,9 @@ config SPI_PPC4xx ...@@ -394,16 +395,9 @@ config SPI_PPC4xx
help help
This selects a driver for the PPC4xx SPI Controller. This selects a driver for the PPC4xx SPI Controller.
config SPI_PXA2XX_PXADMA
bool "PXA2xx SSP legacy PXA DMA API support"
depends on SPI_PXA2XX && ARCH_PXA
help
Enable PXA private legacy DMA API support. Note that this is
deprecated in favor of generic DMA engine API.
config SPI_PXA2XX_DMA config SPI_PXA2XX_DMA
def_bool y def_bool y
depends on SPI_PXA2XX && !SPI_PXA2XX_PXADMA depends on SPI_PXA2XX
config SPI_PXA2XX config SPI_PXA2XX
tristate "PXA2xx SSP SPI master" tristate "PXA2xx SSP SPI master"
...@@ -429,6 +423,12 @@ config SPI_ROCKCHIP ...@@ -429,6 +423,12 @@ config SPI_ROCKCHIP
The main usecase of this controller is to use spi flash as boot The main usecase of this controller is to use spi flash as boot
device. device.
config SPI_RB4XX
tristate "Mikrotik RB4XX SPI master"
depends on SPI_MASTER && ATH79
help
SPI controller driver for the Mikrotik RB4xx series boards.
config SPI_RSPI config SPI_RSPI
tristate "Renesas RSPI/QSPI controller" tristate "Renesas RSPI/QSPI controller"
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
...@@ -610,6 +610,12 @@ config SPI_XTENSA_XTFPGA ...@@ -610,6 +610,12 @@ config SPI_XTENSA_XTFPGA
16 bit words in SPI mode 0, automatically asserting CS on transfer 16 bit words in SPI mode 0, automatically asserting CS on transfer
start and deasserting on end. start and deasserting on end.
config SPI_ZYNQMP_GQSPI
tristate "Xilinx ZynqMP GQSPI controller"
depends on SPI_MASTER
help
Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
config SPI_NUC900 config SPI_NUC900
tristate "Nuvoton NUC900 series SPI" tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900 depends on ARCH_W90X900
......
...@@ -60,12 +60,12 @@ obj-$(CONFIG_SPI_ORION) += spi-orion.o ...@@ -60,12 +60,12 @@ obj-$(CONFIG_SPI_ORION) += spi-orion.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-platform-objs := spi-pxa2xx.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += 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_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_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o spi-s3c24xx-hw-y := spi-s3c24xx.o
...@@ -89,3 +89,4 @@ obj-$(CONFIG_SPI_TXX9) += spi-txx9.o ...@@ -89,3 +89,4 @@ obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o
...@@ -79,10 +79,8 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active) ...@@ -79,10 +79,8 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
} }
if (spi->chip_select) { if (spi->chip_select) {
struct ath79_spi_controller_data *cdata = spi->controller_data;
/* SPI is normally active-low */ /* SPI is normally active-low */
gpio_set_value(cdata->gpio, cs_high); gpio_set_value(spi->cs_gpio, cs_high);
} else { } else {
if (cs_high) if (cs_high)
sp->ioc_base |= AR71XX_SPI_IOC_CS0; sp->ioc_base |= AR71XX_SPI_IOC_CS0;
...@@ -117,11 +115,10 @@ static void ath79_spi_disable(struct ath79_spi *sp) ...@@ -117,11 +115,10 @@ static void ath79_spi_disable(struct ath79_spi *sp)
static int ath79_spi_setup_cs(struct spi_device *spi) static int ath79_spi_setup_cs(struct spi_device *spi)
{ {
struct ath79_spi_controller_data *cdata; struct ath79_spi *sp = ath79_spidev_to_sp(spi);
int status; int status;
cdata = spi->controller_data; if (spi->chip_select && !gpio_is_valid(spi->cs_gpio))
if (spi->chip_select && !cdata)
return -EINVAL; return -EINVAL;
status = 0; status = 0;
...@@ -134,8 +131,15 @@ static int ath79_spi_setup_cs(struct spi_device *spi) ...@@ -134,8 +131,15 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
else else
flags |= GPIOF_INIT_HIGH; flags |= GPIOF_INIT_HIGH;
status = gpio_request_one(cdata->gpio, flags, status = gpio_request_one(spi->cs_gpio, flags,
dev_name(&spi->dev)); dev_name(&spi->dev));
} else {
if (spi->mode & SPI_CS_HIGH)
sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
else
sp->ioc_base |= AR71XX_SPI_IOC_CS0;
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
} }
return status; return status;
...@@ -144,8 +148,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi) ...@@ -144,8 +148,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
static void ath79_spi_cleanup_cs(struct spi_device *spi) static void ath79_spi_cleanup_cs(struct spi_device *spi)
{ {
if (spi->chip_select) { if (spi->chip_select) {
struct ath79_spi_controller_data *cdata = spi->controller_data; gpio_free(spi->cs_gpio);
gpio_free(cdata->gpio);
} }
} }
...@@ -217,6 +220,7 @@ static int ath79_spi_probe(struct platform_device *pdev) ...@@ -217,6 +220,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
} }
sp = spi_master_get_devdata(master); sp = spi_master_get_devdata(master);
master->dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, sp); platform_set_drvdata(pdev, sp);
pdata = dev_get_platdata(&pdev->dev); pdata = dev_get_platdata(&pdev->dev);
...@@ -253,7 +257,7 @@ static int ath79_spi_probe(struct platform_device *pdev) ...@@ -253,7 +257,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
goto err_put_master; goto err_put_master;
} }
ret = clk_enable(sp->clk); ret = clk_prepare_enable(sp->clk);
if (ret) if (ret)
goto err_put_master; goto err_put_master;
...@@ -277,7 +281,7 @@ static int ath79_spi_probe(struct platform_device *pdev) ...@@ -277,7 +281,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
err_disable: err_disable:
ath79_spi_disable(sp); ath79_spi_disable(sp);
err_clk_disable: err_clk_disable:
clk_disable(sp->clk); clk_disable_unprepare(sp->clk);
err_put_master: err_put_master:
spi_master_put(sp->bitbang.master); spi_master_put(sp->bitbang.master);
...@@ -290,7 +294,7 @@ static int ath79_spi_remove(struct platform_device *pdev) ...@@ -290,7 +294,7 @@ static int ath79_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&sp->bitbang); spi_bitbang_stop(&sp->bitbang);
ath79_spi_disable(sp); ath79_spi_disable(sp);
clk_disable(sp->clk); clk_disable_unprepare(sp->clk);
spi_master_put(sp->bitbang.master); spi_master_put(sp->bitbang.master);
return 0; return 0;
...@@ -301,12 +305,18 @@ static void ath79_spi_shutdown(struct platform_device *pdev) ...@@ -301,12 +305,18 @@ static void ath79_spi_shutdown(struct platform_device *pdev)
ath79_spi_remove(pdev); ath79_spi_remove(pdev);
} }
static const struct of_device_id ath79_spi_of_match[] = {
{ .compatible = "qca,ar7100-spi", },
{ },
};
static struct platform_driver ath79_spi_driver = { static struct platform_driver ath79_spi_driver = {
.probe = ath79_spi_probe, .probe = ath79_spi_probe,
.remove = ath79_spi_remove, .remove = ath79_spi_remove,
.shutdown = ath79_spi_shutdown, .shutdown = ath79_spi_shutdown,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.of_match_table = ath79_spi_of_match,
}, },
}; };
module_platform_driver(ath79_spi_driver); module_platform_driver(ath79_spi_driver);
......
This diff is collapsed.
This diff is collapsed.
...@@ -265,7 +265,7 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi, ...@@ -265,7 +265,7 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi,
ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz); ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz);
if (ret < 3 || ret > 256) if (ret < 1 || ret > 256)
return -EINVAL; return -EINVAL;
return ret - 1; return ret - 1;
......
This diff is collapsed.
...@@ -561,9 +561,13 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) ...@@ -561,9 +561,13 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
/* spin until TX is done */ /* spin until TX is done */
ret = spin_event_timeout(((events = mpc8xxx_spi_read_reg( ret = spin_event_timeout(((events = mpc8xxx_spi_read_reg(
&reg_base->event)) & SPIE_NF) == 0, 1000, 0); &reg_base->event)) & SPIE_NF), 1000, 0);
if (!ret) { if (!ret) {
dev_err(mspi->dev, "tired waiting for SPIE_NF\n"); dev_err(mspi->dev, "tired waiting for SPIE_NF\n");
/* Clear the SPIE bits */
mpc8xxx_spi_write_reg(&reg_base->event, events);
complete(&mspi->done);
return; return;
} }
} }
......
...@@ -674,7 +674,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { ...@@ -674,7 +674,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.devtype = IMX51_ECSPI, .devtype = IMX51_ECSPI,
}; };
static struct platform_device_id spi_imx_devtype[] = { static const struct platform_device_id spi_imx_devtype[] = {
{ {
.name = "imx1-cspi", .name = "imx1-cspi",
.driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data, .driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data,
......
This diff is collapsed.
...@@ -61,6 +61,12 @@ enum orion_spi_type { ...@@ -61,6 +61,12 @@ enum orion_spi_type {
struct orion_spi_dev { struct orion_spi_dev {
enum orion_spi_type typ; enum orion_spi_type typ;
/*
* min_divisor and max_hz should be exclusive, the only we can
* have both is for managing the armada-370-spi case with old
* device tree
*/
unsigned long max_hz;
unsigned int min_divisor; unsigned int min_divisor;
unsigned int max_divisor; unsigned int max_divisor;
u32 prescale_mask; u32 prescale_mask;
...@@ -385,16 +391,54 @@ static const struct orion_spi_dev orion_spi_dev_data = { ...@@ -385,16 +391,54 @@ static const struct orion_spi_dev orion_spi_dev_data = {
.prescale_mask = ORION_SPI_CLK_PRESCALE_MASK, .prescale_mask = ORION_SPI_CLK_PRESCALE_MASK,
}; };
static const struct orion_spi_dev armada_spi_dev_data = { static const struct orion_spi_dev armada_370_spi_dev_data = {
.typ = ARMADA_SPI, .typ = ARMADA_SPI,
.min_divisor = 1, .min_divisor = 4,
.max_divisor = 1920,
.max_hz = 50000000,
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
};
static const struct orion_spi_dev armada_xp_spi_dev_data = {
.typ = ARMADA_SPI,
.max_hz = 50000000,
.max_divisor = 1920,
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
};
static const struct orion_spi_dev armada_375_spi_dev_data = {
.typ = ARMADA_SPI,
.min_divisor = 15,
.max_divisor = 1920, .max_divisor = 1920,
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK, .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
}; };
static const struct of_device_id orion_spi_of_match_table[] = { static const struct of_device_id orion_spi_of_match_table[] = {
{ .compatible = "marvell,orion-spi", .data = &orion_spi_dev_data, }, {
{ .compatible = "marvell,armada-370-spi", .data = &armada_spi_dev_data, }, .compatible = "marvell,orion-spi",
.data = &orion_spi_dev_data,
},
{
.compatible = "marvell,armada-370-spi",
.data = &armada_370_spi_dev_data,
},
{
.compatible = "marvell,armada-375-spi",
.data = &armada_375_spi_dev_data,
},
{
.compatible = "marvell,armada-380-spi",
.data = &armada_xp_spi_dev_data,
},
{
.compatible = "marvell,armada-390-spi",
.data = &armada_xp_spi_dev_data,
},
{
.compatible = "marvell,armada-xp-spi",
.data = &armada_xp_spi_dev_data,
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, orion_spi_of_match_table); MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
...@@ -454,7 +498,23 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -454,7 +498,23 @@ static int orion_spi_probe(struct platform_device *pdev)
goto out; goto out;
tclk_hz = clk_get_rate(spi->clk); tclk_hz = clk_get_rate(spi->clk);
master->max_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->min_divisor);
/*
* With old device tree, armada-370-spi could be used with
* Armada XP, however for this SoC the maximum frequency is
* 50MHz instead of tclk/4. On Armada 370, tclk cannot be
* higher than 200MHz. So, in order to be able to handle both
* SoCs, we can take the minimum of 50MHz and tclk/4.
*/
if (of_device_is_compatible(pdev->dev.of_node,
"marvell,armada-370-spi"))
master->max_speed_hz = min(devdata->max_hz,
DIV_ROUND_UP(tclk_hz, devdata->min_divisor));
else if (devdata->min_divisor)
master->max_speed_hz =
DIV_ROUND_UP(tclk_hz, devdata->min_divisor);
else
master->max_speed_hz = devdata->max_hz;
master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor); master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......
...@@ -62,7 +62,7 @@ static struct pxa_spi_info spi_info_configs[] = { ...@@ -62,7 +62,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.max_clk_rate = 3686400, .max_clk_rate = 3686400,
}, },
[PORT_BYT] = { [PORT_BYT] = {
.type = LPSS_SSP, .type = LPSS_BYT_SSP,
.port_id = 0, .port_id = 0,
.num_chipselect = 1, .num_chipselect = 1,
.max_clk_rate = 50000000, .max_clk_rate = 50000000,
...@@ -70,7 +70,7 @@ static struct pxa_spi_info spi_info_configs[] = { ...@@ -70,7 +70,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.rx_param = &byt_rx_param, .rx_param = &byt_rx_param,
}, },
[PORT_BSW0] = { [PORT_BSW0] = {
.type = LPSS_SSP, .type = LPSS_BYT_SSP,
.port_id = 0, .port_id = 0,
.num_chipselect = 1, .num_chipselect = 1,
.max_clk_rate = 50000000, .max_clk_rate = 50000000,
...@@ -78,7 +78,7 @@ static struct pxa_spi_info spi_info_configs[] = { ...@@ -78,7 +78,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.rx_param = &bsw0_rx_param, .rx_param = &bsw0_rx_param,
}, },
[PORT_BSW1] = { [PORT_BSW1] = {
.type = LPSS_SSP, .type = LPSS_BYT_SSP,
.port_id = 1, .port_id = 1,
.num_chipselect = 1, .num_chipselect = 1,
.max_clk_rate = 50000000, .max_clk_rate = 50000000,
...@@ -86,7 +86,7 @@ static struct pxa_spi_info spi_info_configs[] = { ...@@ -86,7 +86,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.rx_param = &bsw1_rx_param, .rx_param = &bsw1_rx_param,
}, },
[PORT_BSW2] = { [PORT_BSW2] = {
.type = LPSS_SSP, .type = LPSS_BYT_SSP,
.port_id = 2, .port_id = 2,
.num_chipselect = 1, .num_chipselect = 1,
.max_clk_rate = 50000000, .max_clk_rate = 50000000,
......
This diff is collapsed.
...@@ -60,21 +60,60 @@ MODULE_ALIAS("platform:pxa2xx-spi"); ...@@ -60,21 +60,60 @@ MODULE_ALIAS("platform:pxa2xx-spi");
| QUARK_X1000_SSCR1_TFT \ | QUARK_X1000_SSCR1_TFT \
| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
#define LPSS_RX_THRESH_DFLT 64
#define LPSS_TX_LOTHRESH_DFLT 160
#define LPSS_TX_HITHRESH_DFLT 224
/* Offset from drv_data->lpss_base */
#define GENERAL_REG 0x08
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) #define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
#define SSP_REG 0x0c
#define SPI_CS_CONTROL 0x18
#define SPI_CS_CONTROL_SW_MODE BIT(0) #define SPI_CS_CONTROL_SW_MODE BIT(0)
#define SPI_CS_CONTROL_CS_HIGH BIT(1) #define SPI_CS_CONTROL_CS_HIGH BIT(1)
struct lpss_config {
/* LPSS offset from drv_data->ioaddr */
unsigned offset;
/* Register offsets from drv_data->lpss_base or -1 */
int reg_general;
int reg_ssp;
int reg_cs_ctrl;
/* FIFO thresholds */
u32 rx_threshold;
u32 tx_threshold_lo;
u32 tx_threshold_hi;
};
/* Keep these sorted with enum pxa_ssp_type */
static const struct lpss_config lpss_platforms[] = {
{ /* LPSS_LPT_SSP */
.offset = 0x800,
.reg_general = 0x08,
.reg_ssp = 0x0c,
.reg_cs_ctrl = 0x18,
.rx_threshold = 64,
.tx_threshold_lo = 160,
.tx_threshold_hi = 224,
},
{ /* LPSS_BYT_SSP */
.offset = 0x400,
.reg_general = 0x08,
.reg_ssp = 0x0c,
.reg_cs_ctrl = 0x18,
.rx_threshold = 64,
.tx_threshold_lo = 160,
.tx_threshold_hi = 224,
},
};
static inline const struct lpss_config
*lpss_get_config(const struct driver_data *drv_data)
{
return &lpss_platforms[drv_data->ssp_type - LPSS_LPT_SSP];
}
static bool is_lpss_ssp(const struct driver_data *drv_data) static bool is_lpss_ssp(const struct driver_data *drv_data)
{ {
return drv_data->ssp_type == LPSS_SSP; switch (drv_data->ssp_type) {
case LPSS_LPT_SSP:
case LPSS_BYT_SSP:
return true;
default:
return false;
}
} }
static bool is_quark_x1000_ssp(const struct driver_data *drv_data) static bool is_quark_x1000_ssp(const struct driver_data *drv_data)
...@@ -192,63 +231,43 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data, ...@@ -192,63 +231,43 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data,
*/ */
static void lpss_ssp_setup(struct driver_data *drv_data) static void lpss_ssp_setup(struct driver_data *drv_data)
{ {
unsigned offset = 0x400; const struct lpss_config *config;
u32 value, orig; u32 value;
/*
* Perform auto-detection of the LPSS SSP private registers. They
* can be either at 1k or 2k offset from the base address.
*/
orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
/* Test SPI_CS_CONTROL_SW_MODE bit enabling */
value = orig | SPI_CS_CONTROL_SW_MODE;
writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
if (value != (orig | SPI_CS_CONTROL_SW_MODE)) {
offset = 0x800;
goto detection_done;
}
orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
/* Test SPI_CS_CONTROL_SW_MODE bit disabling */
value = orig & ~SPI_CS_CONTROL_SW_MODE;
writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
if (value != (orig & ~SPI_CS_CONTROL_SW_MODE)) {
offset = 0x800;
goto detection_done;
}
detection_done: config = lpss_get_config(drv_data);
/* Now set the LPSS base */ drv_data->lpss_base = drv_data->ioaddr + config->offset;
drv_data->lpss_base = drv_data->ioaddr + offset;
/* Enable software chip select control */ /* Enable software chip select control */
value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH; value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value); __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
/* Enable multiblock DMA transfers */ /* Enable multiblock DMA transfers */
if (drv_data->master_info->enable_dma) { if (drv_data->master_info->enable_dma) {
__lpss_ssp_write_priv(drv_data, SSP_REG, 1); __lpss_ssp_write_priv(drv_data, config->reg_ssp, 1);
value = __lpss_ssp_read_priv(drv_data, GENERAL_REG); if (config->reg_general >= 0) {
value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE; value = __lpss_ssp_read_priv(drv_data,
__lpss_ssp_write_priv(drv_data, GENERAL_REG, value); config->reg_general);
value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
__lpss_ssp_write_priv(drv_data,
config->reg_general, value);
}
} }
} }
static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
{ {
const struct lpss_config *config;
u32 value; u32 value;
value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL); config = lpss_get_config(drv_data);
value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
if (enable) if (enable)
value &= ~SPI_CS_CONTROL_CS_HIGH; value &= ~SPI_CS_CONTROL_CS_HIGH;
else else
value |= SPI_CS_CONTROL_CS_HIGH; value |= SPI_CS_CONTROL_CS_HIGH;
__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value); __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
} }
static void cs_assert(struct driver_data *drv_data) static void cs_assert(struct driver_data *drv_data)
...@@ -1075,6 +1094,7 @@ static int setup(struct spi_device *spi) ...@@ -1075,6 +1094,7 @@ static int setup(struct spi_device *spi)
{ {
struct pxa2xx_spi_chip *chip_info = NULL; struct pxa2xx_spi_chip *chip_info = NULL;
struct chip_data *chip; struct chip_data *chip;
const struct lpss_config *config;
struct driver_data *drv_data = spi_master_get_devdata(spi->master); struct driver_data *drv_data = spi_master_get_devdata(spi->master);
unsigned int clk_div; unsigned int clk_div;
uint tx_thres, tx_hi_thres, rx_thres; uint tx_thres, tx_hi_thres, rx_thres;
...@@ -1085,10 +1105,12 @@ static int setup(struct spi_device *spi) ...@@ -1085,10 +1105,12 @@ static int setup(struct spi_device *spi)
tx_hi_thres = 0; tx_hi_thres = 0;
rx_thres = RX_THRESH_QUARK_X1000_DFLT; rx_thres = RX_THRESH_QUARK_X1000_DFLT;
break; break;
case LPSS_SSP: case LPSS_LPT_SSP:
tx_thres = LPSS_TX_LOTHRESH_DFLT; case LPSS_BYT_SSP:
tx_hi_thres = LPSS_TX_HITHRESH_DFLT; config = lpss_get_config(drv_data);
rx_thres = LPSS_RX_THRESH_DFLT; tx_thres = config->tx_threshold_lo;
tx_hi_thres = config->tx_threshold_hi;
rx_thres = config->rx_threshold;
break; break;
default: default:
tx_thres = TX_THRESH_DFLT; tx_thres = TX_THRESH_DFLT;
...@@ -1242,6 +1264,18 @@ static void cleanup(struct spi_device *spi) ...@@ -1242,6 +1264,18 @@ static void cleanup(struct spi_device *spi)
} }
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "INT33C0", LPSS_LPT_SSP },
{ "INT33C1", LPSS_LPT_SSP },
{ "INT3430", LPSS_LPT_SSP },
{ "INT3431", LPSS_LPT_SSP },
{ "80860F0E", LPSS_BYT_SSP },
{ "8086228E", LPSS_BYT_SSP },
{ },
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
static struct pxa2xx_spi_master * static struct pxa2xx_spi_master *
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
{ {
...@@ -1249,12 +1283,19 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) ...@@ -1249,12 +1283,19 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
struct acpi_device *adev; struct acpi_device *adev;
struct ssp_device *ssp; struct ssp_device *ssp;
struct resource *res; struct resource *res;
int devid; const struct acpi_device_id *id;
int devid, type;
if (!ACPI_HANDLE(&pdev->dev) || if (!ACPI_HANDLE(&pdev->dev) ||
acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev)) acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
return NULL; return NULL;
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id)
type = (int)id->driver_data;
else
return NULL;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
return NULL; return NULL;
...@@ -1272,7 +1313,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) ...@@ -1272,7 +1313,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
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);
ssp->type = LPSS_SSP; ssp->type = type;
ssp->pdev = pdev; ssp->pdev = pdev;
ssp->port_id = -1; ssp->port_id = -1;
...@@ -1285,16 +1326,6 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) ...@@ -1285,16 +1326,6 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
return pdata; return pdata;
} }
static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "INT33C0", 0 },
{ "INT33C1", 0 },
{ "INT3430", 0 },
{ "INT3431", 0 },
{ "80860F0E", 0 },
{ "8086228E", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
#else #else
static inline struct pxa2xx_spi_master * static inline struct pxa2xx_spi_master *
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
......
...@@ -162,11 +162,7 @@ extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data); ...@@ -162,11 +162,7 @@ extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data);
/* /*
* Select the right DMA implementation. * Select the right DMA implementation.
*/ */
#if defined(CONFIG_SPI_PXA2XX_PXADMA) #if defined(CONFIG_SPI_PXA2XX_DMA)
#define SPI_PXA2XX_USE_DMA 1
#define MAX_DMA_LEN 8191
#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE)
#elif defined(CONFIG_SPI_PXA2XX_DMA)
#define SPI_PXA2XX_USE_DMA 1 #define SPI_PXA2XX_USE_DMA 1
#define MAX_DMA_LEN SZ_64K #define MAX_DMA_LEN SZ_64K
#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL) #define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL)
......
/*
* SPI controller driver for the Mikrotik RB4xx boards
*
* Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
* Copyright (C) 2015 Bert Vermeulen <bert@biot.com>
*
* This file was based on the patches for Linux 2.6.27.39 published by
* MikroTik for their RouterBoard 4xx series devices.
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <asm/mach-ath79/ar71xx_regs.h>
struct rb4xx_spi {
void __iomem *base;
struct clk *clk;
};
static inline u32 rb4xx_read(struct rb4xx_spi *rbspi, u32 reg)
{
return __raw_readl(rbspi->base + reg);
}
static inline void rb4xx_write(struct rb4xx_spi *rbspi, u32 reg, u32 value)
{
__raw_writel(value, rbspi->base + reg);
}
static inline void do_spi_clk(struct rb4xx_spi *rbspi, u32 spi_ioc, int value)
{
u32 regval;
regval = spi_ioc;
if (value & BIT(0))
regval |= AR71XX_SPI_IOC_DO;
rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
}
static void do_spi_byte(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
{
int i;
for (i = 7; i >= 0; i--)
do_spi_clk(rbspi, spi_ioc, byte >> i);
}
/* The CS2 pin is used to clock in a second bit per clock cycle. */
static inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc,
u8 value)
{
u32 regval;
regval = spi_ioc;
if (value & BIT(1))
regval |= AR71XX_SPI_IOC_DO;
if (value & BIT(0))
regval |= AR71XX_SPI_IOC_CS2;
rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
}
/* Two bits at a time, msb first */
static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
{
do_spi_clk_two(rbspi, spi_ioc, byte >> 6);
do_spi_clk_two(rbspi, spi_ioc, byte >> 4);
do_spi_clk_two(rbspi, spi_ioc, byte >> 2);
do_spi_clk_two(rbspi, spi_ioc, byte >> 0);
}
static void rb4xx_set_cs(struct spi_device *spi, bool enable)
{
struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
/*
* Setting CS is done along with bitbanging the actual values,
* since it's all on the same hardware register. However the
* CPLD needs CS deselected after every command.
*/
if (enable)
rb4xx_write(rbspi, AR71XX_SPI_REG_IOC,
AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1);
}
static int rb4xx_transfer_one(struct spi_master *master,
struct spi_device *spi, struct spi_transfer *t)
{
struct rb4xx_spi *rbspi = spi_master_get_devdata(master);
int i;
u32 spi_ioc;
u8 *rx_buf;
const u8 *tx_buf;
/*
* Prime the SPI register with the SPI device selected. The m25p80 boot
* flash and CPLD share the CS0 pin. This works because the CPLD's
* command set was designed to almost not clash with that of the
* boot flash.
*/
if (spi->chip_select == 2)
/* MMC */
spi_ioc = AR71XX_SPI_IOC_CS0;
else
/* Boot flash and CPLD */
spi_ioc = AR71XX_SPI_IOC_CS1;
tx_buf = t->tx_buf;
rx_buf = t->rx_buf;
for (i = 0; i < t->len; ++i) {
if (t->tx_nbits == SPI_NBITS_DUAL)
/* CPLD can use two-wire transfers */
do_spi_byte_two(rbspi, spi_ioc, tx_buf[i]);
else
do_spi_byte(rbspi, spi_ioc, tx_buf[i]);
if (!rx_buf)
continue;
rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS);
}
spi_finalize_current_transfer(master);
return 0;
}
static int rb4xx_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct clk *ahb_clk;
struct rb4xx_spi *rbspi;
struct resource *r;
int err;
void __iomem *spi_base;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(spi_base))
return PTR_ERR(spi_base);
master = spi_alloc_master(&pdev->dev, sizeof(*rbspi));
if (!master)
return -ENOMEM;
ahb_clk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(ahb_clk))
return PTR_ERR(ahb_clk);
master->bus_num = 0;
master->num_chipselect = 3;
master->mode_bits = SPI_TX_DUAL;
master->bits_per_word_mask = BIT(7);
master->flags = SPI_MASTER_MUST_TX;
master->transfer_one = rb4xx_transfer_one;
master->set_cs = rb4xx_set_cs;
err = devm_spi_register_master(&pdev->dev, master);
if (err) {
dev_err(&pdev->dev, "failed to register SPI master\n");
return err;
}
err = clk_prepare_enable(ahb_clk);
if (err)
return err;
rbspi = spi_master_get_devdata(master);
rbspi->base = spi_base;
rbspi->clk = ahb_clk;
platform_set_drvdata(pdev, rbspi);
/* Enable SPI */
rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
return 0;
}
static int rb4xx_spi_remove(struct platform_device *pdev)
{
struct rb4xx_spi *rbspi = platform_get_drvdata(pdev);
clk_disable_unprepare(rbspi->clk);
return 0;
}
static struct platform_driver rb4xx_spi_drv = {
.probe = rb4xx_spi_probe,
.remove = rb4xx_spi_remove,
.driver = {
.name = "rb4xx-spi",
},
};
module_platform_driver(rb4xx_spi_drv);
MODULE_DESCRIPTION("Mikrotik RB4xx SPI controller driver");
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>");
MODULE_LICENSE("GPL v2");
...@@ -665,15 +665,12 @@ static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi, ...@@ -665,15 +665,12 @@ static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi,
static int rspi_dma_check_then_transfer(struct rspi_data *rspi, static int rspi_dma_check_then_transfer(struct rspi_data *rspi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) { if (!rspi->master->can_dma || !__rspi_can_dma(rspi, xfer))
/* rx_buf can be NULL on RSPI on SH in TX-only Mode */ return -EAGAIN;
int ret = rspi_dma_transfer(rspi, &xfer->tx_sg,
xfer->rx_buf ? &xfer->rx_sg : NULL);
if (ret != -EAGAIN)
return 0;
}
return -EAGAIN; /* rx_buf can be NULL on RSPI on SH in TX-only Mode */
return rspi_dma_transfer(rspi, &xfer->tx_sg,
xfer->rx_buf ? &xfer->rx_sg : NULL);
} }
static int rspi_common_transfer(struct rspi_data *rspi, static int rspi_common_transfer(struct rspi_data *rspi,
...@@ -724,7 +721,7 @@ static int rspi_rz_transfer_one(struct spi_master *master, ...@@ -724,7 +721,7 @@ static int rspi_rz_transfer_one(struct spi_master *master,
return rspi_common_transfer(rspi, xfer); return rspi_common_transfer(rspi, xfer);
} }
static int qspi_trigger_transfer_out_int(struct rspi_data *rspi, const u8 *tx, static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx,
u8 *rx, unsigned int len) u8 *rx, unsigned int len)
{ {
int i, n, ret; int i, n, ret;
...@@ -771,12 +768,8 @@ static int qspi_transfer_out_in(struct rspi_data *rspi, ...@@ -771,12 +768,8 @@ static int qspi_transfer_out_in(struct rspi_data *rspi,
if (ret != -EAGAIN) if (ret != -EAGAIN)
return ret; return ret;
ret = qspi_trigger_transfer_out_int(rspi, xfer->tx_buf, return qspi_trigger_transfer_out_in(rspi, xfer->tx_buf,
xfer->rx_buf, xfer->len); xfer->rx_buf, xfer->len);
if (ret < 0)
return ret;
return 0;
} }
static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
...@@ -1300,7 +1293,7 @@ static int rspi_probe(struct platform_device *pdev) ...@@ -1300,7 +1293,7 @@ static int rspi_probe(struct platform_device *pdev)
return ret; return ret;
} }
static struct platform_device_id spi_driver_ids[] = { static const struct platform_device_id spi_driver_ids[] = {
{ "rspi", (kernel_ulong_t)&rspi_ops }, { "rspi", (kernel_ulong_t)&rspi_ops },
{ "rspi-rz", (kernel_ulong_t)&rspi_rz_ops }, { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops },
{ "qspi", (kernel_ulong_t)&qspi_ops }, { "qspi", (kernel_ulong_t)&qspi_ops },
......
...@@ -1347,7 +1347,7 @@ static struct s3c64xx_spi_port_config exynos7_spi_port_config = { ...@@ -1347,7 +1347,7 @@ static struct s3c64xx_spi_port_config exynos7_spi_port_config = {
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO, .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
}; };
static struct platform_device_id s3c64xx_spi_driver_ids[] = { static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
{ {
.name = "s3c2443-spi", .name = "s3c2443-spi",
.driver_data = (kernel_ulong_t)&s3c2443_spi_port_config, .driver_data = (kernel_ulong_t)&s3c2443_spi_port_config,
......
...@@ -1263,7 +1263,7 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) ...@@ -1263,7 +1263,7 @@ static int sh_msiof_spi_remove(struct platform_device *pdev)
return 0; return 0;
} }
static struct platform_device_id spi_driver_ids[] = { static const struct platform_device_id spi_driver_ids[] = {
{ "spi_sh_msiof", (kernel_ulong_t)&sh_data }, { "spi_sh_msiof", (kernel_ulong_t)&sh_data },
{ "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data }, { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data }, { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
......
This diff is collapsed.
This diff is collapsed.
...@@ -571,7 +571,7 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) ...@@ -571,7 +571,7 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg)
return 0; return 0;
} }
static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
{ {
struct spi_transfer *xfer; struct spi_transfer *xfer;
struct device *tx_dev, *rx_dev; struct device *tx_dev, *rx_dev;
...@@ -583,15 +583,6 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) ...@@ -583,15 +583,6 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
rx_dev = master->dma_rx->device->dev; rx_dev = master->dma_rx->device->dev;
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
/*
* Restore the original value of tx_buf or rx_buf if they are
* NULL.
*/
if (xfer->tx_buf == master->dummy_tx)
xfer->tx_buf = NULL;
if (xfer->rx_buf == master->dummy_rx)
xfer->rx_buf = NULL;
if (!master->can_dma(master, msg->spi, xfer)) if (!master->can_dma(master, msg->spi, xfer))
continue; continue;
...@@ -608,13 +599,32 @@ static inline int __spi_map_msg(struct spi_master *master, ...@@ -608,13 +599,32 @@ static inline int __spi_map_msg(struct spi_master *master,
return 0; return 0;
} }
static inline int spi_unmap_msg(struct spi_master *master, static inline int __spi_unmap_msg(struct spi_master *master,
struct spi_message *msg) struct spi_message *msg)
{ {
return 0; return 0;
} }
#endif /* !CONFIG_HAS_DMA */ #endif /* !CONFIG_HAS_DMA */
static inline int spi_unmap_msg(struct spi_master *master,
struct spi_message *msg)
{
struct spi_transfer *xfer;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
/*
* Restore the original value of tx_buf or rx_buf if they are
* NULL.
*/
if (xfer->tx_buf == master->dummy_tx)
xfer->tx_buf = NULL;
if (xfer->rx_buf == master->dummy_rx)
xfer->rx_buf = NULL;
}
return __spi_unmap_msg(master, msg);
}
static int spi_map_msg(struct spi_master *master, struct spi_message *msg) static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
{ {
struct spi_transfer *xfer; struct spi_transfer *xfer;
...@@ -988,9 +998,6 @@ void spi_finalize_current_message(struct spi_master *master) ...@@ -988,9 +998,6 @@ void spi_finalize_current_message(struct spi_master *master)
spin_lock_irqsave(&master->queue_lock, flags); spin_lock_irqsave(&master->queue_lock, flags);
mesg = master->cur_msg; mesg = master->cur_msg;
master->cur_msg = NULL;
queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags); spin_unlock_irqrestore(&master->queue_lock, flags);
spi_unmap_msg(master, mesg); spi_unmap_msg(master, mesg);
...@@ -1003,9 +1010,13 @@ void spi_finalize_current_message(struct spi_master *master) ...@@ -1003,9 +1010,13 @@ void spi_finalize_current_message(struct spi_master *master)
} }
} }
trace_spi_message_done(mesg); spin_lock_irqsave(&master->queue_lock, flags);
master->cur_msg = NULL;
master->cur_msg_prepared = false; master->cur_msg_prepared = false;
queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
trace_spi_message_done(mesg);
mesg->state = NULL; mesg->state = NULL;
if (mesg->complete) if (mesg->complete)
......
...@@ -95,37 +95,25 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); ...@@ -95,37 +95,25 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/*
* We can't use the standard synchronous wrappers for file I/O; we
* need to protect against async removal of the underlying spi_device.
*/
static void spidev_complete(void *arg)
{
complete(arg);
}
static ssize_t static ssize_t
spidev_sync(struct spidev_data *spidev, struct spi_message *message) spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{ {
DECLARE_COMPLETION_ONSTACK(done); DECLARE_COMPLETION_ONSTACK(done);
int status; int status;
struct spi_device *spi;
message->complete = spidev_complete;
message->context = &done;
spin_lock_irq(&spidev->spi_lock); spin_lock_irq(&spidev->spi_lock);
if (spidev->spi == NULL) spi = spidev->spi;
spin_unlock_irq(&spidev->spi_lock);
if (spi == NULL)
status = -ESHUTDOWN; status = -ESHUTDOWN;
else else
status = spi_async(spidev->spi, message); status = spi_sync(spi, message);
spin_unlock_irq(&spidev->spi_lock);
if (status == 0)
status = message->actual_length;
if (status == 0) {
wait_for_completion(&done);
status = message->status;
if (status == 0)
status = message->actual_length;
}
return status; return status;
} }
...@@ -647,7 +635,6 @@ static int spidev_open(struct inode *inode, struct file *filp) ...@@ -647,7 +635,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
static int spidev_release(struct inode *inode, struct file *filp) static int spidev_release(struct inode *inode, struct file *filp)
{ {
struct spidev_data *spidev; struct spidev_data *spidev;
int status = 0;
mutex_lock(&device_list_lock); mutex_lock(&device_list_lock);
spidev = filp->private_data; spidev = filp->private_data;
...@@ -676,7 +663,7 @@ static int spidev_release(struct inode *inode, struct file *filp) ...@@ -676,7 +663,7 @@ static int spidev_release(struct inode *inode, struct file *filp)
} }
mutex_unlock(&device_list_lock); mutex_unlock(&device_list_lock);
return status; return 0;
} }
static const struct file_operations spidev_fops = { static const struct file_operations spidev_fops = {
......
...@@ -194,8 +194,9 @@ enum pxa_ssp_type { ...@@ -194,8 +194,9 @@ enum pxa_ssp_type {
PXA168_SSP, PXA168_SSP,
PXA910_SSP, PXA910_SSP,
CE4100_SSP, CE4100_SSP,
LPSS_SSP,
QUARK_X1000_SSP, QUARK_X1000_SSP,
LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */
LPSS_BYT_SSP,
}; };
struct ssp_device { struct ssp_device {
......
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