Commit 58e4411b authored by Linus Torvalds's avatar Linus Torvalds

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

Pull spi updates from Mark Brown:
 "The SPI subsystem has also had quite a quiet release, though with a
  fairly large set of per-driver changes and several new drivers. The
  bulk of the changes are:

   - lots and lots of cleanups and improvements for the fsl-espi driver

   - new drivers for Broadcom MSPI/iProc/STB, Cavium ThunderX and
     J-Core"

* tag 'spi-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (80 commits)
  spi: sc18is602: Change gpiod_set_value to gpiod_set_value_cansleep
  spi: pxa2xx: Fix build error because of missing header
  spi: imx: fix error return code in spi_imx_probe()
  spi: pxa2xx: Add support for GPIO descriptor chip selects
  spi: imx: Gracefully handle NULL master->cs_gpios
  spi: iproc-qspi: Add Broadcom iProc SoCs support
  spi: fsl-espi: improve return value handling in fsl_espi_probe
  spi: fsl-espi: simplify of_fsl_espi_probe
  spi: fsl-espi: remove unused variable in fsl_espi_setup
  spi: bcm-qspi: Fix error return code in bcm_qspi_probe()
  spi: bcm-qspi: Fix return value check in bcm_qspi_probe()
  spi: bcm-qspi: fix suspend/resume #ifdef
  spi: bcm-qspi: don't include linux/mtd/cfi.h
  spi: core: Use spi_sync_transfer() in spi_write()/spi_read()
  spi: fsl-espi: improve and extend register bit definitions
  spi: fsl-espi: align register access with other drivers
  spi: fsl-espi: improve and simplify interrupt handler
  spi: fsl-espi: simplify fsl_espi_setup_transfer
  spi: imx: support loopback mode on imx35
  spi: imx: set spi_bus_clk for mx1, mx31 and mx35
  ...
