spi: Updates for v4.15

This release is almost entirely driver changes, there's a couple of
 fixes in the core but otherwise it's all drivers:
 
  - Fix for mixed dynamic and static bus number assignment.
  - Fixes for some leaks arising from confusing lifetime rules during
    device unregistration and improved documentation to try to help avoid
    this in the future.
  - Fixes to make the native chip select support for i.MX usable.
  - Slave mode support for i.MX.
  - Support for Coldfire MCF5441x DSPI, Renesas R8A7443/5 and Spreadtrum
    ADI.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAloJi2ATHGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0IehB/9cM3BMqbo6cSkKvYRcBOHyQZqtBkbc
 LlLcMt9hpqWPA9oYU6D6SnZrMDNz8fr8YmpP279OWFJc/l8vuMpzOCz2tOB/OZyE
 9fANUhu98HioVS48vN0rlgsaW48rQDothtvwbAP8ED2LGivhruay6G+oG062r7/V
 nneWD8YQLmNSd4FaA2qKl0DNI7afkmnqakhX/c9cvctZvGCJmxW//Y20cOyiSL7T
 g0DXk5yirZGI/wO5WxOfCXT9lDCdz8XYZJmOC/Uh5X9gc4qmK8RSC/ydsmRwWDFm
 4Xq542cooKFyuMQLiVqi3ukixk8rMi7htGN464m9aMAu2Hn4IuJjZaOh
 =wkKu
 -----END PGP SIGNATURE-----

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

Pull spi updates from Mark Brown:
 "This release is almost entirely driver changes, there's a couple of
  fixes in the core but otherwise it's all drivers:

   - fix for mixed dynamic and static bus number assignment.

   - fixes for some leaks arising from confusing lifetime rules during
     device unregistration and improved documentation to try to help
     avoid this in the future.

   - fixes to make the native chip select support for i.MX usable.

   - slave mode support for i.MX.

   - support for Coldfire MCF5441x DSPI, Renesas R8A7443/5 and
     Spreadtrum ADI"

* tag 'spi-v4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (31 commits)
  spi: imx: Don't require platform data chipselect array
  spi: imx: Fix failure path leak on GPIO request error
  spi: imx: GPIO based chip selects should not be required
  spi: sh-msiof: remove redundant pointer dev
  spi: s3c64xx: remove redundant pointer sci
  spi: spi-fsl-dspi: enabling Coldfire mcf5441x dspi
  spi: fix IDR collision on systems with both fixed and dynamic SPI bus numbers
  spi: orion: remove redundant assignment of status to zero
  spi: sh-msiof: Fix DMA transfer size check
  spi: imx: Fix failure path leak on GPIO request error
  spi: spi-axi: fix potential use-after-free after deregistration
  spi: document odd controller reference handling
  spi: fix use-after-free at controller deregistration
  spi: sprd: Fix the possible negative value of BIT()
  spi: sprd-adi: fix platform_no_drv_owner.cocci warnings
  spi: a3700: Change SPI mode before asserting chip-select
  spi: tegra114: correct register name in definition
  spi: spreadtrum adi: add hwspinlock dependency
  spi: sh-msiof: Use of_device_get_match_data() helper
  spi: rspi: Use of_device_get_match_data() helper
  ...
This commit is contained in:
Linus Torvalds 2017-11-13 09:43:24 -08:00
commit e75427c694
19 changed files with 926 additions and 116 deletions

View file

@ -1,7 +1,9 @@
Renesas MSIOF spi controller
Required properties:
- compatible : "renesas,msiof-r8a7790" (R-Car H2)
- compatible : "renesas,msiof-r8a7743" (RZ/G1M)
"renesas,msiof-r8a7745" (RZ/G1E)
"renesas,msiof-r8a7790" (R-Car H2)
"renesas,msiof-r8a7791" (R-Car M2-W)
"renesas,msiof-r8a7792" (R-Car V2H)
"renesas,msiof-r8a7793" (R-Car M2-N)
@ -10,7 +12,7 @@ Required properties:
"renesas,msiof-r8a7796" (R-Car M3-W)
"renesas,msiof-sh73a0" (SH-Mobile AG5)
"renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device)
"renesas,rcar-gen2-msiof" (generic R-Car Gen2 compatible device)
"renesas,rcar-gen2-msiof" (generic R-Car Gen2 and RZ/G1 compatible device)
"renesas,rcar-gen3-msiof" (generic R-Car Gen3 compatible device)
"renesas,sh-msiof" (deprecated)

View file

@ -24,6 +24,16 @@ Required properties:
based on a specific SoC configuration.
- interrupts: interrupt number mapped to CPU.
- clocks: spi clk phandle
For 66AK2G this property should be set per binding,
Documentation/devicetree/bindings/clock/ti,sci-clk.txt
SoC-specific Required Properties:
The following are mandatory properties for Keystone 2 66AK2G SoCs only:
- power-domains: Should contain a phandle to a PM domain provider node
and an args specifier containing the SPI device id
value. This property is as per the binding,
Optional:
- cs-gpios: gpio chip selects

View file

@ -5,11 +5,14 @@ Required properties:
"renesas,rspi-<soctype>", "renesas,rspi" as fallback.
For Renesas Serial Peripheral Interface on RZ/A1H:
"renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
For Quad Serial Peripheral Interface on R-Car Gen2:
For Quad Serial Peripheral Interface on R-Car Gen2 and
RZ/G1 devices:
"renesas,qspi-<soctype>", "renesas,qspi" as fallback.
Examples with soctypes are:
- "renesas,rspi-sh7757" (SH)
- "renesas,rspi-r7s72100" (RZ/A1H)
- "renesas,qspi-r8a7743" (RZ/G1M)
- "renesas,qspi-r8a7745" (RZ/G1E)
- "renesas,qspi-r8a7790" (R-Car H2)
- "renesas,qspi-r8a7791" (R-Car M2-W)
- "renesas,qspi-r8a7792" (R-Car V2H)

View file

@ -0,0 +1,58 @@
Spreadtrum ADI controller
ADI is the abbreviation of Anolog-Digital interface, which is used to access
analog chip (such as PMIC) from digital chip. ADI controller follows the SPI
framework for its hardware implementation is alike to SPI bus and its timing
is compatile to SPI timing.
ADI controller has 50 channels including 2 software read/write channels and
48 hardware channels to access analog chip. For 2 software read/write channels,
users should set ADI registers to access analog chip. For hardware channels,
we can configure them to allow other hardware components to use it independently,
which means we can just link one analog chip address to one hardware channel,
then users can access the mapped analog chip address by this hardware channel
triggered by hardware components instead of ADI software channels.
Thus we introduce one property named "sprd,hw-channels" to configure hardware
channels, the first value specifies the hardware channel id which is used to
transfer data triggered by hardware automatically, and the second value specifies
the analog chip address where user want to access by hardware components.
Since we have multi-subsystems will use unique ADI to access analog chip, when
one system is reading/writing data by ADI software channels, that should be under
one hardware spinlock protection to prevent other systems from reading/writing
data by ADI software channels at the same time, or two parallel routine of setting
ADI registers will make ADI controller registers chaos to lead incorrect results.
Then we need one hardware spinlock to synchronize between the multiple subsystems.
Required properties:
- compatible: Should be "sprd,sc9860-adi".
- reg: Offset and length of ADI-SPI controller register space.
- hwlocks: Reference to a phandle of a hwlock provider node.
- hwlock-names: Reference to hwlock name strings defined in the same order
as the hwlocks, should be "adi".
- #address-cells: Number of cells required to define a chip select address
on the ADI-SPI bus. Should be set to 1.
- #size-cells: Size of cells required to define a chip select address size
on the ADI-SPI bus. Should be set to 0.
Optional properties:
- sprd,hw-channels: This is an array of channel values up to 49 channels.
The first value specifies the hardware channel id which is used to
transfer data triggered by hardware automatically, and the second
value specifies the analog chip address where user want to access
by hardware components.
SPI slave nodes must be children of the SPI controller node and can contain
properties described in Documentation/devicetree/bindings/spi/spi-bus.txt.
Example:
adi_bus: spi@40030000 {
compatible = "sprd,sc9860-adi";
reg = <0 0x40030000 0 0x10000>;
hwlocks = <&hwlock1 0>;
hwlock-names = "adi";
#address-cells = <1>;
#size-cells = <0>;
sprd,hw-channels = <30 0x8c20>;
};

View file

@ -1,10 +1,6 @@
#
# SPI driver configuration
#
# NOTE: the reason this doesn't show SPI slave support is mostly that
# nobody's needed a slave side API yet. The master-role API is not
# fully appropriate there, so it'd need some thought to do well.
#
menuconfig SPI
bool "SPI support"
depends on HAS_IOMEM
@ -379,7 +375,7 @@ config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select REGMAP_MMIO
depends on HAS_DMA
depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || M5441x || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
mode. VF610 platform uses the controller.
@ -626,6 +622,13 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
config SPI_SPRD_ADI
tristate "Spreadtrum ADI controller"
depends on ARCH_SPRD || COMPILE_TEST
depends on HWSPINLOCK || (COMPILE_TEST && !HWSPINLOCK)
help
ADI driver based on SPI for Spreadtrum SoCs.
config SPI_STM32
tristate "STMicroelectronics STM32 SPI controller"
depends on ARCH_STM32 || COMPILE_TEST

View file

@ -91,6 +91,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o
obj-$(CONFIG_SPI_STM32) += spi-stm32.o
obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o

View file

@ -213,7 +213,7 @@ static void a3700_spi_mode_set(struct a3700_spi *a3700_spi,
}
static void a3700_spi_clock_set(struct a3700_spi *a3700_spi,
unsigned int speed_hz, u16 mode)
unsigned int speed_hz)
{
u32 val;
u32 prescale;
@ -231,17 +231,6 @@ static void a3700_spi_clock_set(struct a3700_spi *a3700_spi,
val |= A3700_SPI_CLK_CAPT_EDGE;
spireg_write(a3700_spi, A3700_SPI_IF_TIME_REG, val);
}
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val &= ~(A3700_SPI_CLK_POL | A3700_SPI_CLK_PHA);
if (mode & SPI_CPOL)
val |= A3700_SPI_CLK_POL;
if (mode & SPI_CPHA)
val |= A3700_SPI_CLK_PHA;
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
}
static void a3700_spi_bytelen_set(struct a3700_spi *a3700_spi, unsigned int len)
@ -423,7 +412,7 @@ static void a3700_spi_transfer_setup(struct spi_device *spi,
a3700_spi = spi_master_get_devdata(spi->master);
a3700_spi_clock_set(a3700_spi, xfer->speed_hz, spi->mode);
a3700_spi_clock_set(a3700_spi, xfer->speed_hz);
byte_len = xfer->bits_per_word >> 3;
@ -584,6 +573,8 @@ static int a3700_spi_prepare_message(struct spi_master *master,
a3700_spi_bytelen_set(a3700_spi, 4);
a3700_spi_mode_set(a3700_spi, spi->mode);
return 0;
}

View file

@ -553,7 +553,7 @@ static int spi_engine_probe(struct platform_device *pdev)
static int spi_engine_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct spi_engine *spi_engine = spi_master_get_devdata(master);
int irq = platform_get_irq(pdev, 0);
@ -561,6 +561,8 @@ static int spi_engine_remove(struct platform_device *pdev)
free_irq(irq, master);
spi_master_put(master);
writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET);

View file