parents 5a9f228a 2ce04684
Broadcom SPI controller
The Broadcom SPI controller is a SPI master found on various SOCs, including
BRCMSTB (BCM7XXX), Cygnus, NSP and NS2. The Broadcom Master SPI hw IP consits
of :
MSPI : SPI master controller can read and write to a SPI slave device
BSPI : Broadcom SPI in combination with the MSPI hw IP provides acceleration
for flash reads and be configured to do single, double, quad lane
io with 3-byte and 4-byte addressing support.
Supported Broadcom SoCs have one instance of MSPI+BSPI controller IP.
MSPI master can be used wihout BSPI. BRCMSTB SoCs have an additional instance
of a MSPI master without the BSPI to use with non flash slave devices that
use SPI protocol.
Required properties:
- #address-cells:
Must be <1>, as required by generic SPI binding.
- #size-cells:
Must be <0>, also as required by generic SPI binding.
- compatible:
Must be one of :
"brcm,spi-bcm-qspi", "brcm,spi-brcmstb-qspi" : MSPI+BSPI on BRCMSTB SoCs
"brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi" : MSPI+BSPI on Cygnus, NSP
"brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi" : NS2 SoCs
- reg:
Define the bases and ranges of the associated I/O address spaces.
The required range is MSPI controller registers.
- reg-names:
First name does not matter, but must be reserved for the MSPI controller
register range as mentioned in 'reg' above, and will typically contain
- "bspi_regs": BSPI register range, not required with compatible
"spi-brcmstb-mspi"
- "mspi_regs": MSPI register range is required for compatible strings
- "intr_regs", "intr_status_reg" : Interrupt and status register for
NSP, NS2, Cygnus SoC
- interrupts
The interrupts used by the MSPI and/or BSPI controller.
- interrupt-names:
Names of interrupts associated with MSPI
- "mspi_halted" :
- "mspi_done": Indicates that the requested SPI operation is complete.
- "spi_lr_fullness_reached" : Linear read BSPI pipe full
- "spi_lr_session_aborted" : Linear read BSPI pipe aborted
- "spi_lr_impatient" : Linear read BSPI requested when pipe empty
- "spi_lr_session_done" : Linear read BSPI session done
- clocks:
A phandle to the reference clock for this block.
Optional properties:
- native-endian
Defined when using BE SoC and device uses BE register read/write
Recommended optional m25p80 properties:
- spi-rx-bus-width: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Examples:
BRCMSTB SoC Example:
SPI Master (MSPI+BSPI) for SPI-NOR access:
spi@f03e3400 {
#address-cells = <0x1>;
#size-cells = <0x0>;
compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-brcmstb-qspi";
reg = <0xf03e0920 0x4 0xf03e3400 0x188 0xf03e3200 0x50>;
reg-names = "cs_reg", "mspi", "bspi";
interrupts = <0x6 0x5 0x4 0x3 0x2 0x1 0x0>;
interrupt-parent = <0x1c>;
interrupt-names = "mspi_halted",
"mspi_done",
"spi_lr_overread",
"spi_lr_session_done",
"spi_lr_impatient",
"spi_lr_session_aborted",
"spi_lr_fullness_reached";
clocks = <&hif_spi>;
clock-names = "sw_spi";
m25p80@0 {
#size-cells = <0x2>;
#address-cells = <0x2>;
compatible = "m25p80";
reg = <0x0>;
spi-max-frequency = <0x2625a00>;
spi-cpol;
spi-cpha;
m25p,fast-read;
flash0.bolt@0 {
reg = <0x0 0x0 0x0 0x100000>;
};
flash0.macadr@100000 {
reg = <0x0 0x100000 0x0 0x10000>;
};
flash0.nvram@110000 {
reg = <0x0 0x110000 0x0 0x10000>;
};
flash0.kernel@120000 {
reg = <0x0 0x120000 0x0 0x400000>;
};
flash0.devtree@520000 {
reg = <0x0 0x520000 0x0 0x10000>;
};
flash0.splash@530000 {
reg = <0x0 0x530000 0x0 0x80000>;
};
flash0@0 {
reg = <0x0 0x0 0x0 0x4000000>;
};
};
};
MSPI master for any SPI device :
spi@f0416000 {
#address-cells = <1>;
#size-cells = <0>;
clocks = <&upg_fixed>;
compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-brcmstb-mspi";
reg = <0xf0416000 0x180>;
reg-names = "mspi";
interrupts = <0x14>;
interrupt-parent = <&irq0_aon_intc>;
interrupt-names = "mspi_done";
};
iProc SoC Example:
qspi: spi@18027200 {
compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
reg = <0x18027200 0x184>,
<0x18027000 0x124>,
<0x1811c408 0x004>,
<0x180273a0 0x01c>;
reg-names = "mspi_regs", "bspi_regs", "intr_regs", "intr_status_reg";
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names =
"spi_lr_fullness_reached",
"spi_lr_session_aborted",
"spi_lr_impatient",
"spi_lr_session_done",
"mspi_done",
"mspi_halted";
clocks = <&iprocmed>;
clock-names = "iprocmed";
num-cs = <2>;
#address-cells = <1>;
#size-cells = <0>;
};
NS2 SoC Example:
qspi: spi@66470200 {
compatible = "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi";
reg = <0x66470200 0x184>,
<0x66470000 0x124>,
<0x67017408 0x004>,
<0x664703a0 0x01c>;
reg-names = "mspi", "bspi", "intr_regs",
"intr_status_reg";
interrupts = <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "spi_l1_intr";
clocks = <&iprocmed>;
clock-names = "iprocmed";
num-cs = <2>;
#address-cells = <1>;
#size-cells = <0>;
};
m25p80 node for NSP, NS2
&qspi {
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "m25p80";
reg = <0x0>;
spi-max-frequency = <12500000>;
m25p,fast-read;
spi-cpol;
spi-cpha;
partition@0 {
label = "boot";
reg = <0x00000000 0x000a0000>;
};
partition@a0000 {
label = "env";
reg = <0x000a0000 0x00060000>;
};
partition@100000 {
label = "system";
reg = <0x00100000 0x00600000>;
};
partition@700000 {
label = "rootfs";
reg = <0x00700000 0x01900000>;
};
};
J-Core SPI master
Required properties:
- compatible: Must be "jcore,spi2".
- reg: Memory region for registers.
- #address-cells: Must be 1.
- #size-cells: Must be 0.
Optional properties:
- clocks: If a phandle named "ref_clk" is present, SPI clock speed
programming is relative to the frequency of the indicated clock.
Necessary only if the input clock rate is something other than a
fixed 50 MHz.
- clock-names: Clock names, one for each phandle in clocks.
See spi-bus.txt for additional properties not specific to this device.
Example:
spi@40 {
compatible = "jcore,spi2";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x40 0x8>;
spi-max-frequency = <25000000>;
clocks = <&bus_clk>;
clock-names = "ref_clk";
}
......@@ -7,7 +7,7 @@ NOR memories, without DMA support and a 64-byte unified transmit /
receive buffer.
Required properties:
- compatible: should be "amlogic,meson6-spifc"
- compatible: should be "amlogic,meson6-spifc" or "amlogic,meson-gxbb-spifc"
- reg: physical base address and length of the controller registers
- clocks: phandle of the input clock for the baud rate generator
- #address-cells: should be 1
......
......@@ -11165,6 +11165,7 @@ F: Documentation/spi/
F: drivers/spi/
F: include/linux/spi/
F: include/uapi/linux/spi/
F: tools/spi/
SPIDERNET NETWORK DRIVER for CELL
M: Ishizaki Kou <kou.ishizaki@toshiba.co.jp>
......
......@@ -153,6 +153,16 @@ config SPI_BCM63XX_HSSPI
This enables support for the High Speed SPI controller present on
newer Broadcom BCM63XX SoCs.
config SPI_BCM_QSPI
tristate "Broadcom BSPI and MSPI controller support"
depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST
default ARCH_BCM_IPROC
help
Enables support for the Broadcom SPI flash and MSPI controller.
Select this option for any one of BRCMSTB, iProc NSP and NS2 SoCs
based platforms. This driver works for both SPI master for spi-nor
flash device as well as MSPI device.
config SPI_BITBANG
tristate "Utilities for Bitbanging SPI masters"
help
......@@ -285,6 +295,13 @@ config SPI_IMX
This enables using the Freescale i.MX SPI controllers in master
mode.
config SPI_JCORE
tristate "J-Core SPI Master"
depends on OF && (SUPERH || COMPILE_TEST)
help
This enables support for the SPI master controller in the J-Core
synthesizable, open source SoC.
config SPI_LM70_LLP
tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
depends on PARPORT
......@@ -549,7 +566,7 @@ config SPI_SC18IS602
config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK && HAS_DMA
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST
help
SPI driver for SuperH and SH Mobile MSIOF blocks.
......@@ -631,6 +648,13 @@ config SPI_TEGRA20_SLINK
help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
config SPI_THUNDERX
tristate "Cavium ThunderX SPI controller"
depends on PCI && 64BIT && (ARM64 || COMPILE_TEST)
help
SPI host driver for the hardware found on Cavium ThunderX
SOCs.
config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o
obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
......@@ -46,6 +47,7 @@ obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
obj-$(CONFIG_SPI_GPIO) += spi-gpio.o
obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o
obj-$(CONFIG_SPI_IMX) += spi-imx.o
obj-$(CONFIG_SPI_JCORE) += spi-jcore.o
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
......@@ -91,6 +93,8 @@ obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o
obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
......
This diff is collapsed.
/*
* Copyright 2016 Broadcom
*
* 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 (the "GPL").
*
* 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 version 2 (GPLv2) for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*/
#ifndef __SPI_BCM_QSPI_H__
#define __SPI_BCM_QSPI_H__
#include <linux/types.h>
#include <linux/io.h>
/* BSPI interrupt masks */
#define INTR_BSPI_LR_OVERREAD_MASK BIT(4)
#define INTR_BSPI_LR_SESSION_DONE_MASK BIT(3)
#define INTR_BSPI_LR_IMPATIENT_MASK BIT(2)
#define INTR_BSPI_LR_SESSION_ABORTED_MASK BIT(1)
#define INTR_BSPI_LR_FULLNESS_REACHED_MASK BIT(0)
#define BSPI_LR_INTERRUPTS_DATA \
(INTR_BSPI_LR_SESSION_DONE_MASK | \
INTR_BSPI_LR_FULLNESS_REACHED_MASK)
#define BSPI_LR_INTERRUPTS_ERROR \
(INTR_BSPI_LR_OVERREAD_MASK | \
INTR_BSPI_LR_IMPATIENT_MASK | \
INTR_BSPI_LR_SESSION_ABORTED_MASK)
#define BSPI_LR_INTERRUPTS_ALL \
(BSPI_LR_INTERRUPTS_ERROR | \
BSPI_LR_INTERRUPTS_DATA)
/* MSPI Interrupt masks */
#define INTR_MSPI_HALTED_MASK BIT(6)
#define INTR_MSPI_DONE_MASK BIT(5)
#define MSPI_INTERRUPTS_ALL \
(INTR_MSPI_DONE_MASK | \
INTR_MSPI_HALTED_MASK)
#define QSPI_INTERRUPTS_ALL \
(MSPI_INTERRUPTS_ALL | \
BSPI_LR_INTERRUPTS_ALL)
struct platform_device;
struct dev_pm_ops;
enum {
MSPI_DONE = 0x1,
BSPI_DONE = 0x2,
BSPI_ERR = 0x4,
MSPI_BSPI_DONE = 0x7
};
struct bcm_qspi_soc_intc {
void (*bcm_qspi_int_ack)(struct bcm_qspi_soc_intc *soc_intc, int type);
void (*bcm_qspi_int_set)(struct bcm_qspi_soc_intc *soc_intc, int type,
bool en);
u32 (*bcm_qspi_get_int_status)(struct bcm_qspi_soc_intc *soc_intc);
};
/* Read controller register*/
static inline u32 bcm_qspi_readl(bool be, void __iomem *addr)
{
if (be)
return ioread32be(addr);
else
return readl_relaxed(addr);
}
/* Write controller register*/
static inline void bcm_qspi_writel(bool be,
unsigned int data, void __iomem *addr)
{
if (be)
iowrite32be(data, addr);
else
writel_relaxed(data, addr);
}
static inline u32 get_qspi_mask(int type)
{
switch (type) {
case MSPI_DONE:
return INTR_MSPI_DONE_MASK;
case BSPI_DONE:
return BSPI_LR_INTERRUPTS_ALL;
case MSPI_BSPI_DONE:
return QSPI_INTERRUPTS_ALL;
case BSPI_ERR:
return BSPI_LR_INTERRUPTS_ERROR;
}
return 0;
}
/* The common driver functions to be called by the SoC platform driver */
int bcm_qspi_probe(struct platform_device *pdev,
struct bcm_qspi_soc_intc *soc_intc);
int bcm_qspi_remove(struct platform_device *pdev);
/* pm_ops used by the SoC platform driver called on PM suspend/resume */
extern const struct dev_pm_ops bcm_qspi_pm_ops;
#endif /* __SPI_BCM_QSPI_H__ */
/*
* Copyright 2016 Broadcom
*
* 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 (the "GPL").
*
* 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 version 2 (GPLv2) for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include "spi-bcm-qspi.h"
static const struct of_device_id brcmstb_qspi_of_match[] = {
{ .compatible = "brcm,spi-brcmstb-qspi" },
{ .compatible = "brcm,spi-brcmstb-mspi" },
{},
};
MODULE_DEVICE_TABLE(of, brcmstb_qspi_of_match);
static int brcmstb_qspi_probe(struct platform_device *pdev)
{
return bcm_qspi_probe(pdev, NULL);
}
static int brcmstb_qspi_remove(struct platform_device *pdev)
{
return bcm_qspi_remove(pdev);
}
static struct platform_driver brcmstb_qspi_driver = {
.probe = brcmstb_qspi_probe,
.remove = brcmstb_qspi_remove,
.driver = {
.name = "brcmstb_qspi",
.pm = &bcm_qspi_pm_ops,
.of_match_table = brcmstb_qspi_of_match,
}
};
module_platform_driver(brcmstb_qspi_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Kamal Dasu");
MODULE_DESCRIPTION("Broadcom SPI driver for settop SoC");
/*
* Cavium ThunderX SPI driver.
*
* Copyright (C) 2016 Cavium Inc.
* Authors: Jan Glauber <jglauber@cavium.com>
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/spi/spi.h>
#include "spi-cavium.h"
#define DRV_NAME "spi-thunderx"
#define SYS_FREQ_DEFAULT 700000000 /* 700 Mhz */
static int thunderx_spi_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
struct spi_master *master;
struct octeon_spi *p;
int ret;
master = spi_alloc_master(dev, sizeof(struct octeon_spi));
if (!master)
return -ENOMEM;
p = spi_master_get_devdata(master);
ret = pcim_enable_device(pdev);
if (ret)
goto error;
ret = pci_request_regions(pdev, DRV_NAME);
if (ret)
goto error;
p->register_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
if (!p->register_base) {
ret = -EINVAL;
goto error;
}
p->regs.config = 0x1000;
p->regs.status = 0x1008;
p->regs.tx = 0x1010;
p->regs.data = 0x1080;
p->clk = devm_clk_get(dev, NULL);
if (IS_ERR(p->clk)) {
ret = PTR_ERR(p->clk);
goto error;
}
ret = clk_prepare_enable(p->clk);
if (ret)
goto error;
p->sys_freq = clk_get_rate(p->clk);
if (!p->sys_freq)
p->sys_freq = SYS_FREQ_DEFAULT;
dev_info(dev, "Set system clock to %u\n", p->sys_freq);
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
SPI_LSB_FIRST | SPI_3WIRE;
master->transfer_one_message = octeon_spi_transfer_one_message;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
master->dev.of_node = pdev->dev.of_node;
pci_set_drvdata(pdev, master);
ret = devm_spi_register_master(dev, master);
if (ret)
goto error;
return 0;
error:
clk_disable_unprepare(p->clk);
spi_master_put(master);
return ret;
}
static void thunderx_spi_remove(struct pci_dev *pdev)
{
struct spi_master *master = pci_get_drvdata(pdev);
struct octeon_spi *p;
p = spi_master_get_devdata(master);
if (!p)
return;
clk_disable_unprepare(p->clk);
/* Put everything in a known state. */
writeq(0, p->register_base + OCTEON_SPI_CFG(p));
}
static const struct pci_device_id thunderx_spi_pci_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa00b) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, thunderx_spi_pci_id_table);
static struct pci_driver thunderx_spi_driver = {
.name = DRV_NAME,
.id_table = thunderx_spi_pci_id_table,
.probe = thunderx_spi_probe,
.remove = thunderx_spi_remove,
};
module_pci_driver(thunderx_spi_driver);
MODULE_DESCRIPTION("Cavium, Inc. ThunderX SPI bus driver");
MODULE_AUTHOR("Jan Glauber");
MODULE_LICENSE("GPL");
#ifndef __SPI_CAVIUM_H
#define __SPI_CAVIUM_H
#include <linux/clk.h>
#define OCTEON_SPI_MAX_BYTES 9
#define OCTEON_SPI_MAX_CLOCK_HZ 16000000
......@@ -17,6 +19,7 @@ struct octeon_spi {
u64 cs_enax;
int sys_freq;
struct octeon_spi_regs regs;
struct clk *clk;
};
#define OCTEON_SPI_CFG(x) (x->regs.config)
......
......@@ -283,7 +283,6 @@ static int dw_spi_transfer_one(struct spi_master *master,
struct chip_data *chip = spi_get_ctldata(spi);
u8 imask = 0;
u16 txlevel = 0;
u16 clk_div;
u32 cr0;
int ret;
......@@ -298,13 +297,13 @@ static int dw_spi_transfer_one(struct spi_master *master,
spi_enable_chip(dws, 0);
/* Handle per transfer options for bpw and speed */
if (transfer->speed_hz != chip->speed_hz) {
/* clk_div doesn't support odd number */
clk_div = (dws->max_freq / transfer->speed_hz + 1) & 0xfffe;
chip->speed_hz = transfer->speed_hz;
chip->clk_div = clk_div;
if (transfer->speed_hz != dws->current_freq) {
if (transfer->speed_hz != chip->speed_hz) {
/* clk_div doesn't support odd number */
chip->clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
chip->speed_hz = transfer->speed_hz;
}
dws->current_freq = transfer->speed_hz;
spi_set_clk(dws, chip->clk_div);
}
if (transfer->bits_per_word == 8) {
......
......@@ -123,6 +123,7 @@ struct dw_spi {
u8 n_bytes; /* current is a 1/2 bytes op */
u32 dma_width;
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
u32 current_freq; /* frequency in hz */
/* DMA info */
int dma_inited;
......
......@@ -159,7 +159,7 @@ struct fsl_dspi {
u8 cs;
u16 void_write_data;
u32 cs_change;
struct fsl_dspi_devtype_data *devtype_data;
const struct fsl_dspi_devtype_data *devtype_data;
wait_queue_head_t waitq;
u32 waitflags;
......@@ -624,10 +624,13 @@ static int dspi_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct fsl_dspi *dspi = spi_master_get_devdata(master);
int ret;
pinctrl_pm_select_default_state(dev);
clk_prepare_enable(dspi->clk);
ret = clk_prepare_enable(dspi->clk);
if (ret)
return ret;
spi_master_resume(master);
return 0;
......@@ -651,8 +654,6 @@ static int dspi_probe(struct platform_device *pdev)
struct resource *res;
void __iomem *base;
int ret = 0, cs_num, bus_num;
const struct of_device_id *of_id =
of_match_device(fsl_dspi_dt_ids, &pdev->dev);
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
if (!master)
......@@ -686,7 +687,7 @@ static int dspi_probe(struct platform_device *pdev)
}
master->bus_num = bus_num;
dspi->devtype_data = (struct fsl_dspi_devtype_data *)of_id->data;
dspi->devtype_data = of_device_get_match_data(&pdev->dev);
if (!dspi->devtype_data) {
dev_err(&pdev->dev, "can't get devtype_data\n");
ret = -EFAULT;
......@@ -728,7 +729,9 @@ static int dspi_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "unable to get clock\n");
goto out_master_put;
}
clk_prepare_enable(dspi->clk);
ret = clk_prepare_enable(dspi->clk);
if (ret)
goto out_master_put;
master->max_speed_hz =
clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
......@@ -760,7 +763,6 @@ static int dspi_remove(struct platform_device *pdev)
/* Disconnect from the SPI framework */
clk_disable_unprepare(dspi->clk);
spi_unregister_master(dspi->master);
spi_master_put(dspi->master);
return 0;
}
......
This diff is collapsed.
......@@ -23,13 +23,14 @@
/* SPI/eSPI Controller driver's private data. */
struct mpc8xxx_spi {
struct device *dev;
void *reg_base;
void __iomem *reg_base;
/* rx & tx bufs from the spi_transfer */
const void *tx;
void *rx;
#if IS_ENABLED(CONFIG_SPI_FSL_ESPI)
int len;
u8 *local_buf;
#endif
int subblock;
......
......@@ -186,17 +186,19 @@ static unsigned int spi_imx_clkdiv_1(unsigned int fin,
/* MX1, MX31, MX35, MX51 CSPI */
static unsigned int spi_imx_clkdiv_2(unsigned int fin,
unsigned int fspi)
unsigned int fspi, unsigned int *fres)
{
int i, div = 4;
for (i = 0; i < 7; i++) {
if (fspi * div >= fin)
return i;
goto out;
div <<= 1;
}
return 7;
out:
*fres = fin / div;
return i;
}
static int spi_imx_bytes_per_word(const int bpw)
......@@ -453,6 +455,9 @@ static void mx51_ecspi_reset(struct spi_imx_data *spi_imx)
#define MX31_CSPISTATUS 0x14
#define MX31_STATUS_RR (1 << 3)
#define MX31_CSPI_TESTREG 0x1C
#define MX31_TEST_LBC (1 << 14)
/* These functions also work for the i.MX35, but be aware that
* the i.MX35 has a slightly different register layout for bits
* we do not use here.
......@@ -482,9 +487,11 @@ static int mx31_config(struct spi_device *spi, struct spi_imx_config *config)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
unsigned int clk;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz, &clk) <<
MX31_CSPICTRL_DR_SHIFT;
spi_imx->spi_bus_clk = clk;
if (is_imx35_cspi(spi_imx)) {
reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
......@@ -506,6 +513,13 @@ static int mx31_config(struct spi_device *spi, struct spi_imx_config *config)
writel(reg, spi_imx->base + MXC_CSPICTRL);
reg = readl(spi_imx->base + MX31_CSPI_TESTREG);
if (spi->mode & SPI_LOOP)
reg |= MX31_TEST_LBC;
else
reg &= ~MX31_TEST_LBC;
writel(reg, spi_imx->base + MX31_CSPI_TESTREG);
return 0;
}
......@@ -625,9 +639,12 @@ static int mx1_config(struct spi_device *spi, struct spi_imx_config *config)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
unsigned int clk;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz, &clk) <<
MX1_CSPICTRL_DR_SHIFT;
spi_imx->spi_bus_clk = clk;
reg |= config->bpw - 1;
if (spi->mode & SPI_CPHA)
......@@ -1179,7 +1196,7 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
if (is_imx51_ecspi(spi_imx))
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx))
spi_imx->bitbang.master->mode_bits |= SPI_LOOP;
init_completion(&spi_imx->xfer_done);
......@@ -1251,6 +1268,12 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_clk_put;
}
if (!master->cs_gpios) {
dev_err(&pdev->dev, "No CS GPIOs available\n");
ret = -EINVAL;
goto out_clk_put;
}
for (i = 0; i < master->num_chipselect; i++) {
if (!gpio_is_valid(master->cs_gpios[i]))
continue;
......
/*
* Copyright 2016 Broadcom Limited
*
* 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.
*
* 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/device.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "spi-bcm-qspi.h"
#define INTR_BASE_BIT_SHIFT 0x02
#define INTR_COUNT 0x07
struct bcm_iproc_intc {
struct bcm_qspi_soc_intc soc_intc;
struct platform_device *pdev;
void __iomem *int_reg;
void __iomem *int_status_reg;
spinlock_t soclock;
bool big_endian;
};
static u32 bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc *soc_intc)
{
struct bcm_iproc_intc *priv =
container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
void __iomem *mmio = priv->int_status_reg;
int i;
u32 val = 0, sts = 0;
for (i = 0; i < INTR_COUNT; i++) {
if (bcm_qspi_readl(priv->big_endian, mmio + (i * 4)))
val |= 1UL << i;
}
if (val & INTR_MSPI_DONE_MASK)
sts |= MSPI_DONE;
if (val & BSPI_LR_INTERRUPTS_ALL)
sts |= BSPI_DONE;
if (val & BSPI_LR_INTERRUPTS_ERROR)
sts |= BSPI_ERR;
return sts;
}
static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc *soc_intc, int type)
{
struct bcm_iproc_intc *priv =
container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
void __iomem *mmio = priv->int_status_reg;
u32 mask = get_qspi_mask(type);
int i;
for (i = 0; i < INTR_COUNT; i++) {
if (mask & (1UL << i))
bcm_qspi_writel(priv->big_endian, 1, mmio + (i * 4));
}
}
static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc *soc_intc, int type,
bool en)
{
struct bcm_iproc_intc *priv =
container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
void __iomem *mmio = priv->int_reg;
u32 mask = get_qspi_mask(type);
u32 val;
unsigned long flags;
spin_lock_irqsave(&priv->soclock, flags);
val = bcm_qspi_readl(priv->big_endian, mmio);
if (en)
val = val | (mask << INTR_BASE_BIT_SHIFT);
else
val = val & ~(mask << INTR_BASE_BIT_SHIFT);
bcm_qspi_writel(priv->big_endian, val, mmio);
spin_unlock_irqrestore(&priv->soclock, flags);
}
static int bcm_iproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bcm_iproc_intc *priv;
struct bcm_qspi_soc_intc *soc_intc;
struct resource *res;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
soc_intc = &priv->soc_intc;
priv->pdev = pdev;
spin_lock_init(&priv->soclock);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs");
priv->int_reg = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->int_reg))
return PTR_ERR(priv->int_reg);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"intr_status_reg");
priv->int_status_reg = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->int_status_reg))
return PTR_ERR(priv->int_status_reg);
priv->big_endian = of_device_is_big_endian(dev->of_node);
bcm_iproc_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
bcm_iproc_qspi_int_set(soc_intc, MSPI_BSPI_DONE, false);
soc_intc->bcm_qspi_int_ack = bcm_iproc_qspi_int_ack;
soc_intc->bcm_qspi_int_set = bcm_iproc_qspi_int_set;
soc_intc->bcm_qspi_get_int_status = bcm_iproc_qspi_get_l2_int_status;
return bcm_qspi_probe(pdev, soc_intc);
}
static int bcm_iproc_remove(struct platform_device *pdev)
{
return bcm_qspi_remove(pdev);
}
static const struct of_device_id bcm_iproc_of_match[] = {
{ .compatible = "brcm,spi-nsp-qspi" },
{ .compatible = "brcm,spi-ns2-qspi" },
{},
};
MODULE_DEVICE_TABLE(of, bcm_iproc_of_match);
static struct platform_driver bcm_iproc_driver = {
.probe = bcm_iproc_probe,
.remove = bcm_iproc_remove,
.driver = {
.name = "bcm_iproc",
.pm = &bcm_qspi_pm_ops,
.of_match_table = bcm_iproc_of_match,
}
};
module_platform_driver(bcm_iproc_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Kamal Dasu");
MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");
/*
* J-Core SPI controller driver
*
* Copyright (C) 2012-2016 Smart Energy Instruments, Inc.
*
* Current version by Rich Felker
* Based loosely on initial version by Oleksandr G Zhadan
*
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/delay.h>
#define DRV_NAME "jcore_spi"
#define CTRL_REG 0x0
#define DATA_REG 0x4
#define JCORE_SPI_CTRL_XMIT 0x02
#define JCORE_SPI_STAT_BUSY 0x02
#define JCORE_SPI_CTRL_LOOP 0x08
#define JCORE_SPI_CTRL_CS_BITS 0x15
#define JCORE_SPI_WAIT_RDY_MAX_LOOP 2000000
struct jcore_spi {
struct spi_master *master;
void __iomem *base;
unsigned int cs_reg;
unsigned int speed_reg;
unsigned int speed_hz;
unsigned int clock_freq;
};
static int jcore_spi_wait(void __iomem *ctrl_reg)
{
unsigned timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP;
do {
if (!(readl(ctrl_reg) & JCORE_SPI_STAT_BUSY))
return 0;
cpu_relax();
} while (--timeout);
return -EBUSY;
}
static void jcore_spi_program(struct jcore_spi *hw)
{
void __iomem *ctrl_reg = hw->base + CTRL_REG;
if (jcore_spi_wait(ctrl_reg))
dev_err(hw->master->dev.parent,
"timeout waiting to program ctrl reg.\n");
writel(hw->cs_reg | hw->speed_reg, ctrl_reg);
}
static void jcore_spi_chipsel(struct spi_device *spi, bool value)
{
struct jcore_spi *hw = spi_master_get_devdata(spi->master);
u32 csbit = 1U << (2 * spi->chip_select);
dev_dbg(hw->master->dev.parent, "chipselect %d\n", spi->chip_select);
if (value)
hw->cs_reg |= csbit;
else
hw->cs_reg &= ~csbit;
jcore_spi_program(hw);
}
static void jcore_spi_baudrate(struct jcore_spi *hw, int speed)
{
if (speed == hw->speed_hz) return;
hw->speed_hz = speed;
if (speed >= hw->clock_freq / 2)
hw->speed_reg = 0;
else
hw->speed_reg = ((hw->clock_freq / 2 / speed) - 1) << 27;
jcore_spi_program(hw);
dev_dbg(hw->master->dev.parent, "speed=%d reg=0x%x\n",
speed, hw->speed_reg);
}
static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *t)
{
struct jcore_spi *hw = spi_master_get_devdata(master);
void __iomem *ctrl_reg = hw->base + CTRL_REG;
void __iomem *data_reg = hw->base + DATA_REG;
u32 xmit;
/* data buffers */
const unsigned char *tx;
unsigned char *rx;
unsigned int len;
unsigned int count;
jcore_spi_baudrate(hw, t->speed_hz);
xmit = hw->cs_reg | hw->speed_reg | JCORE_SPI_CTRL_XMIT;
tx = t->tx_buf;
rx = t->rx_buf;
len = t->len;
for (count = 0; count < len; count++) {
if (jcore_spi_wait(ctrl_reg))
break;
writel(tx ? *tx++ : 0, data_reg);
writel(xmit, ctrl_reg);
if (jcore_spi_wait(ctrl_reg))
break;
if (rx)
*rx++ = readl(data_reg);
}
spi_finalize_current_transfer(master);
if (count < len)
return -EREMOTEIO;
return 0;
}
static int jcore_spi_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct jcore_spi *hw;
struct spi_master *master;
struct resource *res;
u32 clock_freq;
struct clk *clk;
int err = -ENODEV;
master = spi_alloc_master(&pdev->dev, sizeof(struct jcore_spi));
if (!master)
return err;
/* Setup the master state. */
master->num_chipselect = 3;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->transfer_one = jcore_spi_txrx;
master->set_cs = jcore_spi_chipsel;
master->dev.of_node = node;
master->bus_num = pdev->id;
hw = spi_master_get_devdata(master);
hw->master = master;
platform_set_drvdata(pdev, hw);
/* Find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
goto exit_busy;
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), pdev->name))
goto exit_busy;
hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
if (!hw->base)
goto exit_busy;
/*
* The SPI clock rate controlled via a configurable clock divider
* which is applied to the reference clock. A 50 MHz reference is
* most suitable for obtaining standard SPI clock rates, but some
* designs may have a different reference clock, and the DT must
* make the driver aware so that it can properly program the
* requested rate. If the clock is omitted, 50 MHz is assumed.
*/
clock_freq = 50000000;
clk = devm_clk_get(&pdev->dev, "ref_clk");
if (!IS_ERR_OR_NULL(clk)) {
if (clk_enable(clk) == 0)
clock_freq = clk_get_rate(clk);
else
dev_warn(&pdev->dev, "could not enable ref_clk\n");
}
hw->clock_freq = clock_freq;
/* Initialize all CS bits to high. */
hw->cs_reg = JCORE_SPI_CTRL_CS_BITS;
jcore_spi_baudrate(hw, 400000);
/* Register our spi controller */
err = devm_spi_register_master(&pdev->dev, master);
if (err)
goto exit;
return 0;
exit_busy:
err = -EBUSY;
exit:
spi_master_put(master);
return err;
}
static const struct of_device_id jcore_spi_of_match[] = {
{ .compatible = "jcore,spi2" },
{},
};
static struct platform_driver jcore_spi_driver = {
.probe = jcore_spi_probe,
.driver = {
.name = DRV_NAME,
.of_match_table = jcore_spi_of_match,
},
};
module_platform_driver(jcore_spi_driver);
MODULE_DESCRIPTION("J-Core SPI driver");
MODULE_AUTHOR("Rich Felker <dalias@libc.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);
......@@ -405,7 +405,7 @@ struct rx_ranges {
u8 *end;
};
int rx_ranges_cmp(void *priv, struct list_head *a, struct list_head *b)
static int rx_ranges_cmp(void *priv, struct list_head *a, struct list_head *b)
{
struct rx_ranges *rx_a = list_entry(a, struct rx_ranges, list);
struct rx_ranges *rx_b = list_entry(b, struct rx_ranges, list);
......
......@@ -442,6 +442,7 @@ static const struct dev_pm_ops meson_spifc_pm_ops = {
static const struct of_device_id meson_spifc_dt_match[] = {
{ .compatible = "amlogic,meson6-spifc", },
{ .compatible = "amlogic,meson-gxbb-spifc", },
{ },
};
MODULE_DEVICE_TABLE(of, meson_spifc_dt_match);
......
......@@ -253,15 +253,13 @@ static struct ring_desc *ring_desc_get(struct pic32_sqi *sqi)
return NULL;
rdesc = list_first_entry(&sqi->bd_list_free, struct ring_desc, list);
list_del(&rdesc->list);
list_add_tail(&rdesc->list, &sqi->bd_list_used);
list_move_tail(&rdesc->list, &sqi->bd_list_used);
return rdesc;
}
static void ring_desc_put(struct pic32_sqi *sqi, struct ring_desc *rdesc)
{
list_del(&rdesc->list);
list_add(&rdesc->list, &sqi->bd_list_free);
list_move(&rdesc->list, &sqi->bd_list_free);
}
static int pic32_sqi_one_transfer(struct pic32_sqi *sqi,
......
......@@ -23,7 +23,7 @@
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
bool error)
{
struct spi_message *msg = drv_data->cur_msg;
struct spi_message *msg = drv_data->master->cur_msg;
/*
* It is possible that one CPU is handling ROR interrupt and other
......@@ -76,7 +76,8 @@ static struct dma_async_tx_descriptor *
pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
enum dma_transfer_direction dir)
{
struct chip_data *chip = drv_data->cur_chip;
struct chip_data *chip =
spi_get_ctldata(drv_data->master->cur_msg->spi);
struct spi_transfer *xfer = drv_data->cur_transfer;
enum dma_slave_buswidth width;
struct dma_slave_config cfg;
......@@ -146,7 +147,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
{
struct dma_async_tx_descriptor *tx_desc, *rx_desc;
int err = 0;
int err;
tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV);
if (!tx_desc) {
......
This diff is collapsed.
......@@ -53,9 +53,7 @@ struct driver_data {
atomic_t dma_running;
/* Current message transfer state info */
struct spi_message *cur_msg;
struct spi_transfer *cur_transfer;
struct chip_data *cur_chip;
size_t len;
void *tx;
void *tx_end;
......@@ -68,6 +66,9 @@ struct driver_data {
void (*cs_control)(u32 command);
void __iomem *lpss_base;
/* GPIOs for chip selects */
struct gpio_desc **cs_gpiods;
};
struct chip_data {
......
......@@ -982,8 +982,10 @@ static int spi_qup_suspend(struct device *device)
if (ret)
return ret;
clk_disable_unprepare(controller->cclk);
clk_disable_unprepare(controller->iclk);
if (!pm_runtime_suspended(device)) {
clk_disable_unprepare(controller->cclk);
clk_disable_unprepare(controller->iclk);
}
return 0;
}
......
......@@ -295,14 +295,24 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
{
int spbr;
int div = 0;
unsigned long clksrc;
/* Sets output mode, MOSI signal, and (optionally) loopback */
rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
clksrc = clk_get_rate(rspi->clk);
while (div < 3) {
if (rspi->max_speed_hz >= clksrc/4) /* 4=(CLK/2)/2 */
break;
div++;
clksrc /= 2;
}
/* Sets transfer bit rate */
spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk),
2 * rspi->max_speed_hz) - 1;
spbr = DIV_ROUND_UP(clksrc, 2 * rspi->max_speed_hz) - 1;
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
rspi->spcmd |= div << 2;
/* Disable dummy transmission, set byte access */
rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR);
......
......@@ -23,6 +23,7 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/platform_data/sc18is602.h>
#include <linux/gpio/consumer.h>
enum chips { sc18is602, sc18is602b, sc18is603 };
......@@ -50,6 +51,8 @@ struct sc18is602 {
u8 buffer[SC18IS602_BUFSIZ + 1];
int tlen; /* Data queued for tx in buffer */
int rindex; /* Receive data index in buffer */
struct gpio_desc *reset;
};
static int sc18is602_wait_ready(struct sc18is602 *hw, int len)
......@@ -257,6 +260,12 @@ static int sc18is602_probe(struct i2c_client *client,
hw = spi_master_get_devdata(master);
i2c_set_clientdata(client, hw);
/* assert reset and then release */
hw->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(hw->reset))
return PTR_ERR(hw->reset);
gpiod_set_value_cansleep(hw->reset, 0);
hw->master = master;
hw->client = client;
hw->dev = dev;
......
......@@ -175,10 +175,7 @@ static int spi_st_transfer_one(struct spi_master *master,
static void spi_st_cleanup(struct spi_device *spi)
{
int cs = spi->cs_gpio;
if (gpio_is_valid(cs))
devm_gpio_free(&spi->dev, cs);
gpio_free(spi->cs_gpio);
}
/* the spi->mode bits understood by this driver: */
......@@ -201,14 +198,15 @@ static int spi_st_setup(struct spi_device *spi)
return -EINVAL;
}
if (devm_gpio_request(&spi->dev, cs, dev_name(&spi->dev))) {
ret = gpio_request(cs, dev_name(&spi->dev));
if (ret) {
dev_err(&spi->dev, "could not request gpio:%d\n", cs);
return -EINVAL;
return ret;
}
ret = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
if (ret)
return ret;
goto out_free_gpio;
spi_st_clk = clk_get_rate(spi_st->clk);
......@@ -217,7 +215,8 @@ static int spi_st_setup(struct spi_device *spi)
if (sscbrg < 0x07 || sscbrg > BIT(16)) {
dev_err(&spi->dev,
"baudrate %d outside valid range %d\n", sscbrg, hz);
return -EINVAL;
ret = -EINVAL;
goto out_free_gpio;
}
spi_st->baud = spi_st_clk / (2 * sscbrg);
......@@ -266,6 +265,10 @@ static int spi_st_setup(struct spi_device *spi)
readl_relaxed(spi_st->base + SSC_RBUF);
return 0;
out_free_gpio:
gpio_free(cs);
return ret;
}
/* Interrupt fired when TX shift register becomes empty */
......
......@@ -41,6 +41,8 @@ struct ti_qspi_regs {
};
struct ti_qspi {
struct completion transfer_complete;
/* list synchronization */
struct mutex list_lock;
......@@ -54,6 +56,9 @@ struct ti_qspi {
struct ti_qspi_regs ctx_reg;
dma_addr_t mmap_phys_base;
struct dma_chan *rx_chan;
u32 spi_max_frequency;
u32 cmd;
u32 dc;
......@@ -379,6 +384,72 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t,
return 0;
}
static void ti_qspi_dma_callback(void *param)
{
struct ti_qspi *qspi = param;
complete(&qspi->transfer_complete);
}
static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst,
dma_addr_t dma_src, size_t len)
{
struct dma_chan *chan = qspi->rx_chan;
struct dma_device *dma_dev = chan->device;
dma_cookie_t cookie;
enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
struct dma_async_tx_descriptor *tx;
int ret;
tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src,
len, flags);
if (!tx) {
dev_err(qspi->dev, "device_prep_dma_memcpy error\n");
return -EIO;
}
tx->callback = ti_qspi_dma_callback;
tx->callback_param = qspi;
cookie = tx->tx_submit(tx);
ret = dma_submit_error(cookie);
if (ret) {
dev_err(qspi->dev, "dma_submit_error %d\n", cookie);
return -EIO;
}
dma_async_issue_pending(chan);
ret = wait_for_completion_timeout(&qspi->transfer_complete,
msecs_to_jiffies(len));
if (ret <= 0) {
dmaengine_terminate_sync(chan);
dev_err(qspi->dev, "DMA wait_for_completion_timeout\n");
return -ETIMEDOUT;
}
return 0;
}
static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg,
loff_t from)
{
struct scatterlist *sg;
dma_addr_t dma_src = qspi->mmap_phys_base + from;
dma_addr_t dma_dst;
int i, len, ret;
for_each_sg(rx_sg.sgl, sg, rx_sg.nents, i) {
dma_dst = sg_dma_address(sg);
len = sg_dma_len(sg);
ret = ti_qspi_dma_xfer(qspi, dma_dst, dma_src, len);
if (ret)
return ret;
dma_src += len;
}
return 0;
}
static void ti_qspi_enable_memory_map(struct spi_device *spi)
{
struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
......@@ -426,7 +497,7 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi,
QSPI_SPI_SETUP_REG(spi->chip_select));
}
static int ti_qspi_spi_flash_read(struct spi_device *spi,
static int ti_qspi_spi_flash_read(struct spi_device *spi,
struct spi_flash_read_message *msg)
{
struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
......@@ -437,9 +508,23 @@ static int ti_qspi_spi_flash_read(struct spi_device *spi,
if (!qspi->mmap_enabled)
ti_qspi_enable_memory_map(spi);
ti_qspi_setup_mmap_read(spi, msg);
memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len);
if (qspi->rx_chan) {
if (msg->cur_msg_mapped) {
ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from);
if (ret)
goto err_unlock;
} else {
dev_err(qspi->dev, "Invalid address for DMA\n");
ret = -EIO;
goto err_unlock;
}
} else {
memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len);
}
msg->retlen = msg->len;
err_unlock:
mutex_unlock(&qspi->list_lock);
return ret;
......@@ -536,6 +621,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
u32 max_freq;
int ret = 0, num_cs, irq;
dma_cap_mask_t mask;
master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
if (!master)
......@@ -550,6 +636,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
SPI_BPW_MASK(8);
master->spi_flash_read = ti_qspi_spi_flash_read;
if (!of_property_read_u32(np, "num-cs", &num_cs))
master->num_chipselect = num_cs;
......@@ -592,17 +679,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
goto free_master;
}
if (res_mmap) {
qspi->mmap_base = devm_ioremap_resource(&pdev->dev,
res_mmap);
master->spi_flash_read = ti_qspi_spi_flash_read;
if (IS_ERR(qspi->mmap_base)) {
dev_err(&pdev->dev,
"falling back to PIO mode\n");
master->spi_flash_read = NULL;
}
}
qspi->mmap_enabled = false;
if (of_property_read_bool(np, "syscon-chipselects")) {
qspi->ctrl_base =
......@@ -633,11 +709,37 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
qspi->spi_max_frequency = max_freq;
ret = devm_spi_register_master(&pdev->dev, master);
if (ret)
goto free_master;
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
return 0;
qspi->rx_chan = dma_request_chan_by_mask(&mask);
if (!qspi->rx_chan) {
dev_err(qspi->dev,
"No Rx DMA available, trying mmap mode\n");
ret = 0;
goto no_dma;
}
master->dma_rx = qspi->rx_chan;
init_completion(&qspi->transfer_complete);
if (res_mmap)
qspi->mmap_phys_base = (dma_addr_t)res_mmap->start;
no_dma:
if (!qspi->rx_chan && res_mmap) {
qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap);
if (IS_ERR(qspi->mmap_base)) {
dev_info(&pdev->dev,
"mmap failed with error %ld using PIO mode\n",
PTR_ERR(qspi->mmap_base));
qspi->mmap_base = NULL;
master->spi_flash_read = NULL;
}
}
qspi->mmap_enabled = false;
ret = devm_spi_register_master(&pdev->dev, master);
if (!ret)
return 0;
free_master:
spi_master_put(master);
......@@ -656,6 +758,9 @@ static int ti_qspi_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (qspi->rx_chan)
dma_release_channel(qspi->rx_chan);
return 0;
}
......
......@@ -346,7 +346,7 @@ static int txx9spi_probe(struct platform_device *dev)
c->clk = NULL;
goto exit;
}
ret = clk_enable(c->clk);
ret = clk_prepare_enable(c->clk);
if (ret) {
c->clk = NULL;
goto exit;
......@@ -395,7 +395,7 @@ static int txx9spi_probe(struct platform_device *dev)
exit_busy:
ret = -EBUSY;
exit:
clk_disable(c->clk);
clk_disable_unprepare(c->clk);
spi_master_put(master);
return ret;
}
......@@ -406,7 +406,7 @@ static int txx9spi_remove(struct platform_device *dev)
struct txx9spi *c = spi_master_get_devdata(master);
flush_work(&c->work);
clk_disable(c->clk);
clk_disable_unprepare(c->clk);
return 0;
}
......
......@@ -11,6 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
......@@ -405,8 +406,9 @@ static int xlp_spi_probe(struct platform_device *pdev)
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "could not get spi clock\n");
return -ENODEV;
return PTR_ERR(clk);
}
xspi->spi_clk = clk_get_rate(clk);
master = spi_alloc_master(&pdev->dev, 0);
......@@ -437,6 +439,14 @@ static int xlp_spi_probe(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id xlp_spi_acpi_match[] = {
{ "BRCM900D", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match);
#endif
static const struct of_device_id xlp_spi_dt_id[] = {
{ .compatible = "netlogic,xlp832-spi" },
{ },
......@@ -447,6 +457,7 @@ static struct platform_driver xlp_spi_driver = {
.driver = {
.name = "xlp-spi",
.of_match_table = xlp_spi_dt_id,
.acpi_match_table = ACPI_PTR(xlp_spi_acpi_match),
},
};
module_platform_driver(xlp_spi_driver);
......
......@@ -37,6 +37,7 @@
#include <linux/kthread.h>
#include <linux/ioport.h>
#include <linux/acpi.h>
#include <linux/highmem.h>
#define CREATE_TRACE_POINTS
#include <trace/events/spi.h>
......@@ -709,6 +710,13 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
{
const bool vmalloced_buf = is_vmalloc_addr(buf);
unsigned int max_seg_size = dma_get_max_seg_size(dev);
#ifdef CONFIG_HIGHMEM
const bool kmap_buf = ((unsigned long)buf >= PKMAP_BASE &&
(unsigned long)buf < (PKMAP_BASE +
(LAST_PKMAP * PAGE_SIZE)));
#else
const bool kmap_buf = false;
#endif
int desc_len;
int sgs;
struct page *vm_page;
......@@ -716,7 +724,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
size_t min;
int i, ret;
if (vmalloced_buf) {
if (vmalloced_buf || kmap_buf) {
desc_len = min_t(int, max_seg_size, PAGE_SIZE);
sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len);
} else if (virt_addr_valid(buf)) {
......@@ -732,10 +740,13 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
for (i = 0; i < sgs; i++) {
if (vmalloced_buf) {
if (vmalloced_buf || kmap_buf) {
min = min_t(size_t,
len, desc_len - offset_in_page(buf));
vm_page = vmalloc_to_page(buf);
if (vmalloced_buf)
vm_page = vmalloc_to_page(buf);
else
vm_page = kmap_to_page(buf);
if (!vm_page) {
sg_free_table(sgt);
return -ENOMEM;
......
......@@ -83,7 +83,6 @@
#define SSSR_RFS (1 << 6) /* Receive FIFO Service Request */
#define SSSR_ROR (1 << 7) /* Receive FIFO Overrun */
#ifdef CONFIG_ARCH_PXA
#define RX_THRESH_DFLT 8
#define TX_THRESH_DFLT 8
......@@ -95,19 +94,16 @@
#define SSCR1_RFT (0x00003c00) /* Receive FIFO Threshold (mask) */
#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
#else
#define RX_THRESH_DFLT 2
#define TX_THRESH_DFLT 2
#define RX_THRESH_CE4100_DFLT 2
#define TX_THRESH_CE4100_DFLT 2
#define SSSR_TFL_MASK (0x3 << 8) /* Transmit FIFO Level mask */
#define SSSR_RFL_MASK (0x3 << 12) /* Receive FIFO Level mask */
#define CE4100_SSSR_TFL_MASK (0x3 << 8) /* Transmit FIFO Level mask */
#define CE4100_SSSR_RFL_MASK (0x3 << 12) /* Receive FIFO Level mask */
#define SSCR1_TFT (0x000000c0) /* Transmit FIFO Threshold (mask) */
#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..4] */
#define SSCR1_RFT (0x00000c00) /* Receive FIFO Threshold (mask) */
#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
#endif
#define CE4100_SSCR1_TFT (0x000000c0) /* Transmit FIFO Threshold (mask) */
#define CE4100_SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..4] */
#define CE4100_SSCR1_RFT (0x00000c00) /* Receive FIFO Threshold (mask) */
#define CE4100_SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
/* QUARK_X1000 SSCR0 bit definition */
#define QUARK_X1000_SSCR0_DSS (0x1F) /* Data Size Select (mask) */
......
......@@ -312,6 +312,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @flags: other constraints relevant to this driver
* @max_transfer_size: function that returns the max transfer size for
* a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
* @max_message_size: function that returns the max message size for
* a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
* @io_mutex: mutex for physical bus access
* @bus_lock_spinlock: spinlock for SPI bus locking
* @bus_lock_mutex: mutex for exclusion of multiple callers
......@@ -442,10 +444,11 @@ struct spi_master {
#define SPI_MASTER_MUST_TX BIT(4) /* requires tx */
/*
* on some hardware transfer size may be constrained
* on some hardware transfer / message size may be constrained
* the limit may depend on device transfer settings
*/
size_t (*max_transfer_size)(struct spi_device *spi);
size_t (*max_message_size)(struct spi_device *spi);
/* I/O mutex */
struct mutex io_mutex;
......@@ -905,12 +908,26 @@ extern int spi_async_locked(struct spi_device *spi,
struct spi_message *message);
static inline size_t
spi_max_transfer_size(struct spi_device *spi)
spi_max_message_size(struct spi_device *spi)
{
struct spi_master *master = spi->master;
if (!master->max_transfer_size)
if (!master->max_message_size)
return SIZE_MAX;
return master->max_transfer_size(spi);
return master->max_message_size(spi);
}
static inline size_t
spi_max_transfer_size(struct spi_device *spi)
{
struct spi_master *master = spi->master;
size_t tr_max = SIZE_MAX;
size_t msg_max = spi_max_message_size(spi);
if (master->max_transfer_size)
tr_max = master->max_transfer_size(spi);
/* transfer size limit must not be greater than messsage size limit */
return min(tr_max, msg_max);
}
/*---------------------------------------------------------------------------*/
......@@ -979,6 +996,30 @@ extern int spi_sync_locked(struct spi_device *spi, struct spi_message *message);
extern int spi_bus_lock(struct spi_master *master);
extern int spi_bus_unlock(struct spi_master *master);
/**
* spi_sync_transfer - synchronous SPI data transfer
* @spi: device with which data will be exchanged
* @xfers: An array of spi_transfers
* @num_xfers: Number of items in the xfer array
* Context: can sleep
*
* Does a synchronous SPI data transfer of the given spi_transfer array.
*
* For more specific semantics see spi_sync().
*
* Return: Return: zero on success, else a negative error code.
*/
static inline int
spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers,
unsigned int num_xfers)
{
struct spi_message msg;
spi_message_init_with_transfers(&msg, xfers, num_xfers);
return spi_sync(spi, &msg);
}
/**
* spi_write - SPI synchronous write
* @spi: device to which data will be written
......@@ -998,11 +1039,8 @@ spi_write(struct spi_device *spi, const void *buf, size_t len)
.tx_buf = buf,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(spi, &m);
return spi_sync_transfer(spi, &t, 1);
}
/**
......@@ -1024,35 +1062,8 @@ spi_read(struct spi_device *spi, void *buf, size_t len)
.rx_buf = buf,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(spi, &m);
}
/**
* spi_sync_transfer - synchronous SPI data transfer
* @spi: device with which data will be exchanged
* @xfers: An array of spi_transfers
* @num_xfers: Number of items in the xfer array
* Context: can sleep
*
* Does a synchronous SPI data transfer of the given spi_transfer array.
*
* For more specific semantics see spi_sync().
*
* Return: Return: zero on success, else a negative error code.
*/
static inline int
spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers,
unsigned int num_xfers)
{
struct spi_message msg;
spi_message_init_with_transfers(&msg, xfers, num_xfers);
return spi_sync(spi, &msg);
return spi_sync_transfer(spi, &t, 1);
}
/* this copies txbuf and rxbuf data; for small transfers only! */
......
CC = $(CROSS_COMPILE)gcc
all: spidev_test spidev_fdx
clean:
......
......@@ -19,6 +19,7 @@
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
......@@ -284,7 +285,7 @@ static void parse_opts(int argc, char *argv[])
static void transfer_escaped_string(int fd, char *str)
{
size_t size = strlen(str + 1);
size_t size = strlen(str);
uint8_t *tx;
uint8_t *rx;
......
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