@ -32,6 +32,7 @@
#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-fsl-dspi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/time.h>
@ -151,6 +152,11 @@ static const struct fsl_dspi_devtype_data ls2085a_data = {
.max_clock_factor = 8,
};
static const struct fsl_dspi_devtype_data coldfire_data = {
.trans_mode = DSPI_EOQ_MODE,
.max_clock_factor = 8,
};
struct fsl_dspi_dma {
/* Length of transfer in words of DSPI_FIFO_SIZE */
u32 curr_xfer_len;
@ -741,6 +747,7 @@ static int dspi_setup(struct spi_device *spi)
{
struct chip_data *chip;
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
struct fsl_dspi_platform_data *pdata;
u32 cs_sck_delay = 0, sck_cs_delay = 0;
unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
unsigned char pasc = 0, asc = 0, fmsz = 0;
@ -761,11 +768,18 @@ static int dspi_setup(struct spi_device *spi)
return -ENOMEM;
}
pdata = dev_get_platdata(&dspi->pdev->dev);
if (!pdata) {
of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay",
&cs_sck_delay);
of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay",
&sck_cs_delay);
} else {
cs_sck_delay = pdata->cs_sck_delay;
sck_cs_delay = pdata->sck_cs_delay;
}
chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
@ -949,6 +963,7 @@ static int dspi_probe(struct platform_device *pdev)
struct fsl_dspi *dspi;
struct resource *res;
void __iomem *base;
struct fsl_dspi_platform_data *pdata;
int ret = 0, cs_num, bus_num;
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
@ -969,6 +984,14 @@ static int dspi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) |
SPI_BPW_MASK(16);
pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
master->num_chipselect = pdata->cs_num;
master->bus_num = pdata->bus_num;
dspi->devtype_data = &coldfire_data;
} else {
ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
if (ret < 0) {
dev_err(&pdev->dev, "can't get spi-num-chipselects\n");
@ -989,6 +1012,7 @@ static int dspi_probe(struct platform_device *pdev)
ret = -EFAULT;
goto out_master_put;
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);

View file

@ -53,10 +53,13 @@
/* generic defines to abstract from the different register layouts */
#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */
#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */
#define MXC_INT_RDR BIT(4) /* Receive date threshold interrupt */
/* The maximum bytes that a sdma BD can transfer.*/
#define MAX_SDMA_BD_BYTES (1 << 15)
#define MX51_ECSPI_CTRL_MAX_BURST 512
/* The maximum bytes that IMX53_ECSPI can transfer in slave mode.*/
#define MX53_MAX_TRANSFER_BYTES 512
enum spi_imx_devtype {
IMX1_CSPI,
@ -76,7 +79,9 @@ struct spi_imx_devtype_data {
void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *);
void (*reset)(struct spi_imx_data *);
void (*disable)(struct spi_imx_data *);
bool has_dmamode;
bool has_slavemode;
unsigned int fifo_size;
bool dynamic_burst;
enum spi_imx_devtype devtype;
@ -108,6 +113,11 @@ struct spi_imx_data {
unsigned int dynamic_burst, read_u32;
unsigned int word_mask;
/* Slave mode */
bool slave_mode;
bool slave_aborted;
unsigned int slave_burst;
/* DMA */
bool usedma;
u32 wml;
@ -221,6 +231,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
if (!master->dma_rx)
return false;
if (spi_imx->slave_mode)
return false;
bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
@ -262,6 +275,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_INT 0x10
#define MX51_ECSPI_INT_TEEN (1 << 0)
#define MX51_ECSPI_INT_RREN (1 << 3)
#define MX51_ECSPI_INT_RDREN (1 << 4)
#define MX51_ECSPI_DMA 0x14
#define MX51_ECSPI_DMA_TX_WML(wml) ((wml) & 0x3f)
@ -378,6 +392,44 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
spi_imx_buf_tx_u16(spi_imx);
}
static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
{
u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA));
if (spi_imx->rx_buf) {
int n_bytes = spi_imx->slave_burst % sizeof(val);
if (!n_bytes)
n_bytes = sizeof(val);
memcpy(spi_imx->rx_buf,
((u8 *)&val) + sizeof(val) - n_bytes, n_bytes);
spi_imx->rx_buf += n_bytes;
spi_imx->slave_burst -= n_bytes;
}
}
static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
{
u32 val = 0;
int n_bytes = spi_imx->count % sizeof(val);
if (!n_bytes)
n_bytes = sizeof(val);
if (spi_imx->tx_buf) {
memcpy(((u8 *)&val) + sizeof(val) - n_bytes,
spi_imx->tx_buf, n_bytes);
val = cpu_to_be32(val);
spi_imx->tx_buf += n_bytes;
}
spi_imx->count -= n_bytes;
writel(val, spi_imx->base + MXC_CSPITXDATA);
}
/* MX51 eCSPI */
static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
unsigned int fspi, unsigned int *fres)
@ -427,6 +479,9 @@ static void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
if (enable & MXC_INT_RR)
val |= MX51_ECSPI_INT_RREN;
if (enable & MXC_INT_RDR)
val |= MX51_ECSPI_INT_RDREN;
writel(val, spi_imx->base + MX51_ECSPI_INT);
}
@ -439,6 +494,15 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
}
static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
{
u32 ctrl;
ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
ctrl &= ~MX51_ECSPI_CTRL_ENABLE;
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
}
static int mx51_ecspi_config(struct spi_device *spi)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
@ -446,13 +510,10 @@ static int mx51_ecspi_config(struct spi_device *spi)
u32 clk = spi_imx->speed_hz, delay, reg;
u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
/*
* The hardware seems to have a race condition when changing modes. The
* current assumption is that the selection of the channel arrives
* earlier in the hardware than the mode bits when they are written at
* the same time.
* So set master mode for all channels as we do not support slave mode.
*/
/* set Master or Slave mode */
if (spi_imx->slave_mode)
ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK;
else
ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
/*
@ -468,8 +529,21 @@ static int mx51_ecspi_config(struct spi_device *spi)
/* set chip select to use */
ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
ctrl |= (spi_imx->bits_per_word - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
ctrl |= (spi_imx->slave_burst * 8 - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
else
ctrl |= (spi_imx->bits_per_word - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
/*
* eCSPI burst completion by Chip Select signal in Slave mode
* is not functional for imx53 Soc, config SPI burst completed when
* BURST_LENGTH + 1 bits are received
*/
if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
else
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
if (spi->mode & SPI_CPHA)
@ -805,6 +879,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
.has_slavemode = false,
.devtype = IMX1_CSPI,
};
@ -817,6 +892,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
.has_slavemode = false,
.devtype = IMX21_CSPI,
};
@ -830,6 +906,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
.has_slavemode = false,
.devtype = IMX27_CSPI,
};
@ -842,6 +919,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
.has_slavemode = false,
.devtype = IMX31_CSPI,
};
@ -855,6 +933,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = true,
.dynamic_burst = false,
.has_slavemode = false,
.devtype = IMX35_CSPI,
};
@ -867,6 +946,8 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.fifo_size = 64,
.has_dmamode = true,
.dynamic_burst = true,
.has_slavemode = true,
.disable = mx51_ecspi_disable,
.devtype = IMX51_ECSPI,
};
@ -878,6 +959,8 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
.reset = mx51_ecspi_reset,
.fifo_size = 64,
.has_dmamode = true,
.has_slavemode = true,
.disable = mx51_ecspi_disable,
.devtype = IMX53_ECSPI,
};
@ -945,6 +1028,7 @@ static void spi_imx_push(struct spi_imx_data *spi_imx)
spi_imx->txfifo++;
}
if (!spi_imx->slave_mode)
spi_imx->devtype_data->trigger(spi_imx);
}
@ -952,7 +1036,8 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id)
{
struct spi_imx_data *spi_imx = dev_id;
while (spi_imx->devtype_data->rx_available(spi_imx)) {
while (spi_imx->txfifo &&
spi_imx->devtype_data->rx_available(spi_imx)) {
spi_imx->rx(spi_imx);
spi_imx->txfifo--;
}
@ -1034,7 +1119,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->speed_hz = t->speed_hz;
/* Initialize the functions for transfer */
if (spi_imx->devtype_data->dynamic_burst) {
if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) {
u32 mask;
spi_imx->dynamic_burst = 0;
@ -1078,6 +1163,12 @@ static int spi_imx_setupxfer(struct spi_device *spi,
return ret;
}
if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
spi_imx->rx = mx53_ecspi_rx_slave;
spi_imx->tx = mx53_ecspi_tx_slave;
spi_imx->slave_burst = t->len;
}
spi_imx->devtype_data->config(spi);
return 0;
@ -1262,11 +1353,61 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
return transfer->len;
}
static int spi_imx_pio_transfer_slave(struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
int ret = transfer->len;
if (is_imx53_ecspi(spi_imx) &&
transfer->len > MX53_MAX_TRANSFER_BYTES) {
dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n",
MX53_MAX_TRANSFER_BYTES);
return -EMSGSIZE;
}
spi_imx->tx_buf = transfer->tx_buf;
spi_imx->rx_buf = transfer->rx_buf;
spi_imx->count = transfer->len;
spi_imx->txfifo = 0;
reinit_completion(&spi_imx->xfer_done);
spi_imx->slave_aborted = false;
spi_imx_push(spi_imx);
spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE | MXC_INT_RDR);
if (wait_for_completion_interruptible(&spi_imx->xfer_done) ||
spi_imx->slave_aborted) {
dev_dbg(&spi->dev, "interrupted\n");
ret = -EINTR;
}
/* ecspi has a HW issue when works in Slave mode,
* after 64 words writtern to TXFIFO, even TXFIFO becomes empty,
* ECSPI_TXDATA keeps shift out the last word data,
* so we have to disable ECSPI when in slave mode after the
* transfer completes
*/
if (spi_imx->devtype_data->disable)
spi_imx->devtype_data->disable(spi_imx);
return ret;
}
static int spi_imx_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
/* flush rxfifo before transfer */
while (spi_imx->devtype_data->rx_available(spi_imx))
spi_imx->rx(spi_imx);
if (spi_imx->slave_mode)
return spi_imx_pio_transfer_slave(spi, transfer);
if (spi_imx->usedma)
return spi_imx_dma_transfer(spi_imx, transfer);
else
@ -1323,6 +1464,16 @@ spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg)
return 0;
}
static int spi_imx_slave_abort(struct spi_master *master)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
spi_imx->slave_aborted = true;
complete(&spi_imx->xfer_done);
return 0;
}
static int spi_imx_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@ -1334,13 +1485,23 @@ static int spi_imx_probe(struct platform_device *pdev)
struct spi_imx_data *spi_imx;
struct resource *res;
int i, ret, irq, spi_drctl;
const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data :
(struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
bool slave_mode;
if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
return -EINVAL;
}
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
slave_mode = devtype_data->has_slavemode &&
of_property_read_bool(np, "spi-slave");
if (slave_mode)
master = spi_alloc_slave(&pdev->dev,
sizeof(struct spi_imx_data));
else
master = spi_alloc_master(&pdev->dev,
sizeof(struct spi_imx_data));
if (!master)
return -ENOMEM;
@ -1358,12 +1519,14 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = master;
spi_imx->dev = &pdev->dev;
spi_imx->slave_mode = slave_mode;
spi_imx->devtype_data = of_id ? of_id->data :
(struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
spi_imx->devtype_data = devtype_data;
/* Get number of chip selects, either platform data or OF */
if (mxc_platform_info) {
master->num_chipselect = mxc_platform_info->num_chipselect;
if (mxc_platform_info->chipselect) {
master->cs_gpios = devm_kzalloc(&master->dev,
sizeof(int) * master->num_chipselect, GFP_KERNEL);
if (!master->cs_gpios)
@ -1372,6 +1535,13 @@ static int spi_imx_probe(struct platform_device *pdev)
for (i = 0; i < master->num_chipselect; i++)
master->cs_gpios[i] = mxc_platform_info->chipselect[i];
}
} else {
u32 num_cs;
if (!of_property_read_u32(np, "num-cs", &num_cs))
master->num_chipselect = num_cs;
/* If not preset, default value of 1 is used */
}
spi_imx->bitbang.chipselect = spi_imx_chipselect;
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
@ -1380,6 +1550,7 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
spi_imx->bitbang.master->slave_abort = spi_imx_slave_abort;
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
| SPI_NO_CS;
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
@ -1451,30 +1622,29 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->devtype_data->intctrl(spi_imx, 0);
master->dev.of_node = pdev->dev.of_node;
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
goto out_clk_put;
}
if (!master->cs_gpios) {
dev_err(&pdev->dev, "No CS GPIOs available\n");
ret = -EINVAL;
goto out_clk_put;
}
/* Request GPIO CS lines, if any */
if (!spi_imx->slave_mode && master->cs_gpios) {
for (i = 0; i < master->num_chipselect; i++) {
if (!gpio_is_valid(master->cs_gpios[i]))
continue;
ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
ret = devm_gpio_request(&pdev->dev,
master->cs_gpios[i],
DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev, "Can't get CS GPIO %i\n",
master->cs_gpios[i]);
goto out_clk_put;
goto out_spi_bitbang;
}
}
}
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
goto out_clk_put;
}
dev_info(&pdev->dev, "probed\n");
@ -1482,6 +1652,8 @@ static int spi_imx_probe(struct platform_device *pdev)
clk_disable(spi_imx->clk_per);
return ret;
out_spi_bitbang:
spi_bitbang_stop(&spi_imx->bitbang);
out_clk_put:
clk_disable_unprepare(spi_imx->clk_ipg);
out_put_per:

View file

@ -44,6 +44,7 @@
#include <linux/completion.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
#include <linux/stmp_device.h>
#include <linux/spi/spi.h>
@ -442,6 +443,85 @@ static int mxs_spi_transfer_one(struct spi_master *master,
return status;
}
static int mxs_spi_runtime_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mxs_spi *spi = spi_master_get_devdata(master);
struct mxs_ssp *ssp = &spi->ssp;
int ret;
clk_disable_unprepare(ssp->clk);
ret = pinctrl_pm_select_idle_state(dev);
if (ret) {
int ret2 = clk_prepare_enable(ssp->clk);
if (ret2)
dev_warn(dev, "Failed to reenable clock after failing pinctrl request (pinctrl: %d, clk: %d)\n",
ret, ret2);
}
return ret;
}
static int mxs_spi_runtime_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mxs_spi *spi = spi_master_get_devdata(master);
struct mxs_ssp *ssp = &spi->ssp;
int ret;
ret = pinctrl_pm_select_default_state(dev);
if (ret)
return ret;
ret = clk_prepare_enable(ssp->clk);
if (ret)
pinctrl_pm_select_idle_state(dev);
return ret;
}
static int __maybe_unused mxs_spi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
int ret;
ret = spi_master_suspend(master);
if (ret)
return ret;
if (!pm_runtime_suspended(dev))
return mxs_spi_runtime_suspend(dev);
else
return 0;
}
static int __maybe_unused mxs_spi_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
int ret;
if (!pm_runtime_suspended(dev))
ret = mxs_spi_runtime_resume(dev);
else
ret = 0;
if (ret)
return ret;
ret = spi_master_resume(master);
if (ret < 0 && !pm_runtime_suspended(dev))
mxs_spi_runtime_suspend(dev);
return ret;
}
static const struct dev_pm_ops mxs_spi_pm = {
SET_RUNTIME_PM_OPS(mxs_spi_runtime_suspend,
mxs_spi_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(mxs_spi_suspend, mxs_spi_resume)
};
static const struct of_device_id mxs_spi_dt_ids[] = {
{ .compatible = "fsl,imx23-spi", .data = (void *) IMX23_SSP, },
{ .compatible = "fsl,imx28-spi", .data = (void *) IMX28_SSP, },
@ -493,12 +573,15 @@ static int mxs_spi_probe(struct platform_device *pdev)
if (!master)
return -ENOMEM;
platform_set_drvdata(pdev, master);
master->transfer_one_message = mxs_spi_transfer_one;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->num_chipselect = 3;
master->dev.of_node = np;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->auto_runtime_pm = true;
spi = spi_master_get_devdata(master);
ssp = &spi->ssp;
@ -521,28 +604,41 @@ static int mxs_spi_probe(struct platform_device *pdev)
goto out_master_free;
}
ret = clk_prepare_enable(ssp->clk);
if (ret)
pm_runtime_enable(ssp->dev);
if (!pm_runtime_enabled(ssp->dev)) {
ret = mxs_spi_runtime_resume(ssp->dev);
if (ret < 0) {
dev_err(ssp->dev, "runtime resume failed\n");
goto out_dma_release;
}
}
ret = pm_runtime_get_sync(ssp->dev);
if (ret < 0) {
dev_err(ssp->dev, "runtime_get_sync failed\n");
goto out_pm_runtime_disable;
}
clk_set_rate(ssp->clk, clk_freq);
ret = stmp_reset_block(ssp->base);
if (ret)
goto out_disable_clk;
platform_set_drvdata(pdev, master);
goto out_pm_runtime_put;
ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
goto out_disable_clk;
goto out_pm_runtime_put;
}
pm_runtime_put(ssp->dev);
return 0;
out_disable_clk:
clk_disable_unprepare(ssp->clk);
out_pm_runtime_put:
pm_runtime_put(ssp->dev);
out_pm_runtime_disable:
pm_runtime_disable(ssp->dev);
out_dma_release:
dma_release_channel(ssp->dmach);
out_master_free:
@ -560,7 +656,10 @@ static int mxs_spi_remove(struct platform_device *pdev)
spi = spi_master_get_devdata(master);
ssp = &spi->ssp;
clk_disable_unprepare(ssp->clk);
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
mxs_spi_runtime_suspend(&pdev->dev);
dma_release_channel(ssp->dmach);
return 0;
@ -572,6 +671,7 @@ static struct platform_driver mxs_spi_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = mxs_spi_dt_ids,
.pm = &mxs_spi_pm,
},
};

View file

@ -671,7 +671,6 @@ static int orion_spi_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"%pOF has no valid 'reg' property (%d)\n",
np, status);
status = 0;
continue;
}

View file

@ -1221,7 +1221,6 @@ static int rspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct rspi_data *rspi;
int ret;
const struct of_device_id *of_id;
const struct rspi_plat_data *rspi_pd;
const struct spi_ops *ops;
@ -1229,9 +1228,8 @@ static int rspi_probe(struct platform_device *pdev)
if (master == NULL)
return -ENOMEM;
of_id = of_match_device(rspi_of_match, &pdev->dev);
if (of_id) {
ops = of_id->data;
ops = of_device_get_match_data(&pdev->dev);
if (ops) {
ret = rspi_parse_dt(&pdev->dev, master);
if (ret)
goto error1;

View file

@ -752,7 +752,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
{
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci;
int err;
sdd = spi_master_get_devdata(spi->master);
@ -788,8 +787,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
spi_set_ctldata(spi, cs);
}
sci = sdd->cntrlr_info;
pm_runtime_get_sync(&sdd->pdev->dev);
/* Check if we can provide the requested rate */

View file

@ -900,7 +900,7 @@ static int sh_msiof_transfer_one(struct spi_master *master,
break;
copy32 = copy_bswap32;
} else if (bits <= 16) {
if (l & 1)
if (l & 3)
break;
copy32 = copy_wswap32;
} else {
@ -1021,6 +1021,8 @@ static const struct sh_msiof_chipdata rcar_gen3_data = {
static const struct of_device_id sh_msiof_match[] = {
{ .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
{ .compatible = "renesas,msiof-r8a7743", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7745", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7790", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7791", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7792", .data = &rcar_gen2_data },
@ -1188,12 +1190,10 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
static void sh_msiof_release_dma(struct sh_msiof_spi_priv *p)
{
struct spi_master *master = p->master;
struct device *dev;
if (!master->dma_tx)
return;
dev = &p->pdev->dev;
dma_unmap_single(master->dma_rx->device->dev, p->rx_dma_addr,
PAGE_SIZE, DMA_FROM_DEVICE);
dma_unmap_single(master->dma_tx->device->dev, p->tx_dma_addr,
@ -1209,15 +1209,13 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
struct resource *r;
struct spi_master *master;
const struct sh_msiof_chipdata *chipdata;
const struct of_device_id *of_id;
struct sh_msiof_spi_info *info;
struct sh_msiof_spi_priv *p;
int i;
int ret;
of_id = of_match_device(sh_msiof_match, &pdev->dev);
if (of_id) {
chipdata = of_id->data;
chipdata = of_device_get_match_data(&pdev->dev);
if (chipdata) {
info = sh_msiof_spi_parse_dt(&pdev->dev);
} else {
chipdata = (const void *)pdev->id_entry->driver_data;

418
drivers/spi/spi-sprd-adi.c Normal file
View file

@ -0,0 +1,418 @@
/*
* Copyright (C) 2017 Spreadtrum Communications Inc.
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <linux/hwspinlock.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/sizes.h>
/* Registers definitions for ADI controller */
#define REG_ADI_CTRL0 0x4
#define REG_ADI_CHN_PRIL 0x8
#define REG_ADI_CHN_PRIH 0xc
#define REG_ADI_INT_EN 0x10
#define REG_ADI_INT_RAW 0x14
#define REG_ADI_INT_MASK 0x18
#define REG_ADI_INT_CLR 0x1c
#define REG_ADI_GSSI_CFG0 0x20
#define REG_ADI_GSSI_CFG1 0x24
#define REG_ADI_RD_CMD 0x28
#define REG_ADI_RD_DATA 0x2c
#define REG_ADI_ARM_FIFO_STS 0x30
#define REG_ADI_STS 0x34
#define REG_ADI_EVT_FIFO_STS 0x38
#define REG_ADI_ARM_CMD_STS 0x3c
#define REG_ADI_CHN_EN 0x40
#define REG_ADI_CHN_ADDR(id) (0x44 + (id - 2) * 4)
#define REG_ADI_CHN_EN1 0x20c
/* Bits definitions for register REG_ADI_GSSI_CFG0 */
#define BIT_CLK_ALL_ON BIT(30)
/* Bits definitions for register REG_ADI_RD_DATA */
#define BIT_RD_CMD_BUSY BIT(31)
#define RD_ADDR_SHIFT 16
#define RD_VALUE_MASK GENMASK(15, 0)
#define RD_ADDR_MASK GENMASK(30, 16)
/* Bits definitions for register REG_ADI_ARM_FIFO_STS */
#define BIT_FIFO_FULL BIT(11)
#define BIT_FIFO_EMPTY BIT(10)
/*
* ADI slave devices include RTC, ADC, regulator, charger, thermal and so on.
* The slave devices address offset is always 0x8000 and size is 4K.
*/
#define ADI_SLAVE_ADDR_SIZE SZ_4K
#define ADI_SLAVE_OFFSET 0x8000
/* Timeout (ms) for the trylock of hardware spinlocks */
#define ADI_HWSPINLOCK_TIMEOUT 5000
/*
* ADI controller has 50 channels including 2 software channels
* and 48 hardware channels.
*/
#define ADI_HW_CHNS 50
#define ADI_FIFO_DRAIN_TIMEOUT 1000
#define ADI_READ_TIMEOUT 2000
#define REG_ADDR_LOW_MASK GENMASK(11, 0)
struct sprd_adi {
struct spi_controller *ctlr;
struct device *dev;
void __iomem *base;
struct hwspinlock *hwlock;
unsigned long slave_vbase;
unsigned long slave_pbase;
};
static int sprd_adi_check_paddr(struct sprd_adi *sadi, u32 paddr)
{
if (paddr < sadi->slave_pbase || paddr >
(sadi->slave_pbase + ADI_SLAVE_ADDR_SIZE)) {
dev_err(sadi->dev,
"slave physical address is incorrect, addr = 0x%x\n",
paddr);
return -EINVAL;
}
return 0;
}
static unsigned long sprd_adi_to_vaddr(struct sprd_adi *sadi, u32 paddr)
{
return (paddr - sadi->slave_pbase + sadi->slave_vbase);
}
static int sprd_adi_drain_fifo(struct sprd_adi *sadi)
{
u32 timeout = ADI_FIFO_DRAIN_TIMEOUT;
u32 sts;
do {
sts = readl_relaxed(sadi->base + REG_ADI_ARM_FIFO_STS);
if (sts & BIT_FIFO_EMPTY)
break;
cpu_relax();
} while (--timeout);
if (timeout == 0) {
dev_err(sadi->dev, "drain write fifo timeout\n");
return -EBUSY;
}
return 0;
}
static int sprd_adi_fifo_is_full(struct sprd_adi *sadi)
{
return readl_relaxed(sadi->base + REG_ADI_ARM_FIFO_STS) & BIT_FIFO_FULL;
}
static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val)
{
int read_timeout = ADI_READ_TIMEOUT;
u32 val, rd_addr;
/*
* Set the physical register address need to read into RD_CMD register,
* then ADI controller will start to transfer automatically.
*/
writel_relaxed(reg_paddr, sadi->base + REG_ADI_RD_CMD);
/*
* Wait read operation complete, the BIT_RD_CMD_BUSY will be set
* simultaneously when writing read command to register, and the
* BIT_RD_CMD_BUSY will be cleared after the read operation is
* completed.
*/
do {
val = readl_relaxed(sadi->base + REG_ADI_RD_DATA);
if (!(val & BIT_RD_CMD_BUSY))
break;
cpu_relax();
} while (--read_timeout);
if (read_timeout == 0) {
dev_err(sadi->dev, "ADI read timeout\n");
return -EBUSY;
}
/*
* The return value includes data and read register address, from bit 0
* to bit 15 are data, and from bit 16 to bit 30 are read register
* address. Then we can check the returned register address to validate
* data.
*/
rd_addr = (val & RD_ADDR_MASK ) >> RD_ADDR_SHIFT;
if (rd_addr != (reg_paddr & REG_ADDR_LOW_MASK)) {
dev_err(sadi->dev, "read error, reg addr = 0x%x, val = 0x%x\n",
reg_paddr, val);
return -EIO;
}
*read_val = val & RD_VALUE_MASK;
return 0;
}
static int sprd_adi_write(struct sprd_adi *sadi, unsigned long reg, u32 val)
{
u32 timeout = ADI_FIFO_DRAIN_TIMEOUT;
int ret;
ret = sprd_adi_drain_fifo(sadi);
if (ret < 0)
return ret;
/*
* we should wait for write fifo is empty before writing data to PMIC
* registers.
*/
do {
if (!sprd_adi_fifo_is_full(sadi)) {
writel_relaxed(val, (void __iomem *)reg);
break;
}
cpu_relax();
} while (--timeout);
if (timeout == 0) {
dev_err(sadi->dev, "write fifo is full\n");
return -EBUSY;
}
return 0;
}
static int sprd_adi_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi_dev,
struct spi_transfer *t)
{
struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
unsigned long flags, virt_reg;
u32 phy_reg, val;
int ret;
if (t->rx_buf) {
phy_reg = *(u32 *)t->rx_buf + sadi->slave_pbase;
ret = sprd_adi_check_paddr(sadi, phy_reg);
if (ret)
return ret;
ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
ADI_HWSPINLOCK_TIMEOUT,
&flags);
if (ret) {
dev_err(sadi->dev, "get the hw lock failed\n");
return ret;
}
ret = sprd_adi_read(sadi, phy_reg, &val);
hwspin_unlock_irqrestore(sadi->hwlock, &flags);
if (ret)
return ret;
*(u32 *)t->rx_buf = val;
} else if (t->tx_buf) {
u32 *p = (u32 *)t->tx_buf;
/*
* Get the physical register address need to write and convert
* the physical address to virtual address. Since we need
* virtual register address to write.
*/
phy_reg = *p++ + sadi->slave_pbase;
ret = sprd_adi_check_paddr(sadi, phy_reg);
if (ret)
return ret;
virt_reg = sprd_adi_to_vaddr(sadi, phy_reg);
val = *p;
ret = hwspin_lock_timeout_irqsave(sadi->hwlock,
ADI_HWSPINLOCK_TIMEOUT,
&flags);
if (ret) {
dev_err(sadi->dev, "get the hw lock failed\n");
return ret;
}
ret = sprd_adi_write(sadi, virt_reg, val);
hwspin_unlock_irqrestore(sadi->hwlock, &flags);
if (ret)
return ret;
} else {
dev_err(sadi->dev, "no buffer for transfer\n");
return -EINVAL;
}
return 0;
}
static void sprd_adi_hw_init(struct sprd_adi *sadi)
{
struct device_node *np = sadi->dev->of_node;
int i, size, chn_cnt;
const __be32 *list;
u32 tmp;
/* Address bits select default 12 bits */
writel_relaxed(0, sadi->base + REG_ADI_CTRL0);
/* Set all channels as default priority */
writel_relaxed(0, sadi->base + REG_ADI_CHN_PRIL);
writel_relaxed(0, sadi->base + REG_ADI_CHN_PRIH);
/* Set clock auto gate mode */
tmp = readl_relaxed(sadi->base + REG_ADI_GSSI_CFG0);
tmp &= ~BIT_CLK_ALL_ON;
writel_relaxed(tmp, sadi->base + REG_ADI_GSSI_CFG0);
/* Set hardware channels setting */
list = of_get_property(np, "sprd,hw-channels", &size);
if (!list || !size) {
dev_info(sadi->dev, "no hw channels setting in node\n");
return;
}
chn_cnt = size / 8;
for (i = 0; i < chn_cnt; i++) {
u32 value;
u32 chn_id = be32_to_cpu(*list++);
u32 chn_config = be32_to_cpu(*list++);
/* Channel 0 and 1 are software channels */
if (chn_id < 2)
continue;
writel_relaxed(chn_config, sadi->base +
REG_ADI_CHN_ADDR(chn_id));
if (chn_id < 32) {
value = readl_relaxed(sadi->base + REG_ADI_CHN_EN);
value |= BIT(chn_id);
writel_relaxed(value, sadi->base + REG_ADI_CHN_EN);
} else if (chn_id < ADI_HW_CHNS) {
value = readl_relaxed(sadi->base + REG_ADI_CHN_EN1);
value |= BIT(chn_id - 32);
writel_relaxed(value, sadi->base + REG_ADI_CHN_EN1);
}
}
}
static int sprd_adi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct spi_controller *ctlr;
struct sprd_adi *sadi;
struct resource *res;
u32 num_chipselect;
int ret;
if (!np) {
dev_err(&pdev->dev, "can not find the adi bus node\n");
return -ENODEV;
}
pdev->id = of_alias_get_id(np, "spi");
num_chipselect = of_get_child_count(np);
ctlr = spi_alloc_master(&pdev->dev, sizeof(struct sprd_adi));
if (!ctlr)
return -ENOMEM;
dev_set_drvdata(&pdev->dev, ctlr);
sadi = spi_controller_get_devdata(ctlr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sadi->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(sadi->base)) {
ret = PTR_ERR(sadi->base);
goto put_ctlr;
}
sadi->slave_vbase = (unsigned long)sadi->base + ADI_SLAVE_OFFSET;
sadi->slave_pbase = res->start + ADI_SLAVE_OFFSET;
sadi->ctlr = ctlr;
sadi->dev = &pdev->dev;
ret = of_hwspin_lock_get_id(np, 0);
if (ret < 0) {
dev_err(&pdev->dev, "can not get the hardware spinlock\n");
goto put_ctlr;
}
sadi->hwlock = hwspin_lock_request_specific(ret);
if (!sadi->hwlock) {
ret = -ENXIO;
goto put_ctlr;
}
sprd_adi_hw_init(sadi);
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->bus_num = pdev->id;
ctlr->num_chipselect = num_chipselect;
ctlr->flags = SPI_MASTER_HALF_DUPLEX;
ctlr->bits_per_word_mask = 0;
ctlr->transfer_one = sprd_adi_transfer_one;
ret = devm_spi_register_controller(&pdev->dev, ctlr);
if (ret) {
dev_err(&pdev->dev, "failed to register SPI controller\n");
goto free_hwlock;
}
return 0;
free_hwlock:
hwspin_lock_free(sadi->hwlock);
put_ctlr:
spi_controller_put(ctlr);
return ret;
}
static int sprd_adi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
hwspin_lock_free(sadi->hwlock);
return 0;
}
static const struct of_device_id sprd_adi_of_match[] = {
{
.compatible = "sprd,sc9860-adi",
},
{ },
};
MODULE_DEVICE_TABLE(of, sprd_adi_of_match);
static struct platform_driver sprd_adi_driver = {
.driver = {
.name = "sprd-adi",
.of_match_table = sprd_adi_of_match,
},
.probe = sprd_adi_probe,
.remove = sprd_adi_remove,
};
module_platform_driver(sprd_adi_driver);
MODULE_DESCRIPTION("Spreadtrum ADI Controller Driver");
MODULE_AUTHOR("Baolin Wang <Baolin.Wang@spreadtrum.com>");
MODULE_LICENSE("GPL v2");

View file

@ -50,7 +50,7 @@
#define SPI_IDLE_SDA_PULL_LOW (2 << 18)
#define SPI_IDLE_SDA_PULL_HIGH (3 << 18)
#define SPI_IDLE_SDA_MASK (3 << 18)
#define SPI_CS_SS_VAL (1 << 20)
#define SPI_CS_SW_VAL (1 << 20)
#define SPI_CS_SW_HW (1 << 21)
/* SPI_CS_POL_INACTIVE bits are default high */
/* n from 0 to 3 */
@ -705,9 +705,9 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
command1 |= SPI_CS_SW_HW;
if (spi->mode & SPI_CS_HIGH)
command1 |= SPI_CS_SS_VAL;
command1 |= SPI_CS_SW_VAL;
else
command1 &= ~SPI_CS_SS_VAL;
command1 &= ~SPI_CS_SW_VAL;
tegra_spi_writel(tspi, 0, SPI_COMMAND2);
} else {

View file

@ -2200,7 +2200,7 @@ static void devm_spi_unregister(struct device *dev, void *res)
* Context: can sleep
*
* Register a SPI device as with spi_register_controller() which will
* automatically be unregister
* automatically be unregistered and freed.
*
* Return: zero on success, else a negative error code.
*/
@ -2241,15 +2241,18 @@ static int __unregister(struct device *dev, void *null)
* only ones directly touching chip registers.
*
* This must be called from context that can sleep.
*
* Note that this function also drops a reference to the controller.
*/
void spi_unregister_controller(struct spi_controller *ctlr)
{
struct spi_controller *found;
int id = ctlr->bus_num;
int dummy;
/* First make sure that this controller was ever added */
mutex_lock(&board_lock);
found = idr_find(&spi_master_idr, ctlr->bus_num);
found = idr_find(&spi_master_idr, id);
mutex_unlock(&board_lock);
if (found != ctlr) {
dev_dbg(&ctlr->dev,
@ -2269,7 +2272,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
device_unregister(&ctlr->dev);
/* free bus id */
mutex_lock(&board_lock);
idr_remove(&spi_master_idr, ctlr->bus_num);
idr_remove(&spi_master_idr, id);
mutex_unlock(&board_lock);
}
EXPORT_SYMBOL_GPL(spi_unregister_controller);

View file

@ -0,0 +1,31 @@
/*
* Freescale DSPI controller driver
*
* Copyright (c) 2017 Angelo Dureghello <angelo@sysam.it>
*
* 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.
*/
#ifndef SPI_FSL_DSPI_HEADER_H
#define SPI_FSL_DSPI_HEADER_H
/**
* struct fsl_dspi_platform_data - platform data for the Freescale DSPI driver
* @bus_num: board specific identifier for this DSPI driver.
* @cs_num: number of chip selects supported by this DSPI driver.
*/
struct fsl_dspi_platform_data {
u32 cs_num;
u32 bus_num;
u32 sck_cs_delay;
u32 cs_sck_delay;
};
#endif /* SPI_FSL_DSPI_HEADER_H */