Commit e5aeced6 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull spi updates from Mark Brown:
 "A few core tweaks this time together with the usual collection of
  driver specific updates and fixes plus a larger than average selection
  of new device support:

   - fix DMA mapping of unaligned vmalloc() buffers

   - statistics tracking transfer volumes exposed via sysfs

   - new drivers for Freescale MPC5125, Intel Sunrise Point, Mediatek
     SoCs, and Netlogic XLP SoCs"

* tag 'spi-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (66 commits)
  spi: sh-msiof: Fix FIFO size to 64 word from 256 word
  spi: fsl-(e)spi: Fix checking return value of devm_ioremap_resource
  spi: Add DT bindings documentation for Netlogic XLP SPI controller
  spi/xlp: SPI controller driver for Netlogic XLP SoCs
  spi: fsl-espi: add runtime PM
  spi: fsl-(e)spi: simplify cleanup code
  spi: fsl-(e)spi: migrate to using devm_ functions to simplify cleanup
  spi: mediatek: fix SPI_CMD_PAUSE_IE macro error
  spi: check bits_per_word in spi_setup
  spi: mediatek: replace *_time name
  spi: mediatek: add PM clk_prepare_enable fail flow
  spi: mediatek: replace int with u32, delete TAB and define MTK_SPI_PAUSE_INT_STATUS marco
  spi: mediatek: add linux/io.h include file
  spi/bcm63xx-hsspi: add support for dual spi read/write
  spi: dw: Allow interface drivers to limit data I/O to word sizes
  dt: snps,dw-apb-ssi: Document new I/O data register width property
  spi: Fall back to master maximum speed if no slave speed specified
  spi: mediatek: use BIT() to instead of SPI_CMD_*_OFFSET
  spi: medaitek: revise quirks compatibility style
  spi: mediatek: fix spi incorrect endian usage
  ...
parents cf9d615f c5992f61
...@@ -6,14 +6,14 @@ PSC in UART mode ...@@ -6,14 +6,14 @@ PSC in UART mode
For PSC in UART mode the needed PSC serial devices For PSC in UART mode the needed PSC serial devices
are specified by fsl,mpc5121-psc-uart nodes in the are specified by fsl,mpc5121-psc-uart nodes in the
fsl,mpc5121-immr SoC node. Additionally the PSC FIFO fsl,mpc5121-immr SoC node. Additionally the PSC FIFO
Controller node fsl,mpc5121-psc-fifo is requered there: Controller node fsl,mpc5121-psc-fifo is required there:
fsl,mpc5121-psc-uart nodes fsl,mpc512x-psc-uart nodes
-------------------------- --------------------------
Required properties : Required properties :
- compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc" - compatible : Should contain "fsl,<soc>-psc-uart" and "fsl,<soc>-psc"
- cell-index : Index of the PSC in hardware Supported <soc>s: mpc5121, mpc5125
- reg : Offset and length of the register set for the PSC device - reg : Offset and length of the register set for the PSC device
- interrupts : <a b> where a is the interrupt number of the - interrupts : <a b> where a is the interrupt number of the
PSC FIFO Controller and b is a field that represents an PSC FIFO Controller and b is a field that represents an
...@@ -25,12 +25,21 @@ Recommended properties : ...@@ -25,12 +25,21 @@ Recommended properties :
- fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4) - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4)
- fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4) - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4)
PSC in SPI mode
---------------
fsl,mpc5121-psc-fifo node Similar to the UART mode a PSC can be operated in SPI mode. The compatible used
for that is fsl,mpc5121-psc-spi. It requires a fsl,mpc5121-psc-fifo as well.
The required and recommended properties are identical to the
fsl,mpc5121-psc-uart nodes, just use spi instead of uart in the compatible
string.
fsl,mpc512x-psc-fifo node
------------------------- -------------------------
Required properties : Required properties :
- compatible : Should be "fsl,mpc5121-psc-fifo" - compatible : Should be "fsl,<soc>-psc-fifo"
Supported <soc>s: mpc5121, mpc5125
- reg : Offset and length of the register set for the PSC - reg : Offset and length of the register set for the PSC
FIFO Controller FIFO Controller
- interrupts : <a b> where a is the interrupt number of the - interrupts : <a b> where a is the interrupt number of the
...@@ -39,6 +48,9 @@ Required properties : ...@@ -39,6 +48,9 @@ Required properties :
- interrupt-parent : the phandle for the interrupt controller that - interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device. services interrupts for this device.
Recommended properties :
- clocks : specifies the clock needed to operate the fifo controller
- clock-names : name(s) for the clock(s) listed in clocks
Example for a board using PSC0 and PSC1 devices in serial mode: Example for a board using PSC0 and PSC1 devices in serial mode:
......
...@@ -10,6 +10,8 @@ Required properties: ...@@ -10,6 +10,8 @@ Required properties:
Optional properties: Optional properties:
- cs-gpios : Specifies the gpio pis to be used for chipselects. - cs-gpios : Specifies the gpio pis to be used for chipselects.
- num-cs : The number of chipselects. If omitted, this will default to 4. - num-cs : The number of chipselects. If omitted, this will default to 4.
- reg-io-width : The I/O register width (in bytes) implemented by this
device. Supported values are 2 or 4 (the default).
Child nodes as per the generic SPI binding. Child nodes as per the generic SPI binding.
......
...@@ -12,6 +12,8 @@ Required properties: ...@@ -12,6 +12,8 @@ Required properties:
- compatible: - compatible:
- "ti,dm6441-spi" for SPI used similar to that on DM644x SoC family - "ti,dm6441-spi" for SPI used similar to that on DM644x SoC family
- "ti,da830-spi" for SPI used similar to that on DA8xx SoC family - "ti,da830-spi" for SPI used similar to that on DA8xx SoC family
- "ti,keystone-spi" for SPI used similar to that on Keystone2 SoC
family
- reg: Offset and length of SPI controller register space - reg: Offset and length of SPI controller register space
- num-cs: Number of chip selects. This includes internal as well as - num-cs: Number of chip selects. This includes internal as well as
GPIO chip selects. GPIO chip selects.
......
...@@ -21,6 +21,7 @@ Required properties: ...@@ -21,6 +21,7 @@ Required properties:
Optional properties: Optional properties:
- img,supports-quad-mode: Should be set if the interface supports quad mode - img,supports-quad-mode: Should be set if the interface supports quad mode
SPI transfers. SPI transfers.
- spfi-max-frequency: Maximum speed supported by the spfi block.
Example: Example:
......
Binding for MTK SPI controller
Required properties:
- compatible: should be one of the following.
- mediatek,mt8173-spi: for mt8173 platforms
- mediatek,mt8135-spi: for mt8135 platforms
- mediatek,mt6589-spi: for mt6589 platforms
- #address-cells: should be 1.
- #size-cells: should be 0.
- reg: Address and length of the register set for the device
- interrupts: Should contain spi interrupt
- clocks: phandles to input clocks.
The first should be <&topckgen CLK_TOP_SPI_SEL>.
The second should be one of the following.
- <&clk26m>: specify parent clock 26MHZ.
- <&topckgen CLK_TOP_SYSPLL3_D2>: specify parent clock 109MHZ.
It's the default one.
- <&topckgen CLK_TOP_SYSPLL4_D2>: specify parent clock 78MHZ.
- <&topckgen CLK_TOP_UNIVPLL2_D4>: specify parent clock 104MHZ.
- <&topckgen CLK_TOP_UNIVPLL1_D8>: specify parent clock 78MHZ.
- clock-names: shall be "spi-clk" for the controller clock, and
"parent-clk" for the parent clock.
Optional properties:
- mediatek,pad-select: specify which pins group(ck/mi/mo/cs) spi
controller used, this value should be 0~3, only required for MT8173.
0: specify GPIO69,70,71,72 for spi pins.
1: specify GPIO102,103,104,105 for spi pins.
2: specify GPIO128,129,130,131 for spi pins.
3: specify GPIO5,6,7,8 for spi pins.
Example:
- SoC Specific Portion:
spi: spi@1100a000 {
compatible = "mediatek,mt8173-spi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0 0x1100a000 0 0x1000>;
interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>;
clocks = <&topckgen CLK_TOP_SPI_SEL>, <&topckgen CLK_TOP_SYSPLL3_D2>;
clock-names = "spi-clk", "parent-clk";
mediatek,pad-select = <0>;
status = "disabled";
};
SPI Master controller for Netlogic XLP MIPS64 SOCs
==================================================
Currently this SPI controller driver is supported for the following
Netlogic XLP SoCs:
XLP832, XLP316, XLP208, XLP980, XLP532
Required properties:
- compatible : Should be "netlogic,xlp832-spi".
- #address-cells : Number of cells required to define a chip select address
on the SPI bus.
- #size-cells : Should be zero.
- reg : Should contain register location and length.
- clocks : Phandle of the spi clock
- interrupts : Interrupt number used by this controller.
- interrupt-parent : Phandle of the parent interrupt controller.
SPI slave nodes must be children of the SPI master node and can contain
properties described in Documentation/devicetree/bindings/spi/spi-bus.txt.
Example:
spi: xlp_spi@3a100 {
compatible = "netlogic,xlp832-spi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0 0x3a100 0x100>;
clocks = <&spi_clk>;
interrupts = <34>;
interrupt-parent = <&pic>;
spi_nor@1 {
compatible = "spansion,s25sl12801";
#address-cells = <1>;
#size-cells = <1>;
reg = <1>; /* Chip Select */
spi-max-frequency = <40000000>;
};
};
...@@ -1010,11 +1010,13 @@ static struct davinci_spi_platform_data da8xx_spi_pdata[] = { ...@@ -1010,11 +1010,13 @@ static struct davinci_spi_platform_data da8xx_spi_pdata[] = {
.version = SPI_VERSION_2, .version = SPI_VERSION_2,
.intr_line = 1, .intr_line = 1,
.dma_event_q = EVENTQ_0, .dma_event_q = EVENTQ_0,
.prescaler_limit = 2,
}, },
[1] = { [1] = {
.version = SPI_VERSION_2, .version = SPI_VERSION_2,
.intr_line = 1, .intr_line = 1,
.dma_event_q = EVENTQ_0, .dma_event_q = EVENTQ_0,
.prescaler_limit = 2,
}, },
}; };
......
...@@ -411,6 +411,7 @@ static struct davinci_spi_platform_data dm355_spi0_pdata = { ...@@ -411,6 +411,7 @@ static struct davinci_spi_platform_data dm355_spi0_pdata = {
.num_chipselect = 2, .num_chipselect = 2,
.cshold_bug = true, .cshold_bug = true,
.dma_event_q = EVENTQ_1, .dma_event_q = EVENTQ_1,
.prescaler_limit = 1,
}; };
static struct platform_device dm355_spi0_device = { static struct platform_device dm355_spi0_device = {
.name = "spi_davinci", .name = "spi_davinci",
......
...@@ -646,6 +646,7 @@ static struct davinci_spi_platform_data dm365_spi0_pdata = { ...@@ -646,6 +646,7 @@ static struct davinci_spi_platform_data dm365_spi0_pdata = {
.version = SPI_VERSION_1, .version = SPI_VERSION_1,
.num_chipselect = 2, .num_chipselect = 2,
.dma_event_q = EVENTQ_3, .dma_event_q = EVENTQ_3,
.prescaler_limit = 1,
}; };
static struct resource dm365_spi0_resources[] = { static struct resource dm365_spi0_resources[] = {
......
...@@ -150,7 +150,10 @@ ...@@ -150,7 +150,10 @@
/* Structure of the hardware registers */ /* Structure of the hardware registers */
struct mpc52xx_psc { struct mpc52xx_psc {
u8 mode; /* PSC + 0x00 */ union {
u8 mode; /* PSC + 0x00 */
u8 mr2;
};
u8 reserved0[3]; u8 reserved0[3];
union { /* PSC + 0x04 */ union { /* PSC + 0x04 */
u16 status; u16 status;
......
...@@ -326,6 +326,15 @@ config SPI_MESON_SPIFC ...@@ -326,6 +326,15 @@ config SPI_MESON_SPIFC
This enables master mode support for the SPIFC (SPI flash This enables master mode support for the SPIFC (SPI flash
controller) available in Amlogic Meson SoCs. controller) available in Amlogic Meson SoCs.
config SPI_MT65XX
tristate "MediaTek SPI controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
help
This selects the MediaTek(R) SPI bus driver.
If you want to use MediaTek(R) SPI interface,
say Y or M here.If you are not sure, say N.
SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs.
config SPI_OC_TINY config SPI_OC_TINY
tristate "OpenCores tiny SPI" tristate "OpenCores tiny SPI"
depends on GPIOLIB || COMPILE_TEST depends on GPIOLIB || COMPILE_TEST
...@@ -598,6 +607,17 @@ config SPI_XILINX ...@@ -598,6 +607,17 @@ config SPI_XILINX
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
config SPI_XLP
tristate "Netlogic XLP SPI controller driver"
depends on CPU_XLP || COMPILE_TEST
help
Enable support for the SPI controller on the Netlogic XLP SoCs.
Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX
and XLP5XX.
If you have a Netlogic XLP platform say Y here.
If unsure, say N.
config SPI_XTENSA_XTFPGA config SPI_XTENSA_XTFPGA
tristate "Xtensa SPI controller for xtfpga" tristate "Xtensa SPI controller for xtfpga"
depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST
......
...@@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o ...@@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o
obj-$(CONFIG_SPI_MXS) += spi-mxs.o obj-$(CONFIG_SPI_MXS) += spi-mxs.o
obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
...@@ -88,5 +89,6 @@ obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o ...@@ -88,5 +89,6 @@ obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
obj-$(CONFIG_SPI_XLP) += spi-xlp.o
obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/platform_data/atmel.h>
#include <linux/platform_data/dma-atmel.h> #include <linux/platform_data/dma-atmel.h>
#include <linux/of.h> #include <linux/of.h>
......
...@@ -480,7 +480,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, ...@@ -480,7 +480,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *tfr, struct spi_transfer *tfr,
u32 cs, u32 cs,
unsigned long xfer_time_us) unsigned long long xfer_time_us)
{ {
struct bcm2835_spi *bs = spi_master_get_devdata(master); struct bcm2835_spi *bs = spi_master_get_devdata(master);
unsigned long timeout; unsigned long timeout;
...@@ -531,7 +531,8 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, ...@@ -531,7 +531,8 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
{ {
struct bcm2835_spi *bs = spi_master_get_devdata(master); struct bcm2835_spi *bs = spi_master_get_devdata(master);
unsigned long spi_hz, clk_hz, cdiv; unsigned long spi_hz, clk_hz, cdiv;
unsigned long spi_used_hz, xfer_time_us; unsigned long spi_used_hz;
unsigned long long xfer_time_us;
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
/* set clock */ /* set clock */
...@@ -553,13 +554,11 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, ...@@ -553,13 +554,11 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536); spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536);
bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
/* handle all the modes */ /* handle all the 3-wire mode */
if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf)) if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
cs |= BCM2835_SPI_CS_REN; cs |= BCM2835_SPI_CS_REN;
if (spi->mode & SPI_CPOL) else
cs |= BCM2835_SPI_CS_CPOL; cs &= ~BCM2835_SPI_CS_REN;
if (spi->mode & SPI_CPHA)
cs |= BCM2835_SPI_CS_CPHA;
/* for gpio_cs set dummy CS so that no HW-CS get changed /* for gpio_cs set dummy CS so that no HW-CS get changed
* we can not run this in bcm2835_spi_set_cs, as it does * we can not run this in bcm2835_spi_set_cs, as it does
...@@ -575,9 +574,10 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, ...@@ -575,9 +574,10 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
bs->rx_len = tfr->len; bs->rx_len = tfr->len;
/* calculate the estimated time in us the transfer runs */ /* calculate the estimated time in us the transfer runs */
xfer_time_us = tfr->len xfer_time_us = (unsigned long long)tfr->len
* 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */ * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */
* 1000000 / spi_used_hz; * 1000000;
do_div(xfer_time_us, spi_used_hz);
/* for short requests run polling*/ /* for short requests run polling*/
if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US) if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US)
...@@ -592,6 +592,25 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, ...@@ -592,6 +592,25 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs); return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
} }
static int bcm2835_spi_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
struct spi_device *spi = msg->spi;
struct bcm2835_spi *bs = spi_master_get_devdata(master);
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA);
if (spi->mode & SPI_CPOL)
cs |= BCM2835_SPI_CS_CPOL;
if (spi->mode & SPI_CPHA)
cs |= BCM2835_SPI_CS_CPHA;
bcm2835_wr(bs, BCM2835_SPI_CS, cs);
return 0;
}
static void bcm2835_spi_handle_err(struct spi_master *master, static void bcm2835_spi_handle_err(struct spi_master *master,
struct spi_message *msg) struct spi_message *msg)
{ {
...@@ -739,6 +758,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) ...@@ -739,6 +758,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
master->set_cs = bcm2835_spi_set_cs; master->set_cs = bcm2835_spi_set_cs;
master->transfer_one = bcm2835_spi_transfer_one; master->transfer_one = bcm2835_spi_transfer_one;
master->handle_err = bcm2835_spi_handle_err; master->handle_err = bcm2835_spi_handle_err;
master->prepare_message = bcm2835_spi_prepare_message;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
bs = spi_master_get_devdata(master); bs = spi_master_get_devdata(master);
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
#define HSSPI_FIFO_REG(x) (0x200 + (x) * 0x200) #define HSSPI_FIFO_REG(x) (0x200 + (x) * 0x200)
#define HSSPI_OP_MULTIBIT BIT(11)
#define HSSPI_OP_CODE_SHIFT 13 #define HSSPI_OP_CODE_SHIFT 13
#define HSSPI_OP_SLEEP (0 << HSSPI_OP_CODE_SHIFT) #define HSSPI_OP_SLEEP (0 << HSSPI_OP_CODE_SHIFT)
#define HSSPI_OP_READ_WRITE (1 << HSSPI_OP_CODE_SHIFT) #define HSSPI_OP_READ_WRITE (1 << HSSPI_OP_CODE_SHIFT)
...@@ -171,9 +172,12 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t) ...@@ -171,9 +172,12 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
if (opcode != HSSPI_OP_READ) if (opcode != HSSPI_OP_READ)
step_size -= HSSPI_OPCODE_LEN; step_size -= HSSPI_OPCODE_LEN;
__raw_writel(0 << MODE_CTRL_PREPENDBYTE_CNT_SHIFT | if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
2 << MODE_CTRL_MULTIDATA_WR_STRT_SHIFT | (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL))
2 << MODE_CTRL_MULTIDATA_RD_STRT_SHIFT | 0xff, opcode |= HSSPI_OP_MULTIBIT;
__raw_writel(1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT |
1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT | 0xff,
bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select)); bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
while (pending > 0) { while (pending > 0) {
...@@ -374,7 +378,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) ...@@ -374,7 +378,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
master->num_chipselect = 8; master->num_chipselect = 8;
master->setup = bcm63xx_hsspi_setup; master->setup = bcm63xx_hsspi_setup;
master->transfer_one_message = bcm63xx_hsspi_transfer_one; master->transfer_one_message = bcm63xx_hsspi_transfer_one;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
SPI_RX_DUAL | SPI_TX_DUAL;
master->bits_per_word_mask = SPI_BPW_MASK(8); master->bits_per_word_mask = SPI_BPW_MASK(8);
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
......
...@@ -49,7 +49,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi, ...@@ -49,7 +49,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
{ {
/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
bool oldbit = !(word & 1); u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
/* clock starts at inactive polarity */ /* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) { for (word <<= (32 - bits); likely(bits); bits--) {
...@@ -81,7 +81,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi, ...@@ -81,7 +81,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
{ {
/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
bool oldbit = !(word & (1 << 31)); u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
/* clock starts at inactive polarity */ /* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) { for (word <<= (32 - bits); likely(bits); bits--) {
......
...@@ -139,6 +139,8 @@ struct davinci_spi { ...@@ -139,6 +139,8 @@ struct davinci_spi {
u32 (*get_tx)(struct davinci_spi *); u32 (*get_tx)(struct davinci_spi *);
u8 *bytes_per_word; u8 *bytes_per_word;
u8 prescaler_limit;
}; };
static struct davinci_spi_config davinci_spi_default_cfg; static struct davinci_spi_config davinci_spi_default_cfg;
...@@ -255,7 +257,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) ...@@ -255,7 +257,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
* This function calculates the prescale value that generates a clock rate * This function calculates the prescale value that generates a clock rate
* less than or equal to the specified maximum. * less than or equal to the specified maximum.
* *
* Returns: calculated prescale - 1 for easy programming into SPI registers * Returns: calculated prescale value for easy programming into SPI registers
* or negative error number if valid prescalar cannot be updated. * or negative error number if valid prescalar cannot be updated.
*/ */
static inline int davinci_spi_get_prescale(struct davinci_spi *dspi, static inline int davinci_spi_get_prescale(struct davinci_spi *dspi,
...@@ -263,12 +265,13 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi, ...@@ -263,12 +265,13 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi,
{ {
int ret; int ret;
ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz); /* Subtract 1 to match what will be programmed into SPI register. */
ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz) - 1;
if (ret < 1 || ret > 256) if (ret < dspi->prescaler_limit || ret > 255)
return -EINVAL; return -EINVAL;
return ret - 1; return ret;
} }
/** /**
...@@ -832,13 +835,40 @@ static int davinci_spi_request_dma(struct davinci_spi *dspi) ...@@ -832,13 +835,40 @@ static int davinci_spi_request_dma(struct davinci_spi *dspi)
} }
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
/* OF SPI data structure */
struct davinci_spi_of_data {
u8 version;
u8 prescaler_limit;
};
static const struct davinci_spi_of_data dm6441_spi_data = {
.version = SPI_VERSION_1,
.prescaler_limit = 2,
};
static const struct davinci_spi_of_data da830_spi_data = {
.version = SPI_VERSION_2,
.prescaler_limit = 2,
};
static const struct davinci_spi_of_data keystone_spi_data = {
.version = SPI_VERSION_1,
.prescaler_limit = 0,
};
static const struct of_device_id davinci_spi_of_match[] = { static const struct of_device_id davinci_spi_of_match[] = {
{ {
.compatible = "ti,dm6441-spi", .compatible = "ti,dm6441-spi",
.data = &dm6441_spi_data,
}, },
{ {
.compatible = "ti,da830-spi", .compatible = "ti,da830-spi",
.data = (void *)SPI_VERSION_2, .data = &da830_spi_data,
},
{
.compatible = "ti,keystone-spi",
.data = &keystone_spi_data,
}, },
{ }, { },
}; };
...@@ -857,21 +887,21 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, ...@@ -857,21 +887,21 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
struct davinci_spi *dspi) struct davinci_spi *dspi)
{ {
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct davinci_spi_of_data *spi_data;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
unsigned int num_cs, intr_line = 0; unsigned int num_cs, intr_line = 0;
const struct of_device_id *match; const struct of_device_id *match;
pdata = &dspi->pdata; pdata = &dspi->pdata;
pdata->version = SPI_VERSION_1;
match = of_match_device(davinci_spi_of_match, &pdev->dev); match = of_match_device(davinci_spi_of_match, &pdev->dev);
if (!match) if (!match)
return -ENODEV; return -ENODEV;
/* match data has the SPI version number for SPI_VERSION_2 */ spi_data = (struct davinci_spi_of_data *)match->data;
if (match->data == (void *)SPI_VERSION_2)
pdata->version = SPI_VERSION_2;
pdata->version = spi_data->version;
pdata->prescaler_limit = spi_data->prescaler_limit;
/* /*
* default num_cs is 1 and all chipsel are internal to the chip * default num_cs is 1 and all chipsel are internal to the chip
* indicated by chip_sel being NULL or cs_gpios being NULL or * indicated by chip_sel being NULL or cs_gpios being NULL or
...@@ -991,7 +1021,7 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -991,7 +1021,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.chipselect = davinci_spi_chipselect;
dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
dspi->prescaler_limit = pdata->prescaler_limit;
dspi->version = pdata->version; dspi->version = pdata->version;
dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
......
...@@ -74,6 +74,9 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) ...@@ -74,6 +74,9 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
dws->max_freq = clk_get_rate(dwsmmio->clk); dws->max_freq = clk_get_rate(dwsmmio->clk);
of_property_read_u32(pdev->dev.of_node, "reg-io-width",
&dws->reg_io_width);
num_cs = 4; num_cs = 4;
if (pdev->dev.of_node) if (pdev->dev.of_node)
......
...@@ -194,7 +194,7 @@ static void dw_writer(struct dw_spi *dws) ...@@ -194,7 +194,7 @@ static void dw_writer(struct dw_spi *dws)
else else
txw = *(u16 *)(dws->tx); txw = *(u16 *)(dws->tx);
} }
dw_writel(dws, DW_SPI_DR, txw); dw_write_io_reg(dws, DW_SPI_DR, txw);
dws->tx += dws->n_bytes; dws->tx += dws->n_bytes;
} }
} }
...@@ -205,7 +205,7 @@ static void dw_reader(struct dw_spi *dws) ...@@ -205,7 +205,7 @@ static void dw_reader(struct dw_spi *dws)
u16 rxw; u16 rxw;
while (max--) { while (max--) {
rxw = dw_readl(dws, DW_SPI_DR); rxw = dw_read_io_reg(dws, DW_SPI_DR);
/* Care rx only if the transfer's original "rx" is not null */ /* Care rx only if the transfer's original "rx" is not null */
if (dws->rx_end - dws->len) { if (dws->rx_end - dws->len) {
if (dws->n_bytes == 1) if (dws->n_bytes == 1)
......
...@@ -109,6 +109,7 @@ struct dw_spi { ...@@ -109,6 +109,7 @@ struct dw_spi {
u32 fifo_len; /* depth of the FIFO buffer */ u32 fifo_len; /* depth of the FIFO buffer */
u32 max_freq; /* max bus freq supported */ u32 max_freq; /* max bus freq supported */
u32 reg_io_width; /* DR I/O width in bytes */
u16 bus_num; u16 bus_num;
u16 num_cs; /* supported slave numbers */ u16 num_cs; /* supported slave numbers */
...@@ -145,11 +146,45 @@ static inline u32 dw_readl(struct dw_spi *dws, u32 offset) ...@@ -145,11 +146,45 @@ static inline u32 dw_readl(struct dw_spi *dws, u32 offset)
return __raw_readl(dws->regs + offset); return __raw_readl(dws->regs + offset);
} }
static inline u16 dw_readw(struct dw_spi *dws, u32 offset)
{
return __raw_readw(dws->regs + offset);
}
static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val) static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val)
{ {
__raw_writel(val, dws->regs + offset); __raw_writel(val, dws->regs + offset);
} }
static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val)
{
__raw_writew(val, dws->regs + offset);
}
static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset)
{
switch (dws->reg_io_width) {
case 2:
return dw_readw(dws, offset);
case 4:
default:
return dw_readl(dws, offset);
}
}
static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val)
{
switch (dws->reg_io_width) {
case 2:
dw_writew(dws, offset, val);
break;
case 4:
default:
dw_writel(dws, offset, val);
break;
}
}
static inline void spi_enable_chip(struct dw_spi *dws, int enable) static inline void spi_enable_chip(struct dw_spi *dws, int enable)
{ {
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0)); dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/pm_runtime.h>
#include <sysdev/fsl_soc.h> #include <sysdev/fsl_soc.h>
#include "spi-fsl-lib.h" #include "spi-fsl-lib.h"
...@@ -85,6 +86,8 @@ struct fsl_espi_transfer { ...@@ -85,6 +86,8 @@ struct fsl_espi_transfer {
#define SPCOM_TRANLEN(x) ((x) << 0) #define SPCOM_TRANLEN(x) ((x) << 0)
#define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */ #define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */
#define AUTOSUSPEND_TIMEOUT 2000
static void fsl_espi_change_mode(struct spi_device *spi) static void fsl_espi_change_mode(struct spi_device *spi)
{ {
struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
...@@ -485,6 +488,8 @@ static int fsl_espi_setup(struct spi_device *spi) ...@@ -485,6 +488,8 @@ static int fsl_espi_setup(struct spi_device *spi)
mpc8xxx_spi = spi_master_get_devdata(spi->master); mpc8xxx_spi = spi_master_get_devdata(spi->master);
reg_base = mpc8xxx_spi->reg_base; reg_base = mpc8xxx_spi->reg_base;
pm_runtime_get_sync(mpc8xxx_spi->dev);
hw_mode = cs->hw_mode; /* Save original settings */ hw_mode = cs->hw_mode; /* Save original settings */
cs->hw_mode = mpc8xxx_spi_read_reg( cs->hw_mode = mpc8xxx_spi_read_reg(
&reg_base->csmode[spi->chip_select]); &reg_base->csmode[spi->chip_select]);
...@@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi) ...@@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi)
mpc8xxx_spi_write_reg(&reg_base->mode, loop_mode); mpc8xxx_spi_write_reg(&reg_base->mode, loop_mode);
retval = fsl_espi_setup_transfer(spi, NULL); retval = fsl_espi_setup_transfer(spi, NULL);
pm_runtime_mark_last_busy(mpc8xxx_spi->dev);
pm_runtime_put_autosuspend(mpc8xxx_spi->dev);
if (retval < 0) { if (retval < 0) {
cs->hw_mode = hw_mode; /* Restore settings */ cs->hw_mode = hw_mode; /* Restore settings */
return retval; return retval;
...@@ -604,20 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) ...@@ -604,20 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
return ret; return ret;
} }
static void fsl_espi_remove(struct mpc8xxx_spi *mspi) #ifdef CONFIG_PM
static int fsl_espi_runtime_suspend(struct device *dev)
{ {
iounmap(mspi->reg_base); struct spi_master *master = dev_get_drvdata(dev);
} struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
static int fsl_espi_suspend(struct spi_master *master)
{
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_espi_reg *reg_base;
u32 regval; u32 regval;
mpc8xxx_spi = spi_master_get_devdata(master);
reg_base = mpc8xxx_spi->reg_base;
regval = mpc8xxx_spi_read_reg(&reg_base->mode); regval = mpc8xxx_spi_read_reg(&reg_base->mode);
regval &= ~SPMODE_ENABLE; regval &= ~SPMODE_ENABLE;
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
...@@ -625,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master) ...@@ -625,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master)
return 0; return 0;
} }
static int fsl_espi_resume(struct spi_master *master) static int fsl_espi_runtime_resume(struct device *dev)
{ {
struct mpc8xxx_spi *mpc8xxx_spi; struct spi_master *master = dev_get_drvdata(dev);
struct fsl_espi_reg *reg_base; struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
u32 regval; u32 regval;
mpc8xxx_spi = spi_master_get_devdata(master);
reg_base = mpc8xxx_spi->reg_base;
regval = mpc8xxx_spi_read_reg(&reg_base->mode); regval = mpc8xxx_spi_read_reg(&reg_base->mode);
regval |= SPMODE_ENABLE; regval |= SPMODE_ENABLE;
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
return 0; return 0;
} }
#endif
static struct spi_master * fsl_espi_probe(struct device *dev, static struct spi_master * fsl_espi_probe(struct device *dev,
struct resource *mem, unsigned int irq) struct resource *mem, unsigned int irq)
...@@ -667,25 +669,23 @@ static struct spi_master * fsl_espi_probe(struct device *dev, ...@@ -667,25 +669,23 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
master->setup = fsl_espi_setup; master->setup = fsl_espi_setup;
master->cleanup = fsl_espi_cleanup; master->cleanup = fsl_espi_cleanup;
master->transfer_one_message = fsl_espi_do_one_msg; master->transfer_one_message = fsl_espi_do_one_msg;
master->prepare_transfer_hardware = fsl_espi_resume; master->auto_runtime_pm = true;
master->unprepare_transfer_hardware = fsl_espi_suspend;
mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->spi_remove = fsl_espi_remove;
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
if (!mpc8xxx_spi->reg_base) { if (IS_ERR(mpc8xxx_spi->reg_base)) {
ret = -ENOMEM; ret = PTR_ERR(mpc8xxx_spi->reg_base);
goto err_probe; goto err_probe;
} }
reg_base = mpc8xxx_spi->reg_base; reg_base = mpc8xxx_spi->reg_base;
/* Register for SPI Interrupt */ /* Register for SPI Interrupt */
ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq, ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_espi_irq,
0, "fsl_espi", mpc8xxx_spi); 0, "fsl_espi", mpc8xxx_spi);
if (ret) if (ret)
goto free_irq; goto err_probe;
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
mpc8xxx_spi->rx_shift = 16; mpc8xxx_spi->rx_shift = 16;
...@@ -731,18 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev, ...@@ -731,18 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
ret = spi_register_master(master); pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
ret = devm_spi_register_master(dev, master);
if (ret < 0) if (ret < 0)
goto unreg_master; goto err_pm;
dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return master; return master;
unreg_master: err_pm:
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); pm_runtime_put_noidle(dev);
free_irq: pm_runtime_disable(dev);
iounmap(mpc8xxx_spi->reg_base); pm_runtime_set_suspended(dev);
err_probe: err_probe:
spi_master_put(master); spi_master_put(master);
err: err:
...@@ -809,7 +818,9 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) ...@@ -809,7 +818,9 @@ static int of_fsl_espi_probe(struct platform_device *ofdev)
static int of_fsl_espi_remove(struct platform_device *dev) static int of_fsl_espi_remove(struct platform_device *dev)
{ {
return mpc8xxx_spi_remove(&dev->dev); pm_runtime_disable(&dev->dev);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -824,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev) ...@@ -824,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev)
return ret; return ret;
} }
return fsl_espi_suspend(master); ret = pm_runtime_force_suspend(dev);
if (ret < 0)
return ret;
return 0;
} }
static int of_fsl_espi_resume(struct device *dev) static int of_fsl_espi_resume(struct device *dev)
...@@ -834,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev) ...@@ -834,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev)
struct mpc8xxx_spi *mpc8xxx_spi; struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_espi_reg *reg_base; struct fsl_espi_reg *reg_base;
u32 regval; u32 regval;
int i; int i, ret;
mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi = spi_master_get_devdata(master);
reg_base = mpc8xxx_spi->reg_base; reg_base = mpc8xxx_spi->reg_base;
...@@ -854,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev) ...@@ -854,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev)
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
ret = pm_runtime_force_resume(dev);
if (ret < 0)
return ret;
return spi_master_resume(master); return spi_master_resume(master);
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops espi_pm = { static const struct dev_pm_ops espi_pm = {
SET_RUNTIME_PM_OPS(fsl_espi_runtime_suspend,
fsl_espi_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume) SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume)
}; };
......
...@@ -114,25 +114,6 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, ...@@ -114,25 +114,6 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
} }
EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe); EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe);
int mpc8xxx_spi_remove(struct device *dev)
{
struct mpc8xxx_spi *mpc8xxx_spi;
struct spi_master *master;
master = dev_get_drvdata(dev);
mpc8xxx_spi = spi_master_get_devdata(master);
spi_unregister_master(master);
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
if (mpc8xxx_spi->spi_remove)
mpc8xxx_spi->spi_remove(mpc8xxx_spi);
return 0;
}
EXPORT_SYMBOL_GPL(mpc8xxx_spi_remove);
int of_mpc8xxx_spi_probe(struct platform_device *ofdev) int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
{ {
struct device *dev = &ofdev->dev; struct device *dev = &ofdev->dev;
......
...@@ -54,9 +54,6 @@ struct mpc8xxx_spi { ...@@ -54,9 +54,6 @@ struct mpc8xxx_spi {
void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
u32(*get_tx) (struct mpc8xxx_spi *); u32(*get_tx) (struct mpc8xxx_spi *);
/* hooks for different controller driver */
void (*spi_remove) (struct mpc8xxx_spi *mspi);
unsigned int count; unsigned int count;
unsigned int irq; unsigned int irq;
......
...@@ -559,12 +559,6 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) ...@@ -559,12 +559,6 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
return ret; return ret;
} }
static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
{
iounmap(mspi->reg_base);
fsl_spi_cpm_free(mspi);
}
static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
{ {
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
...@@ -631,7 +625,6 @@ static struct spi_master * fsl_spi_probe(struct device *dev, ...@@ -631,7 +625,6 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
master->transfer_one_message = fsl_spi_do_one_msg; master->transfer_one_message = fsl_spi_do_one_msg;
mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->spi_remove = fsl_spi_remove;
mpc8xxx_spi->max_bits_per_word = 32; mpc8xxx_spi->max_bits_per_word = 32;
mpc8xxx_spi->type = fsl_spi_get_type(dev); mpc8xxx_spi->type = fsl_spi_get_type(dev);
...@@ -639,10 +632,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev, ...@@ -639,10 +632,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
if (ret) if (ret)
goto err_cpm_init; goto err_cpm_init;
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
if (mpc8xxx_spi->reg_base == NULL) { if (IS_ERR(mpc8xxx_spi->reg_base)) {
ret = -ENOMEM; ret = PTR_ERR(mpc8xxx_spi->reg_base);
goto err_ioremap; goto err_probe;
} }
if (mpc8xxx_spi->type == TYPE_GRLIB) if (mpc8xxx_spi->type == TYPE_GRLIB)
...@@ -661,11 +654,11 @@ static struct spi_master * fsl_spi_probe(struct device *dev, ...@@ -661,11 +654,11 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
&mpc8xxx_spi->tx_shift, 8, 1); &mpc8xxx_spi->tx_shift, 8, 1);
/* Register for SPI Interrupt */ /* Register for SPI Interrupt */
ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq, ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_spi_irq,
0, "fsl_spi", mpc8xxx_spi); 0, "fsl_spi", mpc8xxx_spi);
if (ret != 0) if (ret != 0)
goto free_irq; goto err_probe;
reg_base = mpc8xxx_spi->reg_base; reg_base = mpc8xxx_spi->reg_base;
...@@ -686,20 +679,16 @@ static struct spi_master * fsl_spi_probe(struct device *dev, ...@@ -686,20 +679,16 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
mpc8xxx_spi_write_reg(&reg_base->mode, regval); mpc8xxx_spi_write_reg(&reg_base->mode, regval);
ret = spi_register_master(master); ret = devm_spi_register_master(dev, master);
if (ret < 0) if (ret < 0)
goto unreg_master; goto err_probe;
dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base, dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags)); mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
return master; return master;
unreg_master: err_probe:
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
free_irq:
iounmap(mpc8xxx_spi->reg_base);
err_ioremap:
fsl_spi_cpm_free(mpc8xxx_spi); fsl_spi_cpm_free(mpc8xxx_spi);
err_cpm_init: err_cpm_init:
spi_master_put(master); spi_master_put(master);
...@@ -866,11 +855,8 @@ static int of_fsl_spi_remove(struct platform_device *ofdev) ...@@ -866,11 +855,8 @@ static int of_fsl_spi_remove(struct platform_device *ofdev)
{ {
struct spi_master *master = platform_get_drvdata(ofdev); struct spi_master *master = platform_get_drvdata(ofdev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
int ret;
ret = mpc8xxx_spi_remove(&ofdev->dev); fsl_spi_cpm_free(mpc8xxx_spi);
if (ret)
return ret;
if (mpc8xxx_spi->type == TYPE_FSL) if (mpc8xxx_spi->type == TYPE_FSL)
of_fsl_spi_free_chipselects(&ofdev->dev); of_fsl_spi_free_chipselects(&ofdev->dev);
return 0; return 0;
...@@ -916,7 +902,12 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev) ...@@ -916,7 +902,12 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
static int plat_mpc8xxx_spi_remove(struct platform_device *pdev) static int plat_mpc8xxx_spi_remove(struct platform_device *pdev)
{ {
return mpc8xxx_spi_remove(&pdev->dev); struct spi_master *master = platform_get_drvdata(pdev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
fsl_spi_cpm_free(mpc8xxx_spi);
return 0;
} }
MODULE_ALIAS("platform:mpc8xxx_spi"); MODULE_ALIAS("platform:mpc8xxx_spi");
......
...@@ -105,6 +105,10 @@ struct img_spfi { ...@@ -105,6 +105,10 @@ struct img_spfi {
bool rx_dma_busy; bool rx_dma_busy;
}; };
struct img_spfi_device_data {
bool gpio_requested;
};
static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
{ {
return readl(spfi->regs + reg); return readl(spfi->regs + reg);
...@@ -267,15 +271,15 @@ static int img_spfi_start_pio(struct spi_master *master, ...@@ -267,15 +271,15 @@ static int img_spfi_start_pio(struct spi_master *master,
cpu_relax(); cpu_relax();
} }
ret = spfi_wait_all_done(spfi);
if (ret < 0)
return ret;
if (rx_bytes > 0 || tx_bytes > 0) { if (rx_bytes > 0 || tx_bytes > 0) {
dev_err(spfi->dev, "PIO transfer timed out\n"); dev_err(spfi->dev, "PIO transfer timed out\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
ret = spfi_wait_all_done(spfi);
if (ret < 0)
return ret;
return 0; return 0;
} }
...@@ -440,21 +444,50 @@ static int img_spfi_unprepare(struct spi_master *master, ...@@ -440,21 +444,50 @@ static int img_spfi_unprepare(struct spi_master *master,
static int img_spfi_setup(struct spi_device *spi) static int img_spfi_setup(struct spi_device *spi)
{ {
int ret; int ret = -EINVAL;
struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, if (!spfi_data) {
dev_name(&spi->dev)); spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL);
if (ret) if (!spfi_data)
dev_err(&spi->dev, "can't request chipselect gpio %d\n", return -ENOMEM;
spfi_data->gpio_requested = false;
spi_set_ctldata(spi, spfi_data);
}
if (!spfi_data->gpio_requested) {
ret = gpio_request_one(spi->cs_gpio,
(spi->mode & SPI_CS_HIGH) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
dev_name(&spi->dev));
if (ret)
dev_err(&spi->dev, "can't request chipselect gpio %d\n",
spi->cs_gpio); spi->cs_gpio);
else
spfi_data->gpio_requested = true;
} else {
if (gpio_is_valid(spi->cs_gpio)) {
int mode = ((spi->mode & SPI_CS_HIGH) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
ret = gpio_direction_output(spi->cs_gpio, mode);
if (ret)
dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
spi->cs_gpio, ret);
}
}
return ret; return ret;
} }
static void img_spfi_cleanup(struct spi_device *spi) static void img_spfi_cleanup(struct spi_device *spi)
{ {
gpio_free(spi->cs_gpio); struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
if (spfi_data) {
if (spfi_data->gpio_requested)
gpio_free(spi->cs_gpio);
kfree(spfi_data);
spi_set_ctldata(spi, NULL);
}
} }
static void img_spfi_config(struct spi_master *master, struct spi_device *spi, static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
...@@ -548,6 +581,7 @@ static int img_spfi_probe(struct platform_device *pdev) ...@@ -548,6 +581,7 @@ static int img_spfi_probe(struct platform_device *pdev)
struct img_spfi *spfi; struct img_spfi *spfi;
struct resource *res; struct resource *res;
int ret; int ret;
u32 max_speed_hz;
master = spi_alloc_master(&pdev->dev, sizeof(*spfi)); master = spi_alloc_master(&pdev->dev, sizeof(*spfi));
if (!master) if (!master)
...@@ -612,6 +646,19 @@ static int img_spfi_probe(struct platform_device *pdev) ...@@ -612,6 +646,19 @@ static int img_spfi_probe(struct platform_device *pdev)
master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
/*
* Maximum speed supported by spfi is limited to the lower value
* between 1/4 of the SPFI clock or to "spfi-max-frequency"
* defined in the device tree.
* If no value is defined in the device tree assume the maximum
* speed supported to be 1/4 of the SPFI clock.
*/
if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency",
&max_speed_hz)) {
if (master->max_speed_hz > max_speed_hz)
master->max_speed_hz = max_speed_hz;
}
master->setup = img_spfi_setup; master->setup = img_spfi_setup;
master->cleanup = img_spfi_cleanup; master->cleanup = img_spfi_cleanup;
master->transfer_one = img_spfi_transfer_one; master->transfer_one = img_spfi_transfer_one;
......
...@@ -30,11 +30,37 @@ ...@@ -30,11 +30,37 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <asm/mpc52xx_psc.h> #include <asm/mpc52xx_psc.h>
enum {
TYPE_MPC5121,
TYPE_MPC5125,
};
/*
* This macro abstracts the differences in the PSC register layout between
* MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc).
*/
#define psc_addr(mps, regname) ({ \
void *__ret = NULL; \
switch (mps->type) { \
case TYPE_MPC5121: { \
struct mpc52xx_psc __iomem *psc = mps->psc; \
__ret = &psc->regname; \
}; \
break; \
case TYPE_MPC5125: { \
struct mpc5125_psc __iomem *psc = mps->psc; \
__ret = &psc->regname; \
}; \
break; \
} \
__ret; })
struct mpc512x_psc_spi { struct mpc512x_psc_spi {
void (*cs_control)(struct spi_device *spi, bool on); void (*cs_control)(struct spi_device *spi, bool on);
/* driver internal data */ /* driver internal data */
struct mpc52xx_psc __iomem *psc; int type;
void __iomem *psc;
struct mpc512x_psc_fifo __iomem *fifo; struct mpc512x_psc_fifo __iomem *fifo;
unsigned int irq; unsigned int irq;
u8 bits_per_word; u8 bits_per_word;
...@@ -71,13 +97,12 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) ...@@ -71,13 +97,12 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
{ {
struct mpc512x_psc_spi_cs *cs = spi->controller_state; struct mpc512x_psc_spi_cs *cs = spi->controller_state;
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc52xx_psc __iomem *psc = mps->psc;
u32 sicr; u32 sicr;
u32 ccr; u32 ccr;
int speed; int speed;
u16 bclkdiv; u16 bclkdiv;
sicr = in_be32(&psc->sicr); sicr = in_be32(psc_addr(mps, sicr));
/* Set clock phase and polarity */ /* Set clock phase and polarity */
if (spi->mode & SPI_CPHA) if (spi->mode & SPI_CPHA)
...@@ -94,9 +119,9 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) ...@@ -94,9 +119,9 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
sicr |= 0x10000000; sicr |= 0x10000000;
else else
sicr &= ~0x10000000; sicr &= ~0x10000000;
out_be32(&psc->sicr, sicr); out_be32(psc_addr(mps, sicr), sicr);
ccr = in_be32(&psc->ccr); ccr = in_be32(psc_addr(mps, ccr));
ccr &= 0xFF000000; ccr &= 0xFF000000;
speed = cs->speed_hz; speed = cs->speed_hz;
if (!speed) if (!speed)
...@@ -104,7 +129,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) ...@@ -104,7 +129,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
bclkdiv = (mps->mclk_rate / speed) - 1; bclkdiv = (mps->mclk_rate / speed) - 1;
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
out_be32(&psc->ccr, ccr); out_be32(psc_addr(mps, ccr), ccr);
mps->bits_per_word = cs->bits_per_word; mps->bits_per_word = cs->bits_per_word;
if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) if (mps->cs_control && gpio_is_valid(spi->cs_gpio))
...@@ -315,16 +340,15 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master, ...@@ -315,16 +340,15 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
{ {
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
struct mpc52xx_psc __iomem *psc = mps->psc;
dev_dbg(&master->dev, "%s()\n", __func__); dev_dbg(&master->dev, "%s()\n", __func__);
/* Zero MR2 */ /* Zero MR2 */
in_8(&psc->mode); in_8(psc_addr(mps, mr2));
out_8(&psc->mode, 0x0); out_8(psc_addr(mps, mr2), 0x0);
/* enable transmitter/receiver */ /* enable transmitter/receiver */
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); out_8(psc_addr(mps, command), MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
return 0; return 0;
} }
...@@ -332,13 +356,12 @@ static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) ...@@ -332,13 +356,12 @@ static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master) static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master)
{ {
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
dev_dbg(&master->dev, "%s()\n", __func__); dev_dbg(&master->dev, "%s()\n", __func__);
/* disable transmitter/receiver and fifo interrupt */ /* disable transmitter/receiver and fifo interrupt */
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
out_be32(&fifo->tximr, 0); out_be32(&fifo->tximr, 0);
return 0; return 0;
...@@ -388,7 +411,6 @@ static void mpc512x_psc_spi_cleanup(struct spi_device *spi) ...@@ -388,7 +411,6 @@ static void mpc512x_psc_spi_cleanup(struct spi_device *spi)
static int mpc512x_psc_spi_port_config(struct spi_master *master, static int mpc512x_psc_spi_port_config(struct spi_master *master,
struct mpc512x_psc_spi *mps) struct mpc512x_psc_spi *mps)
{ {
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
u32 sicr; u32 sicr;
u32 ccr; u32 ccr;
...@@ -396,12 +418,12 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, ...@@ -396,12 +418,12 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
u16 bclkdiv; u16 bclkdiv;
/* Reset the PSC into a known state */ /* Reset the PSC into a known state */
out_8(&psc->command, MPC52xx_PSC_RST_RX); out_8(psc_addr(mps, command), MPC52xx_PSC_RST_RX);
out_8(&psc->command, MPC52xx_PSC_RST_TX); out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX);
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
/* Disable psc interrupts all useful interrupts are in fifo */ /* Disable psc interrupts all useful interrupts are in fifo */
out_be16(&psc->isr_imr.imr, 0); out_be16(psc_addr(mps, isr_imr.imr), 0);
/* Disable fifo interrupts, will be enabled later */ /* Disable fifo interrupts, will be enabled later */
out_be32(&fifo->tximr, 0); out_be32(&fifo->tximr, 0);
...@@ -417,18 +439,18 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, ...@@ -417,18 +439,18 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
0x00004000 | /* MSTR = 1 -- SPI master */ 0x00004000 | /* MSTR = 1 -- SPI master */
0x00000800; /* UseEOF = 1 -- SS low until EOF */ 0x00000800; /* UseEOF = 1 -- SS low until EOF */
out_be32(&psc->sicr, sicr); out_be32(psc_addr(mps, sicr), sicr);
ccr = in_be32(&psc->ccr); ccr = in_be32(psc_addr(mps, ccr));
ccr &= 0xFF000000; ccr &= 0xFF000000;
speed = 1000000; /* default 1MHz */ speed = 1000000; /* default 1MHz */
bclkdiv = (mps->mclk_rate / speed) - 1; bclkdiv = (mps->mclk_rate / speed) - 1;
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
out_be32(&psc->ccr, ccr); out_be32(psc_addr(mps, ccr), ccr);
/* Set 2ms DTL delay */ /* Set 2ms DTL delay */
out_8(&psc->ctur, 0x00); out_8(psc_addr(mps, ctur), 0x00);
out_8(&psc->ctlr, 0x82); out_8(psc_addr(mps, ctlr), 0x82);
/* we don't use the alarms */ /* we don't use the alarms */
out_be32(&fifo->rxalarm, 0xfff); out_be32(&fifo->rxalarm, 0xfff);
...@@ -482,6 +504,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, ...@@ -482,6 +504,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
dev_set_drvdata(dev, master); dev_set_drvdata(dev, master);
mps = spi_master_get_devdata(master); mps = spi_master_get_devdata(master);
mps->type = (int)of_device_get_match_data(dev);
mps->irq = irq; mps->irq = irq;
if (pdata == NULL) { if (pdata == NULL) {
...@@ -589,7 +612,8 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op) ...@@ -589,7 +612,8 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op)
} }
static const struct of_device_id mpc512x_psc_spi_of_match[] = { static const struct of_device_id mpc512x_psc_spi_of_match[] = {
{ .compatible = "fsl,mpc5121-psc-spi", }, { .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 },
{ .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 },
{}, {},
}; };
......
/*
* Copyright (c) 2015 MediaTek Inc.
* Author: Leilk Liu <leilk.liu@mediatek.com>
*
* 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/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/platform_data/spi-mt65xx.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#define SPI_CFG0_REG 0x0000
#define SPI_CFG1_REG 0x0004
#define SPI_TX_SRC_REG 0x0008
#define SPI_RX_DST_REG 0x000c
#define SPI_TX_DATA_REG 0x0010
#define SPI_RX_DATA_REG 0x0014
#define SPI_CMD_REG 0x0018
#define SPI_STATUS0_REG 0x001c
#define SPI_PAD_SEL_REG 0x0024
#define SPI_CFG0_SCK_HIGH_OFFSET 0
#define SPI_CFG0_SCK_LOW_OFFSET 8
#define SPI_CFG0_CS_HOLD_OFFSET 16
#define SPI_CFG0_CS_SETUP_OFFSET 24
#define SPI_CFG1_CS_IDLE_OFFSET 0
#define SPI_CFG1_PACKET_LOOP_OFFSET 8
#define SPI_CFG1_PACKET_LENGTH_OFFSET 16
#define SPI_CFG1_GET_TICK_DLY_OFFSET 30
#define SPI_CFG1_CS_IDLE_MASK 0xff
#define SPI_CFG1_PACKET_LOOP_MASK 0xff00
#define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000
#define SPI_CMD_ACT BIT(0)
#define SPI_CMD_RESUME BIT(1)
#define SPI_CMD_RST BIT(2)
#define SPI_CMD_PAUSE_EN BIT(4)
#define SPI_CMD_DEASSERT BIT(5)
#define SPI_CMD_CPHA BIT(8)
#define SPI_CMD_CPOL BIT(9)
#define SPI_CMD_RX_DMA BIT(10)
#define SPI_CMD_TX_DMA BIT(11)
#define SPI_CMD_TXMSBF BIT(12)
#define SPI_CMD_RXMSBF BIT(13)
#define SPI_CMD_RX_ENDIAN BIT(14)
#define SPI_CMD_TX_ENDIAN BIT(15)
#define SPI_CMD_FINISH_IE BIT(16)
#define SPI_CMD_PAUSE_IE BIT(17)
#define MT8173_SPI_MAX_PAD_SEL 3
#define MTK_SPI_PAUSE_INT_STATUS 0x2
#define MTK_SPI_IDLE 0
#define MTK_SPI_PAUSED 1
#define MTK_SPI_MAX_FIFO_SIZE 32
#define MTK_SPI_PACKET_SIZE 1024
struct mtk_spi_compatible {
bool need_pad_sel;
/* Must explicitly send dummy Tx bytes to do Rx only transfer */
bool must_tx;
};
struct mtk_spi {
void __iomem *base;
u32 state;
u32 pad_sel;
struct clk *spi_clk, *parent_clk;
struct spi_transfer *cur_transfer;
u32 xfer_len;
struct scatterlist *tx_sgl, *rx_sgl;
u32 tx_sgl_len, rx_sgl_len;
const struct mtk_spi_compatible *dev_comp;
};
static const struct mtk_spi_compatible mt6589_compat;
static const struct mtk_spi_compatible mt8135_compat;
static const struct mtk_spi_compatible mt8173_compat = {
.need_pad_sel = true,
.must_tx = true,
};
/*
* A piece of default chip info unless the platform
* supplies it.
*/
static const struct mtk_chip_config mtk_default_chip_info = {
.rx_mlsb = 1,
.tx_mlsb = 1,
};
static const struct of_device_id mtk_spi_of_match[] = {
{ .compatible = "mediatek,mt6589-spi", .data = (void *)&mt6589_compat },
{ .compatible = "mediatek,mt8135-spi", .data = (void *)&mt8135_compat },
{ .compatible = "mediatek,mt8173-spi", .data = (void *)&mt8173_compat },
{}
};
MODULE_DEVICE_TABLE(of, mtk_spi_of_match);
static void mtk_spi_reset(struct mtk_spi *mdata)
{
u32 reg_val;
/* set the software reset bit in SPI_CMD_REG. */
reg_val = readl(mdata->base + SPI_CMD_REG);
reg_val |= SPI_CMD_RST;
writel(reg_val, mdata->base + SPI_CMD_REG);
reg_val = readl(mdata->base + SPI_CMD_REG);
reg_val &= ~SPI_CMD_RST;
writel(reg_val, mdata->base + SPI_CMD_REG);
}
static void mtk_spi_config(struct mtk_spi *mdata,
struct mtk_chip_config *chip_config)
{
u32 reg_val;
reg_val = readl(mdata->base + SPI_CMD_REG);
/* set the mlsbx and mlsbtx */
if (chip_config->tx_mlsb)
reg_val |= SPI_CMD_TXMSBF;
else
reg_val &= ~SPI_CMD_TXMSBF;
if (chip_config->rx_mlsb)
reg_val |= SPI_CMD_RXMSBF;
else
reg_val &= ~SPI_CMD_RXMSBF;
/* set the tx/rx endian */
#ifdef __LITTLE_ENDIAN
reg_val &= ~SPI_CMD_TX_ENDIAN;
reg_val &= ~SPI_CMD_RX_ENDIAN;
#else
reg_val |= SPI_CMD_TX_ENDIAN;
reg_val |= SPI_CMD_RX_ENDIAN;
#endif
/* set finish and pause interrupt always enable */
reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_IE;
/* disable dma mode */
reg_val &= ~(SPI_CMD_TX_DMA | SPI_CMD_RX_DMA);
/* disable deassert mode */
reg_val &= ~SPI_CMD_DEASSERT;
writel(reg_val, mdata->base + SPI_CMD_REG);
/* pad select */
if (mdata->dev_comp->need_pad_sel)
writel(mdata->pad_sel, mdata->base + SPI_PAD_SEL_REG);
}
static int mtk_spi_prepare_hardware(struct spi_master *master)
{
struct spi_transfer *trans;
struct mtk_spi *mdata = spi_master_get_devdata(master);
struct spi_message *msg = master->cur_msg;
trans = list_first_entry(&msg->transfers, struct spi_transfer,
transfer_list);
if (!trans->cs_change) {
mdata->state = MTK_SPI_IDLE;
mtk_spi_reset(mdata);
}
return 0;
}
static int mtk_spi_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
u32 reg_val;
u8 cpha, cpol;
struct mtk_chip_config *chip_config;
struct spi_device *spi = msg->spi;
struct mtk_spi *mdata = spi_master_get_devdata(master);
cpha = spi->mode & SPI_CPHA ? 1 : 0;
cpol = spi->mode & SPI_CPOL ? 1 : 0;
reg_val = readl(mdata->base + SPI_CMD_REG);
if (cpha)
reg_val |= SPI_CMD_CPHA;
else
reg_val &= ~SPI_CMD_CPHA;
if (cpol)
reg_val |= SPI_CMD_CPOL;
else
reg_val &= ~SPI_CMD_CPOL;
writel(reg_val, mdata->base + SPI_CMD_REG);
chip_config = spi->controller_data;
if (!chip_config) {
chip_config = (void *)&mtk_default_chip_info;
spi->controller_data = chip_config;
}
mtk_spi_config(mdata, chip_config);
return 0;
}
static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
{
u32 reg_val;
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
reg_val = readl(mdata->base + SPI_CMD_REG);
if (!enable)
reg_val |= SPI_CMD_PAUSE_EN;
else
reg_val &= ~SPI_CMD_PAUSE_EN;
writel(reg_val, mdata->base + SPI_CMD_REG);
}
static void mtk_spi_prepare_transfer(struct spi_master *master,
struct spi_transfer *xfer)
{
u32 spi_clk_hz, div, sck_time, cs_time, reg_val = 0;
struct mtk_spi *mdata = spi_master_get_devdata(master);
spi_clk_hz = clk_get_rate(mdata->spi_clk);
if (xfer->speed_hz < spi_clk_hz / 2)
div = DIV_ROUND_UP(spi_clk_hz, xfer->speed_hz);
else
div = 1;
sck_time = (div + 1) / 2;
cs_time = sck_time * 2;
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_HIGH_OFFSET);
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET);
writel(reg_val, mdata->base + SPI_CFG0_REG);
reg_val = readl(mdata->base + SPI_CFG1_REG);
reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
writel(reg_val, mdata->base + SPI_CFG1_REG);
}
static void mtk_spi_setup_packet(struct spi_master *master)
{
u32 packet_size, packet_loop, reg_val;
struct mtk_spi *mdata = spi_master_get_devdata(master);
packet_size = min_t(u32, mdata->xfer_len, MTK_SPI_PACKET_SIZE);
packet_loop = mdata->xfer_len / packet_size;
reg_val = readl(mdata->base + SPI_CFG1_REG);
reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK);
reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET;
reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET;
writel(reg_val, mdata->base + SPI_CFG1_REG);
}
static void mtk_spi_enable_transfer(struct spi_master *master)
{
u32 cmd;
struct mtk_spi *mdata = spi_master_get_devdata(master);
cmd = readl(mdata->base + SPI_CMD_REG);
if (mdata->state == MTK_SPI_IDLE)
cmd |= SPI_CMD_ACT;
else
cmd |= SPI_CMD_RESUME;
writel(cmd, mdata->base + SPI_CMD_REG);
}
static int mtk_spi_get_mult_delta(u32 xfer_len)
{
u32 mult_delta;
if (xfer_len > MTK_SPI_PACKET_SIZE)
mult_delta = xfer_len % MTK_SPI_PACKET_SIZE;
else
mult_delta = 0;
return mult_delta;
}
static void mtk_spi_update_mdata_len(struct spi_master *master)
{
int mult_delta;
struct mtk_spi *mdata = spi_master_get_devdata(master);
if (mdata->tx_sgl_len && mdata->rx_sgl_len) {
if (mdata->tx_sgl_len > mdata->rx_sgl_len) {
mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len);
mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
mdata->rx_sgl_len = mult_delta;
mdata->tx_sgl_len -= mdata->xfer_len;
} else {
mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len);
mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
mdata->tx_sgl_len = mult_delta;
mdata->rx_sgl_len -= mdata->xfer_len;
}
} else if (mdata->tx_sgl_len) {
mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len);
mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
mdata->tx_sgl_len = mult_delta;
} else if (mdata->rx_sgl_len) {
mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len);
mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
mdata->rx_sgl_len = mult_delta;
}
}
static void mtk_spi_setup_dma_addr(struct spi_master *master,
struct spi_transfer *xfer)
{
struct mtk_spi *mdata = spi_master_get_devdata(master);
if (mdata->tx_sgl)
writel(xfer->tx_dma, mdata->base + SPI_TX_SRC_REG);
if (mdata->rx_sgl)
writel(xfer->rx_dma, mdata->base + SPI_RX_DST_REG);
}
static int mtk_spi_fifo_transfer(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
int cnt;
struct mtk_spi *mdata = spi_master_get_devdata(master);
mdata->cur_transfer = xfer;
mdata->xfer_len = xfer->len;
mtk_spi_prepare_transfer(master, xfer);
mtk_spi_setup_packet(master);
if (xfer->len % 4)
cnt = xfer->len / 4 + 1;
else
cnt = xfer->len / 4;
iowrite32_rep(mdata->base + SPI_TX_DATA_REG, xfer->tx_buf, cnt);
mtk_spi_enable_transfer(master);
return 1;
}
static int mtk_spi_dma_transfer(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
int cmd;
struct mtk_spi *mdata = spi_master_get_devdata(master);
mdata->tx_sgl = NULL;
mdata->rx_sgl = NULL;
mdata->tx_sgl_len = 0;
mdata->rx_sgl_len = 0;
mdata->cur_transfer = xfer;
mtk_spi_prepare_transfer(master, xfer);
cmd = readl(mdata->base + SPI_CMD_REG);
if (xfer->tx_buf)
cmd |= SPI_CMD_TX_DMA;
if (xfer->rx_buf)
cmd |= SPI_CMD_RX_DMA;
writel(cmd, mdata->base + SPI_CMD_REG);
if (xfer->tx_buf)
mdata->tx_sgl = xfer->tx_sg.sgl;
if (xfer->rx_buf)
mdata->rx_sgl = xfer->rx_sg.sgl;
if (mdata->tx_sgl) {
xfer->tx_dma = sg_dma_address(mdata->tx_sgl);
mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
}
if (mdata->rx_sgl) {
xfer->rx_dma = sg_dma_address(mdata->rx_sgl);
mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
}
mtk_spi_update_mdata_len(master);
mtk_spi_setup_packet(master);
mtk_spi_setup_dma_addr(master, xfer);
mtk_spi_enable_transfer(master);
return 1;
}
static int mtk_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
if (master->can_dma(master, spi, xfer))
return mtk_spi_dma_transfer(master, spi, xfer);
else
return mtk_spi_fifo_transfer(master, spi, xfer);
}
static bool mtk_spi_can_dma(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
return xfer->len > MTK_SPI_MAX_FIFO_SIZE;
}
static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
{
u32 cmd, reg_val, cnt;
struct spi_master *master = dev_id;
struct mtk_spi *mdata = spi_master_get_devdata(master);
struct spi_transfer *trans = mdata->cur_transfer;
reg_val = readl(mdata->base + SPI_STATUS0_REG);
if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
mdata->state = MTK_SPI_PAUSED;
else
mdata->state = MTK_SPI_IDLE;
if (!master->can_dma(master, master->cur_msg->spi, trans)) {
if (trans->rx_buf) {
if (mdata->xfer_len % 4)
cnt = mdata->xfer_len / 4 + 1;
else
cnt = mdata->xfer_len / 4;
ioread32_rep(mdata->base + SPI_RX_DATA_REG,
trans->rx_buf, cnt);
}
spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
if (mdata->tx_sgl)
trans->tx_dma += mdata->xfer_len;
if (mdata->rx_sgl)
trans->rx_dma += mdata->xfer_len;
if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) {
mdata->tx_sgl = sg_next(mdata->tx_sgl);
if (mdata->tx_sgl) {
trans->tx_dma = sg_dma_address(mdata->tx_sgl);
mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
}
}
if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) {
mdata->rx_sgl = sg_next(mdata->rx_sgl);
if (mdata->rx_sgl) {
trans->rx_dma = sg_dma_address(mdata->rx_sgl);
mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
}
}
if (!mdata->tx_sgl && !mdata->rx_sgl) {
/* spi disable dma */
cmd = readl(mdata->base + SPI_CMD_REG);
cmd &= ~SPI_CMD_TX_DMA;
cmd &= ~SPI_CMD_RX_DMA;
writel(cmd, mdata->base + SPI_CMD_REG);
spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
mtk_spi_update_mdata_len(master);
mtk_spi_setup_packet(master);
mtk_spi_setup_dma_addr(master, trans);
mtk_spi_enable_transfer(master);
return IRQ_HANDLED;
}
static int mtk_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct mtk_spi *mdata;
const struct of_device_id *of_id;
struct resource *res;
int irq, ret;
master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
if (!master) {
dev_err(&pdev->dev, "failed to alloc spi master\n");
return -ENOMEM;
}
master->auto_runtime_pm = true;
master->dev.of_node = pdev->dev.of_node;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->set_cs = mtk_spi_set_cs;
master->prepare_transfer_hardware = mtk_spi_prepare_hardware;
master->prepare_message = mtk_spi_prepare_message;
master->transfer_one = mtk_spi_transfer_one;
master->can_dma = mtk_spi_can_dma;
of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node);
if (!of_id) {
dev_err(&pdev->dev, "failed to probe of_node\n");
ret = -EINVAL;
goto err_put_master;
}
mdata = spi_master_get_devdata(master);
mdata->dev_comp = of_id->data;
if (mdata->dev_comp->must_tx)
master->flags = SPI_MASTER_MUST_TX;
if (mdata->dev_comp->need_pad_sel) {
ret = of_property_read_u32(pdev->dev.of_node,
"mediatek,pad-select",
&mdata->pad_sel);
if (ret) {
dev_err(&pdev->dev, "failed to read pad select: %d\n",
ret);
goto err_put_master;
}
if (mdata->pad_sel > MT8173_SPI_MAX_PAD_SEL) {
dev_err(&pdev->dev, "wrong pad-select: %u\n",
mdata->pad_sel);
ret = -EINVAL;
goto err_put_master;
}
}
platform_set_drvdata(pdev, master);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
dev_err(&pdev->dev, "failed to determine base address\n");
goto err_put_master;
}
mdata->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(mdata->base)) {
ret = PTR_ERR(mdata->base);
goto err_put_master;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get irq (%d)\n", irq);
ret = irq;
goto err_put_master;
}
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
ret = devm_request_irq(&pdev->dev, irq, mtk_spi_interrupt,
IRQF_TRIGGER_NONE, dev_name(&pdev->dev), master);
if (ret) {
dev_err(&pdev->dev, "failed to register irq (%d)\n", ret);
goto err_put_master;
}
mdata->spi_clk = devm_clk_get(&pdev->dev, "spi-clk");
if (IS_ERR(mdata->spi_clk)) {
ret = PTR_ERR(mdata->spi_clk);
dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret);
goto err_put_master;
}
mdata->parent_clk = devm_clk_get(&pdev->dev, "parent-clk");
if (IS_ERR(mdata->parent_clk)) {
ret = PTR_ERR(mdata->parent_clk);
dev_err(&pdev->dev, "failed to get parent-clk: %d\n", ret);
goto err_put_master;
}
ret = clk_prepare_enable(mdata->spi_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret);
goto err_put_master;
}
ret = clk_set_parent(mdata->spi_clk, mdata->parent_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to clk_set_parent (%d)\n", ret);
goto err_disable_clk;
}
clk_disable_unprepare(mdata->spi_clk);
pm_runtime_enable(&pdev->dev);
ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
dev_err(&pdev->dev, "failed to register master (%d)\n", ret);
goto err_put_master;
}
return 0;
err_disable_clk:
clk_disable_unprepare(mdata->spi_clk);
err_put_master:
spi_master_put(master);
return ret;
}
static int mtk_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
pm_runtime_disable(&pdev->dev);
mtk_spi_reset(mdata);
clk_disable_unprepare(mdata->spi_clk);
spi_master_put(master);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int mtk_spi_suspend(struct device *dev)
{
int ret;
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
ret = spi_master_suspend(master);
if (ret)
return ret;
if (!pm_runtime_suspended(dev))
clk_disable_unprepare(mdata->spi_clk);
return ret;
}
static int mtk_spi_resume(struct device *dev)
{
int ret;
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
if (!pm_runtime_suspended(dev)) {
ret = clk_prepare_enable(mdata->spi_clk);
if (ret < 0) {
dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
return ret;
}
}
ret = spi_master_resume(master);
if (ret < 0)
clk_disable_unprepare(mdata->spi_clk);
return ret;
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int mtk_spi_runtime_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
clk_disable_unprepare(mdata->spi_clk);
return 0;
}
static int mtk_spi_runtime_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mtk_spi *mdata = spi_master_get_devdata(master);
int ret;
ret = clk_prepare_enable(mdata->spi_clk);
if (ret < 0) {
dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
return ret;
}
return 0;
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops mtk_spi_pm = {
SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_suspend, mtk_spi_resume)
SET_RUNTIME_PM_OPS(mtk_spi_runtime_suspend,
mtk_spi_runtime_resume, NULL)
};
static struct platform_driver mtk_spi_driver = {
.driver = {
.name = "mtk-spi",
.pm = &mtk_spi_pm,
.of_match_table = mtk_spi_of_match,
},
.probe = mtk_spi_probe,
.remove = mtk_spi_remove,
};
module_platform_driver(mtk_spi_driver);
MODULE_DESCRIPTION("MTK SPI Controller driver");
MODULE_AUTHOR("Leilk Liu <leilk.liu@mediatek.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:mtk-spi");
...@@ -245,6 +245,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) ...@@ -245,6 +245,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
{ {
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
u32 l; u32 l;
/* The controller handles the inverted chip selects /* The controller handles the inverted chip selects
...@@ -255,6 +256,12 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) ...@@ -255,6 +256,12 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
enable = !enable; enable = !enable;
if (spi->controller_state) { if (spi->controller_state) {
int err = pm_runtime_get_sync(mcspi->dev);
if (err < 0) {
dev_err(mcspi->dev, "failed to get sync: %d\n", err);
return;
}
l = mcspi_cached_chconf0(spi); l = mcspi_cached_chconf0(spi);
if (enable) if (enable)
...@@ -263,6 +270,9 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) ...@@ -263,6 +270,9 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
l |= OMAP2_MCSPI_CHCONF_FORCE; l |= OMAP2_MCSPI_CHCONF_FORCE;
mcspi_write_chconf0(spi, l); mcspi_write_chconf0(spi, l);
pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
} }
} }
......
...@@ -41,6 +41,11 @@ ...@@ -41,6 +41,11 @@
#define ORION_SPI_DATA_OUT_REG 0x08 #define ORION_SPI_DATA_OUT_REG 0x08
#define ORION_SPI_DATA_IN_REG 0x0c #define ORION_SPI_DATA_IN_REG 0x0c
#define ORION_SPI_INT_CAUSE_REG 0x10 #define ORION_SPI_INT_CAUSE_REG 0x10
#define ORION_SPI_TIMING_PARAMS_REG 0x18
#define ORION_SPI_TMISO_SAMPLE_MASK (0x3 << 6)
#define ORION_SPI_TMISO_SAMPLE_1 (1 << 6)
#define ORION_SPI_TMISO_SAMPLE_2 (2 << 6)
#define ORION_SPI_MODE_CPOL (1 << 11) #define ORION_SPI_MODE_CPOL (1 << 11)
#define ORION_SPI_MODE_CPHA (1 << 12) #define ORION_SPI_MODE_CPHA (1 << 12)
...@@ -70,6 +75,7 @@ struct orion_spi_dev { ...@@ -70,6 +75,7 @@ struct orion_spi_dev {
unsigned int min_divisor; unsigned int min_divisor;
unsigned int max_divisor; unsigned int max_divisor;
u32 prescale_mask; u32 prescale_mask;
bool is_errata_50mhz_ac;
}; };
struct orion_spi { struct orion_spi {
...@@ -195,6 +201,41 @@ orion_spi_mode_set(struct spi_device *spi) ...@@ -195,6 +201,41 @@ orion_spi_mode_set(struct spi_device *spi)
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
} }
static void
orion_spi_50mhz_ac_timing_erratum(struct spi_device *spi, unsigned int speed)
{
u32 reg;
struct orion_spi *orion_spi;
orion_spi = spi_master_get_devdata(spi->master);
/*
* Erratum description: (Erratum NO. FE-9144572) The device
* SPI interface supports frequencies of up to 50 MHz.
* However, due to this erratum, when the device core clock is
* 250 MHz and the SPI interfaces is configured for 50MHz SPI
* clock and CPOL=CPHA=1 there might occur data corruption on
* reads from the SPI device.
* Erratum Workaround:
* Work in one of the following configurations:
* 1. Set CPOL=CPHA=0 in "SPI Interface Configuration
* Register".
* 2. Set TMISO_SAMPLE value to 0x2 in "SPI Timing Parameters 1
* Register" before setting the interface.
*/
reg = readl(spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
reg &= ~ORION_SPI_TMISO_SAMPLE_MASK;
if (clk_get_rate(orion_spi->clk) == 250000000 &&
speed == 50000000 && spi->mode & SPI_CPOL &&
spi->mode & SPI_CPHA)
reg |= ORION_SPI_TMISO_SAMPLE_2;
else
reg |= ORION_SPI_TMISO_SAMPLE_1; /* This is the default value */
writel(reg, spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
}
/* /*
* called only when no transfer is active on the bus * called only when no transfer is active on the bus
*/ */
...@@ -216,6 +257,9 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -216,6 +257,9 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
orion_spi_mode_set(spi); orion_spi_mode_set(spi);
if (orion_spi->devdata->is_errata_50mhz_ac)
orion_spi_50mhz_ac_timing_erratum(spi, speed);
rc = orion_spi_baudrate_set(spi, speed); rc = orion_spi_baudrate_set(spi, speed);
if (rc) if (rc)
return rc; return rc;
...@@ -413,6 +457,14 @@ static const struct orion_spi_dev armada_375_spi_dev_data = { ...@@ -413,6 +457,14 @@ static const struct orion_spi_dev armada_375_spi_dev_data = {
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK, .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
}; };
static const struct orion_spi_dev armada_380_spi_dev_data = {
.typ = ARMADA_SPI,
.max_hz = 50000000,
.max_divisor = 1920,
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
.is_errata_50mhz_ac = true,
};
static const struct of_device_id orion_spi_of_match_table[] = { static const struct of_device_id orion_spi_of_match_table[] = {
{ {
.compatible = "marvell,orion-spi", .compatible = "marvell,orion-spi",
...@@ -428,7 +480,7 @@ static const struct of_device_id orion_spi_of_match_table[] = { ...@@ -428,7 +480,7 @@ static const struct of_device_id orion_spi_of_match_table[] = {
}, },
{ {
.compatible = "marvell,armada-380-spi", .compatible = "marvell,armada-380-spi",
.data = &armada_xp_spi_dev_data, .data = &armada_380_spi_dev_data,
}, },
{ {
.compatible = "marvell,armada-390-spi", .compatible = "marvell,armada-390-spi",
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/clk.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
...@@ -97,6 +98,15 @@ static const struct lpss_config lpss_platforms[] = { ...@@ -97,6 +98,15 @@ static const struct lpss_config lpss_platforms[] = {
.tx_threshold_lo = 160, .tx_threshold_lo = 160,
.tx_threshold_hi = 224, .tx_threshold_hi = 224,
}, },
{ /* LPSS_SPT_SSP */
.offset = 0x200,
.reg_general = -1,
.reg_ssp = 0x20,
.reg_cs_ctrl = 0x24,
.rx_threshold = 1,
.tx_threshold_lo = 32,
.tx_threshold_hi = 56,
},
}; };
static inline const struct lpss_config static inline const struct lpss_config
...@@ -110,6 +120,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data) ...@@ -110,6 +120,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data)
switch (drv_data->ssp_type) { switch (drv_data->ssp_type) {
case LPSS_LPT_SSP: case LPSS_LPT_SSP:
case LPSS_BYT_SSP: case LPSS_BYT_SSP:
case LPSS_SPT_SSP:
return true; return true;
default: default:
return false; return false;
...@@ -1107,6 +1118,7 @@ static int setup(struct spi_device *spi) ...@@ -1107,6 +1118,7 @@ static int setup(struct spi_device *spi)
break; break;
case LPSS_LPT_SSP: case LPSS_LPT_SSP:
case LPSS_BYT_SSP: case LPSS_BYT_SSP:
case LPSS_SPT_SSP:
config = lpss_get_config(drv_data); config = lpss_get_config(drv_data);
tx_thres = config->tx_threshold_lo; tx_thres = config->tx_threshold_lo;
tx_hi_thres = config->tx_threshold_hi; tx_hi_thres = config->tx_threshold_hi;
...@@ -1276,6 +1288,31 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { ...@@ -1276,6 +1288,31 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
}; };
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
/*
* PCI IDs of compound devices that integrate both host controller and private
* integrated DMA engine. Please note these are not used in module
* autoloading and probing in this module but matching the LPSS SSP type.
*/
static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
/* SPT-LP */
{ PCI_VDEVICE(INTEL, 0x9d29), LPSS_SPT_SSP },
{ PCI_VDEVICE(INTEL, 0x9d2a), LPSS_SPT_SSP },
/* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP },
{ PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP },
{ },
};
static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
{
struct device *dev = param;
if (dev != chan->device->dev->parent)
return false;
return true;
}
static struct pxa2xx_spi_master * static struct pxa2xx_spi_master *
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
{ {
...@@ -1283,16 +1320,25 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) ...@@ -1283,16 +1320,25 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
struct acpi_device *adev; struct acpi_device *adev;
struct ssp_device *ssp; struct ssp_device *ssp;
struct resource *res; struct resource *res;
const struct acpi_device_id *id; const struct acpi_device_id *adev_id = NULL;
const struct pci_device_id *pcidev_id = NULL;
int devid, type; int devid, type;
if (!ACPI_HANDLE(&pdev->dev) || if (!ACPI_HANDLE(&pdev->dev) ||
acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev)) acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
return NULL; return NULL;
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); if (dev_is_pci(pdev->dev.parent))
if (id) pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match,
type = (int)id->driver_data; to_pci_dev(pdev->dev.parent));
else
adev_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
&pdev->dev);
if (adev_id)
type = (int)adev_id->driver_data;
else if (pcidev_id)
type = (int)pcidev_id->driver_data;
else else
return NULL; return NULL;
...@@ -1311,6 +1357,12 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) ...@@ -1311,6 +1357,12 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
if (IS_ERR(ssp->mmio_base)) if (IS_ERR(ssp->mmio_base))
return NULL; return NULL;
if (pcidev_id) {
pdata->tx_param = pdev->dev.parent;
pdata->rx_param = pdev->dev.parent;
pdata->dma_filter = pxa2xx_spi_idma_filter;
}
ssp->clk = devm_clk_get(&pdev->dev, NULL); ssp->clk = devm_clk_get(&pdev->dev, NULL);
ssp->irq = platform_get_irq(pdev, 0); ssp->irq = platform_get_irq(pdev, 0);
ssp->type = type; ssp->type = type;
...@@ -1362,8 +1414,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1362,8 +1414,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
/* Allocate master with space for drv_data and null dma buffer */ master = spi_alloc_master(dev, sizeof(struct driver_data));
master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
if (!master) { if (!master) {
dev_err(&pdev->dev, "cannot alloc spi_master\n"); dev_err(&pdev->dev, "cannot alloc spi_master\n");
pxa_ssp_free(ssp); pxa_ssp_free(ssp);
...@@ -1390,7 +1441,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1390,7 +1441,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
drv_data->ssp_type = ssp->type; drv_data->ssp_type = ssp->type;
drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
drv_data->ioaddr = ssp->mmio_base; drv_data->ioaddr = ssp->mmio_base;
drv_data->ssdr_physical = ssp->phys_base + SSDR; drv_data->ssdr_physical = ssp->phys_base + SSDR;
...@@ -1424,8 +1474,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1424,8 +1474,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
} }
/* Setup DMA if requested */ /* Setup DMA if requested */
drv_data->tx_channel = -1;
drv_data->rx_channel = -1;
if (platform_info->enable_dma) { if (platform_info->enable_dma) {
status = pxa2xx_spi_dma_setup(drv_data); status = pxa2xx_spi_dma_setup(drv_data);
if (status) { if (status) {
......
...@@ -36,11 +36,6 @@ struct driver_data { ...@@ -36,11 +36,6 @@ struct driver_data {
/* PXA hookup */ /* PXA hookup */
struct pxa2xx_spi_master *master_info; struct pxa2xx_spi_master *master_info;
/* PXA private DMA setup stuff */
int rx_channel;
int tx_channel;
u32 *null_dma_buf;
/* SSP register addresses */ /* SSP register addresses */
void __iomem *ioaddr; void __iomem *ioaddr;
u32 ssdr_physical; u32 ssdr_physical;
......
...@@ -645,7 +645,6 @@ static int rockchip_spi_probe(struct platform_device *pdev) ...@@ -645,7 +645,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
rs = spi_master_get_devdata(master); rs = spi_master_get_devdata(master);
memset(rs, 0, sizeof(struct rockchip_spi));
/* Get basic io resource and map it */ /* Get basic io resource and map it */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......
...@@ -383,7 +383,8 @@ static void qspi_update(const struct rspi_data *rspi, u8 mask, u8 val, u8 reg) ...@@ -383,7 +383,8 @@ static void qspi_update(const struct rspi_data *rspi, u8 mask, u8 val, u8 reg)
rspi_write8(rspi, data, reg); rspi_write8(rspi, data, reg);
} }
static int qspi_set_send_trigger(struct rspi_data *rspi, unsigned int len) static unsigned int qspi_set_send_trigger(struct rspi_data *rspi,
unsigned int len)
{ {
unsigned int n; unsigned int n;
...@@ -724,25 +725,25 @@ static int rspi_rz_transfer_one(struct spi_master *master, ...@@ -724,25 +725,25 @@ static int rspi_rz_transfer_one(struct spi_master *master,
static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx, static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx,
u8 *rx, unsigned int len) u8 *rx, unsigned int len)
{ {
int i, n, ret; unsigned int i, n;
int error; int ret;
while (len > 0) { while (len > 0) {
n = qspi_set_send_trigger(rspi, len); n = qspi_set_send_trigger(rspi, len);
qspi_set_receive_trigger(rspi, len); qspi_set_receive_trigger(rspi, len);
if (n == QSPI_BUFFER_SIZE) { if (n == QSPI_BUFFER_SIZE) {
error = rspi_wait_for_tx_empty(rspi); ret = rspi_wait_for_tx_empty(rspi);
if (error < 0) { if (ret < 0) {
dev_err(&rspi->master->dev, "transmit timeout\n"); dev_err(&rspi->master->dev, "transmit timeout\n");
return error; return ret;
} }
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
rspi_write_data(rspi, *tx++); rspi_write_data(rspi, *tx++);
error = rspi_wait_for_rx_full(rspi); ret = rspi_wait_for_rx_full(rspi);
if (error < 0) { if (ret < 0) {
dev_err(&rspi->master->dev, "receive timeout\n"); dev_err(&rspi->master->dev, "receive timeout\n");
return error; return ret;
} }
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
*rx++ = rspi_read_data(rspi); *rx++ = rspi_read_data(rspi);
......
...@@ -501,7 +501,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) ...@@ -501,7 +501,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
} }
hw = spi_master_get_devdata(master); hw = spi_master_get_devdata(master);
memset(hw, 0, sizeof(struct s3c24xx_spi));
hw->master = master; hw->master = master;
hw->pdata = pdata = dev_get_platdata(&pdev->dev); hw->pdata = pdata = dev_get_platdata(&pdev->dev);
......
...@@ -1191,8 +1191,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) ...@@ -1191,8 +1191,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n", dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
sdd->port_id, master->num_chipselect); sdd->port_id, master->num_chipselect);
dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tDMA=[Rx-%d, Tx-%d]\n", dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\tDMA=[Rx-%d, Tx-%d]\n",
mem_res, mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1,
sdd->rx_dma.dmach, sdd->tx_dma.dmach); sdd->rx_dma.dmach, sdd->tx_dma.dmach);
return 0; return 0;
......
...@@ -48,8 +48,8 @@ struct sh_msiof_spi_priv { ...@@ -48,8 +48,8 @@ struct sh_msiof_spi_priv {
const struct sh_msiof_chipdata *chipdata; const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info; struct sh_msiof_spi_info *info;
struct completion done; struct completion done;
int tx_fifo_size; unsigned int tx_fifo_size;
int rx_fifo_size; unsigned int rx_fifo_size;
void *tx_dma_page; void *tx_dma_page;
void *rx_dma_page; void *rx_dma_page;
dma_addr_t tx_dma_addr; dma_addr_t tx_dma_addr;
...@@ -95,8 +95,6 @@ struct sh_msiof_spi_priv { ...@@ -95,8 +95,6 @@ struct sh_msiof_spi_priv {
#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ #define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ #define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */
#define MAX_WDLEN 256U
/* TSCR and RSCR */ /* TSCR and RSCR */
#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ #define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */
#define SCR_BRPS(i) (((i) - 1) << 8) #define SCR_BRPS(i) (((i) - 1) << 8)
...@@ -850,7 +848,12 @@ static int sh_msiof_transfer_one(struct spi_master *master, ...@@ -850,7 +848,12 @@ static int sh_msiof_transfer_one(struct spi_master *master,
* DMA supports 32-bit words only, hence pack 8-bit and 16-bit * DMA supports 32-bit words only, hence pack 8-bit and 16-bit
* words, with byte resp. word swapping. * words, with byte resp. word swapping.
*/ */
unsigned int l = min(len, MAX_WDLEN * 4); unsigned int l = 0;
if (tx_buf)
l = min(len, p->tx_fifo_size * 4);
if (rx_buf)
l = min(len, p->rx_fifo_size * 4);
if (bits <= 8) { if (bits <= 8) {
if (l & 3) if (l & 3)
...@@ -963,7 +966,7 @@ static const struct sh_msiof_chipdata sh_data = { ...@@ -963,7 +966,7 @@ static const struct sh_msiof_chipdata sh_data = {
static const struct sh_msiof_chipdata r8a779x_data = { static const struct sh_msiof_chipdata r8a779x_data = {
.tx_fifo_size = 64, .tx_fifo_size = 64,
.rx_fifo_size = 256, .rx_fifo_size = 64,
.master_flags = SPI_MASTER_MUST_TX, .master_flags = SPI_MASTER_MUST_TX,
}; };
...@@ -1265,11 +1268,6 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) ...@@ -1265,11 +1268,6 @@ static int sh_msiof_spi_remove(struct platform_device *pdev)
static const struct platform_device_id spi_driver_ids[] = { static const struct platform_device_id spi_driver_ids[] = {
{ "spi_sh_msiof", (kernel_ulong_t)&sh_data }, { "spi_sh_msiof", (kernel_ulong_t)&sh_data },
{ "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7792_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7793_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7794_msiof", (kernel_ulong_t)&r8a779x_data },
{}, {},
}; };
MODULE_DEVICE_TABLE(platform, spi_driver_ids); MODULE_DEVICE_TABLE(platform, spi_driver_ids);
......
...@@ -99,6 +99,8 @@ struct ti_qspi { ...@@ -99,6 +99,8 @@ struct ti_qspi {
#define QSPI_INVAL (4 << 16) #define QSPI_INVAL (4 << 16)
#define QSPI_WC_CMD_INT_EN (1 << 14) #define QSPI_WC_CMD_INT_EN (1 << 14)
#define QSPI_FLEN(n) ((n - 1) << 0) #define QSPI_FLEN(n) ((n - 1) << 0)
#define QSPI_WLEN_MAX_BITS 128
#define QSPI_WLEN_MAX_BYTES 16
/* STATUS REGISTER */ /* STATUS REGISTER */
#define BUSY 0x01 #define BUSY 0x01
...@@ -217,14 +219,16 @@ static inline u32 qspi_is_busy(struct ti_qspi *qspi) ...@@ -217,14 +219,16 @@ static inline u32 qspi_is_busy(struct ti_qspi *qspi)
static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
{ {
int wlen, count; int wlen, count, xfer_len;
unsigned int cmd; unsigned int cmd;
const u8 *txbuf; const u8 *txbuf;
u32 data;
txbuf = t->tx_buf; txbuf = t->tx_buf;
cmd = qspi->cmd | QSPI_WR_SNGL; cmd = qspi->cmd | QSPI_WR_SNGL;
count = t->len; count = t->len;
wlen = t->bits_per_word >> 3; /* in bytes */ wlen = t->bits_per_word >> 3; /* in bytes */
xfer_len = wlen;
while (count) { while (count) {
if (qspi_is_busy(qspi)) if (qspi_is_busy(qspi))
...@@ -234,7 +238,29 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) ...@@ -234,7 +238,29 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
case 1: case 1:
dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
cmd, qspi->dc, *txbuf); cmd, qspi->dc, *txbuf);
writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); if (count >= QSPI_WLEN_MAX_BYTES) {
u32 *txp = (u32 *)txbuf;
data = cpu_to_be32(*txp++);
writel(data, qspi->base +
QSPI_SPI_DATA_REG_3);
data = cpu_to_be32(*txp++);
writel(data, qspi->base +
QSPI_SPI_DATA_REG_2);
data = cpu_to_be32(*txp++);
writel(data, qspi->base +
QSPI_SPI_DATA_REG_1);
data = cpu_to_be32(*txp++);
writel(data, qspi->base +
QSPI_SPI_DATA_REG);
xfer_len = QSPI_WLEN_MAX_BYTES;
cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS);
} else {
writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG);
cmd = qspi->cmd | QSPI_WR_SNGL;
xfer_len = wlen;
cmd |= QSPI_WLEN(wlen);
}
break; break;
case 2: case 2:
dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n",
...@@ -254,8 +280,8 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) ...@@ -254,8 +280,8 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
dev_err(qspi->dev, "write timed out\n"); dev_err(qspi->dev, "write timed out\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
txbuf += wlen; txbuf += xfer_len;
count -= wlen; count -= xfer_len;
} }
return 0; return 0;
......
...@@ -237,11 +237,11 @@ static const struct i2c_device_id spi_xcomm_ids[] = { ...@@ -237,11 +237,11 @@ static const struct i2c_device_id spi_xcomm_ids[] = {
{ "spi-xcomm" }, { "spi-xcomm" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(i2c, spi_xcomm_ids);
static struct i2c_driver spi_xcomm_driver = { static struct i2c_driver spi_xcomm_driver = {
.driver = { .driver = {
.name = "spi-xcomm", .name = "spi-xcomm",
.owner = THIS_MODULE,
}, },
.id_table = spi_xcomm_ids, .id_table = spi_xcomm_ids,
.probe = spi_xcomm_probe, .probe = spi_xcomm_probe,
......
...@@ -249,19 +249,23 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ...@@ -249,19 +249,23 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
xspi->tx_ptr = t->tx_buf; xspi->tx_ptr = t->tx_buf;
xspi->rx_ptr = t->rx_buf; xspi->rx_ptr = t->rx_buf;
remaining_words = t->len / xspi->bytes_per_word; remaining_words = t->len / xspi->bytes_per_word;
reinit_completion(&xspi->done);
if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) { if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
u32 isr;
use_irq = true; use_irq = true;
xspi->write_fn(XSPI_INTR_TX_EMPTY,
xspi->regs + XIPIF_V123B_IISR_OFFSET);
/* Enable the global IPIF interrupt */
xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
xspi->regs + XIPIF_V123B_DGIER_OFFSET);
/* Inhibit irq to avoid spurious irqs on tx_empty*/ /* Inhibit irq to avoid spurious irqs on tx_empty*/
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
xspi->regs + XSPI_CR_OFFSET); xspi->regs + XSPI_CR_OFFSET);
/* ACK old irqs (if any) */
isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
if (isr)
xspi->write_fn(isr,
xspi->regs + XIPIF_V123B_IISR_OFFSET);
/* Enable the global IPIF interrupt */
xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
xspi->regs + XIPIF_V123B_DGIER_OFFSET);
reinit_completion(&xspi->done);
} }
while (remaining_words) { while (remaining_words) {
...@@ -302,8 +306,10 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ...@@ -302,8 +306,10 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
remaining_words -= n_words; remaining_words -= n_words;
} }
if (use_irq) if (use_irq) {
xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET); xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
}
return t->len; return t->len;
} }
......
/*
* Copyright (C) 2003-2015 Broadcom Corporation
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 (GPL v2)
* 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/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/interrupt.h>
/* SPI Configuration Register */
#define XLP_SPI_CONFIG 0x00
#define XLP_SPI_CPHA BIT(0)
#define XLP_SPI_CPOL BIT(1)
#define XLP_SPI_CS_POL BIT(2)
#define XLP_SPI_TXMISO_EN BIT(3)
#define XLP_SPI_TXMOSI_EN BIT(4)
#define XLP_SPI_RXMISO_EN BIT(5)
#define XLP_SPI_CS_LSBFE BIT(10)
#define XLP_SPI_RXCAP_EN BIT(11)
/* SPI Frequency Divider Register */
#define XLP_SPI_FDIV 0x04
/* SPI Command Register */
#define XLP_SPI_CMD 0x08
#define XLP_SPI_CMD_IDLE_MASK 0x0
#define XLP_SPI_CMD_TX_MASK 0x1
#define XLP_SPI_CMD_RX_MASK 0x2
#define XLP_SPI_CMD_TXRX_MASK 0x3
#define XLP_SPI_CMD_CONT BIT(4)
#define XLP_SPI_XFR_BITCNT_SHIFT 16
/* SPI Status Register */
#define XLP_SPI_STATUS 0x0c
#define XLP_SPI_XFR_PENDING BIT(0)
#define XLP_SPI_XFR_DONE BIT(1)
#define XLP_SPI_TX_INT BIT(2)
#define XLP_SPI_RX_INT BIT(3)
#define XLP_SPI_TX_UF BIT(4)
#define XLP_SPI_RX_OF BIT(5)
#define XLP_SPI_STAT_MASK 0x3f
/* SPI Interrupt Enable Register */
#define XLP_SPI_INTR_EN 0x10
#define XLP_SPI_INTR_DONE BIT(0)
#define XLP_SPI_INTR_TXTH BIT(1)
#define XLP_SPI_INTR_RXTH BIT(2)
#define XLP_SPI_INTR_TXUF BIT(3)
#define XLP_SPI_INTR_RXOF BIT(4)
/* SPI FIFO Threshold Register */
#define XLP_SPI_FIFO_THRESH 0x14
/* SPI FIFO Word Count Register */
#define XLP_SPI_FIFO_WCNT 0x18
#define XLP_SPI_RXFIFO_WCNT_MASK 0xf
#define XLP_SPI_TXFIFO_WCNT_MASK 0xf0
#define XLP_SPI_TXFIFO_WCNT_SHIFT 4
/* SPI Transmit Data FIFO Register */
#define XLP_SPI_TXDATA_FIFO 0x1c
/* SPI Receive Data FIFO Register */
#define XLP_SPI_RXDATA_FIFO 0x20
/* SPI System Control Register */
#define XLP_SPI_SYSCTRL 0x100
#define XLP_SPI_SYS_RESET BIT(0)
#define XLP_SPI_SYS_CLKDIS BIT(1)
#define XLP_SPI_SYS_PMEN BIT(8)
#define SPI_CS_OFFSET 0x40
#define XLP_SPI_TXRXTH 0x80
#define XLP_SPI_FIFO_SIZE 8
#define XLP_SPI_MAX_CS 4
#define XLP_SPI_DEFAULT_FREQ 133333333
#define XLP_SPI_FDIV_MIN 4
#define XLP_SPI_FDIV_MAX 65535
/*
* SPI can transfer only 28 bytes properly at a time. So split the
* transfer into 28 bytes size.
*/
#define XLP_SPI_XFER_SIZE 28
struct xlp_spi_priv {
struct device dev; /* device structure */
void __iomem *base; /* spi registers base address */
const u8 *tx_buf; /* tx data buffer */
u8 *rx_buf; /* rx data buffer */
int tx_len; /* tx xfer length */
int rx_len; /* rx xfer length */
int txerrors; /* TXFIFO underflow count */
int rxerrors; /* RXFIFO overflow count */
int cs; /* slave device chip select */
u32 spi_clk; /* spi clock frequency */
bool cmd_cont; /* cs active */
struct completion done; /* completion notification */
};
static inline u32 xlp_spi_reg_read(struct xlp_spi_priv *priv,
int cs, int regoff)
{
return readl(priv->base + regoff + cs * SPI_CS_OFFSET);
}
static inline void xlp_spi_reg_write(struct xlp_spi_priv *priv, int cs,
int regoff, u32 val)
{
writel(val, priv->base + regoff + cs * SPI_CS_OFFSET);
}
static inline void xlp_spi_sysctl_write(struct xlp_spi_priv *priv,
int regoff, u32 val)
{
writel(val, priv->base + regoff);
}
/*
* Setup global SPI_SYSCTRL register for all SPI channels.
*/
static void xlp_spi_sysctl_setup(struct xlp_spi_priv *xspi)
{
int cs;
for (cs = 0; cs < XLP_SPI_MAX_CS; cs++)
xlp_spi_sysctl_write(xspi, XLP_SPI_SYSCTRL,
XLP_SPI_SYS_RESET << cs);
xlp_spi_sysctl_write(xspi, XLP_SPI_SYSCTRL, XLP_SPI_SYS_PMEN);
}
static int xlp_spi_setup(struct spi_device *spi)
{
struct xlp_spi_priv *xspi;
u32 fdiv, cfg;
int cs;
xspi = spi_master_get_devdata(spi->master);
cs = spi->chip_select;
/*
* The value of fdiv must be between 4 and 65535.
*/
fdiv = DIV_ROUND_UP(xspi->spi_clk, spi->max_speed_hz);
if (fdiv > XLP_SPI_FDIV_MAX)
fdiv = XLP_SPI_FDIV_MAX;
else if (fdiv < XLP_SPI_FDIV_MIN)
fdiv = XLP_SPI_FDIV_MIN;
xlp_spi_reg_write(xspi, cs, XLP_SPI_FDIV, fdiv);
xlp_spi_reg_write(xspi, cs, XLP_SPI_FIFO_THRESH, XLP_SPI_TXRXTH);
cfg = xlp_spi_reg_read(xspi, cs, XLP_SPI_CONFIG);
if (spi->mode & SPI_CPHA)
cfg |= XLP_SPI_CPHA;
else
cfg &= ~XLP_SPI_CPHA;
if (spi->mode & SPI_CPOL)
cfg |= XLP_SPI_CPOL;
else
cfg &= ~XLP_SPI_CPOL;
if (!(spi->mode & SPI_CS_HIGH))
cfg |= XLP_SPI_CS_POL;
else
cfg &= ~XLP_SPI_CS_POL;
if (spi->mode & SPI_LSB_FIRST)
cfg |= XLP_SPI_CS_LSBFE;
else
cfg &= ~XLP_SPI_CS_LSBFE;
cfg |= XLP_SPI_TXMOSI_EN | XLP_SPI_RXMISO_EN;
if (fdiv == 4)
cfg |= XLP_SPI_RXCAP_EN;
xlp_spi_reg_write(xspi, cs, XLP_SPI_CONFIG, cfg);
return 0;
}
static void xlp_spi_read_rxfifo(struct xlp_spi_priv *xspi)
{
u32 rx_data, rxfifo_cnt;
int i, j, nbytes;
rxfifo_cnt = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_FIFO_WCNT);
rxfifo_cnt &= XLP_SPI_RXFIFO_WCNT_MASK;
while (rxfifo_cnt) {
rx_data = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_RXDATA_FIFO);
j = 0;
nbytes = min(xspi->rx_len, 4);
for (i = nbytes - 1; i >= 0; i--, j++)
xspi->rx_buf[i] = (rx_data >> (j * 8)) & 0xff;
xspi->rx_len -= nbytes;
xspi->rx_buf += nbytes;
rxfifo_cnt--;
}
}
static void xlp_spi_fill_txfifo(struct xlp_spi_priv *xspi)
{
u32 tx_data, txfifo_cnt;
int i, j, nbytes;
txfifo_cnt = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_FIFO_WCNT);
txfifo_cnt &= XLP_SPI_TXFIFO_WCNT_MASK;
txfifo_cnt >>= XLP_SPI_TXFIFO_WCNT_SHIFT;
while (xspi->tx_len && (txfifo_cnt < XLP_SPI_FIFO_SIZE)) {
j = 0;
tx_data = 0;
nbytes = min(xspi->tx_len, 4);
for (i = nbytes - 1; i >= 0; i--, j++)
tx_data |= xspi->tx_buf[i] << (j * 8);
xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_TXDATA_FIFO, tx_data);
xspi->tx_len -= nbytes;
xspi->tx_buf += nbytes;
txfifo_cnt++;
}
}
static irqreturn_t xlp_spi_interrupt(int irq, void *dev_id)
{
struct xlp_spi_priv *xspi = dev_id;
u32 stat;
stat = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_STATUS) &
XLP_SPI_STAT_MASK;
if (!stat)
return IRQ_NONE;
if (stat & XLP_SPI_TX_INT) {
if (xspi->tx_len)
xlp_spi_fill_txfifo(xspi);
if (stat & XLP_SPI_TX_UF)
xspi->txerrors++;
}
if (stat & XLP_SPI_RX_INT) {
if (xspi->rx_len)
xlp_spi_read_rxfifo(xspi);
if (stat & XLP_SPI_RX_OF)
xspi->rxerrors++;
}
/* write status back to clear interrupts */
xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_STATUS, stat);
if (stat & XLP_SPI_XFR_DONE)
complete(&xspi->done);
return IRQ_HANDLED;
}
static void xlp_spi_send_cmd(struct xlp_spi_priv *xspi, int xfer_len,
int cmd_cont)
{
u32 cmd = 0;
if (xspi->tx_buf)
cmd |= XLP_SPI_CMD_TX_MASK;
if (xspi->rx_buf)
cmd |= XLP_SPI_CMD_RX_MASK;
if (cmd_cont)
cmd |= XLP_SPI_CMD_CONT;
cmd |= ((xfer_len * 8 - 1) << XLP_SPI_XFR_BITCNT_SHIFT);
xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_CMD, cmd);
}
static int xlp_spi_xfer_block(struct xlp_spi_priv *xs,
const unsigned char *tx_buf,
unsigned char *rx_buf, int xfer_len, int cmd_cont)
{
int timeout;
u32 intr_mask = 0;
xs->tx_buf = tx_buf;
xs->rx_buf = rx_buf;
xs->tx_len = (xs->tx_buf == NULL) ? 0 : xfer_len;
xs->rx_len = (xs->rx_buf == NULL) ? 0 : xfer_len;
xs->txerrors = xs->rxerrors = 0;
/* fill TXDATA_FIFO, then send the CMD */
if (xs->tx_len)
xlp_spi_fill_txfifo(xs);
xlp_spi_send_cmd(xs, xfer_len, cmd_cont);
/*
* We are getting some spurious tx interrupts, so avoid enabling
* tx interrupts when only rx is in process.
* Enable all the interrupts in tx case.
*/
if (xs->tx_len)
intr_mask |= XLP_SPI_INTR_TXTH | XLP_SPI_INTR_TXUF |
XLP_SPI_INTR_RXTH | XLP_SPI_INTR_RXOF;
else
intr_mask |= XLP_SPI_INTR_RXTH | XLP_SPI_INTR_RXOF;
intr_mask |= XLP_SPI_INTR_DONE;
xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, intr_mask);
timeout = wait_for_completion_timeout(&xs->done,
msecs_to_jiffies(1000));
/* Disable interrupts */
xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, 0x0);
if (!timeout) {
dev_err(&xs->dev, "xfer timedout!\n");
goto out;
}
if (xs->txerrors || xs->rxerrors)
dev_err(&xs->dev, "Over/Underflow rx %d tx %d xfer %d!\n",
xs->rxerrors, xs->txerrors, xfer_len);
return xfer_len;
out:
return -ETIMEDOUT;
}
static int xlp_spi_txrx_bufs(struct xlp_spi_priv *xs, struct spi_transfer *t)
{
int bytesleft, sz;
unsigned char *rx_buf;
const unsigned char *tx_buf;
tx_buf = t->tx_buf;
rx_buf = t->rx_buf;
bytesleft = t->len;
while (bytesleft) {
if (bytesleft > XLP_SPI_XFER_SIZE)
sz = xlp_spi_xfer_block(xs, tx_buf, rx_buf,
XLP_SPI_XFER_SIZE, 1);
else
sz = xlp_spi_xfer_block(xs, tx_buf, rx_buf,
bytesleft, xs->cmd_cont);
if (sz < 0)
return sz;
bytesleft -= sz;
if (tx_buf)
tx_buf += sz;
if (rx_buf)
rx_buf += sz;
}
return bytesleft;
}
static int xlp_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *t)
{
struct xlp_spi_priv *xspi = spi_master_get_devdata(master);
int ret = 0;
xspi->cs = spi->chip_select;
xspi->dev = spi->dev;
if (spi_transfer_is_last(master, t))
xspi->cmd_cont = 0;
else
xspi->cmd_cont = 1;
if (xlp_spi_txrx_bufs(xspi, t))
ret = -EIO;
spi_finalize_current_transfer(master);
return ret;
}
static int xlp_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct xlp_spi_priv *xspi;
struct resource *res;
struct clk *clk;
int irq, err;
xspi = devm_kzalloc(&pdev->dev, sizeof(*xspi), GFP_KERNEL);
if (!xspi)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xspi->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xspi->base))
return PTR_ERR(xspi->base);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no IRQ resource found\n");
return -EINVAL;
}
err = devm_request_irq(&pdev->dev, irq, xlp_spi_interrupt, 0,
pdev->name, xspi);
if (err) {
dev_err(&pdev->dev, "unable to request irq %d\n", irq);
return err;
}
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "could not get spi clock\n");
return -ENODEV;
}
xspi->spi_clk = clk_get_rate(clk);
master = spi_alloc_master(&pdev->dev, 0);
if (!master) {
dev_err(&pdev->dev, "could not alloc master\n");
return -ENOMEM;
}
master->bus_num = 0;
master->num_chipselect = XLP_SPI_MAX_CS;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = xlp_spi_setup;
master->transfer_one = xlp_spi_transfer_one;
master->dev.of_node = pdev->dev.of_node;
init_completion(&xspi->done);
spi_master_set_devdata(master, xspi);
xlp_spi_sysctl_setup(xspi);
/* register spi controller */
err = devm_spi_register_master(&pdev->dev, master);
if (err) {
dev_err(&pdev->dev, "spi register master failed!\n");
spi_master_put(master);
return err;
}
return 0;
}
static const struct of_device_id xlp_spi_dt_id[] = {
{ .compatible = "netlogic,xlp832-spi" },
{ },
};
static struct platform_driver xlp_spi_driver = {
.probe = xlp_spi_probe,
.driver = {
.name = "xlp-spi",
.of_match_table = xlp_spi_dt_id,
},
};
module_platform_driver(xlp_spi_driver);
MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
MODULE_DESCRIPTION("Netlogic XLP SPI controller driver");
MODULE_LICENSE("GPL v2");
...@@ -67,11 +67,141 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf) ...@@ -67,11 +67,141 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
} }
static DEVICE_ATTR_RO(modalias); static DEVICE_ATTR_RO(modalias);
#define SPI_STATISTICS_ATTRS(field, file) \
static ssize_t spi_master_##field##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct spi_master *master = container_of(dev, \
struct spi_master, dev); \
return spi_statistics_##field##_show(&master->statistics, buf); \
} \
static struct device_attribute dev_attr_spi_master_##field = { \
.attr = { .name = file, .mode = S_IRUGO }, \
.show = spi_master_##field##_show, \
}; \
static ssize_t spi_device_##field##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct spi_device *spi = container_of(dev, \
struct spi_device, dev); \
return spi_statistics_##field##_show(&spi->statistics, buf); \
} \
static struct device_attribute dev_attr_spi_device_##field = { \
.attr = { .name = file, .mode = S_IRUGO }, \
.show = spi_device_##field##_show, \
}
#define SPI_STATISTICS_SHOW_NAME(name, file, field, format_string) \
static ssize_t spi_statistics_##name##_show(struct spi_statistics *stat, \
char *buf) \
{ \
unsigned long flags; \
ssize_t len; \
spin_lock_irqsave(&stat->lock, flags); \
len = sprintf(buf, format_string, stat->field); \
spin_unlock_irqrestore(&stat->lock, flags); \
return len; \
} \
SPI_STATISTICS_ATTRS(name, file)
#define SPI_STATISTICS_SHOW(field, format_string) \
SPI_STATISTICS_SHOW_NAME(field, __stringify(field), \
field, format_string)
SPI_STATISTICS_SHOW(messages, "%lu");
SPI_STATISTICS_SHOW(transfers, "%lu");
SPI_STATISTICS_SHOW(errors, "%lu");
SPI_STATISTICS_SHOW(timedout, "%lu");
SPI_STATISTICS_SHOW(spi_sync, "%lu");
SPI_STATISTICS_SHOW(spi_sync_immediate, "%lu");
SPI_STATISTICS_SHOW(spi_async, "%lu");
SPI_STATISTICS_SHOW(bytes, "%llu");
SPI_STATISTICS_SHOW(bytes_rx, "%llu");
SPI_STATISTICS_SHOW(bytes_tx, "%llu");
static struct attribute *spi_dev_attrs[] = { static struct attribute *spi_dev_attrs[] = {
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(spi_dev);
static const struct attribute_group spi_dev_group = {
.attrs = spi_dev_attrs,
};
static struct attribute *spi_device_statistics_attrs[] = {
&dev_attr_spi_device_messages.attr,
&dev_attr_spi_device_transfers.attr,
&dev_attr_spi_device_errors.attr,
&dev_attr_spi_device_timedout.attr,
&dev_attr_spi_device_spi_sync.attr,
&dev_attr_spi_device_spi_sync_immediate.attr,
&dev_attr_spi_device_spi_async.attr,
&dev_attr_spi_device_bytes.attr,
&dev_attr_spi_device_bytes_rx.attr,
&dev_attr_spi_device_bytes_tx.attr,
NULL,
};
static const struct attribute_group spi_device_statistics_group = {
.name = "statistics",
.attrs = spi_device_statistics_attrs,
};
static const struct attribute_group *spi_dev_groups[] = {
&spi_dev_group,
&spi_device_statistics_group,
NULL,
};
static struct attribute *spi_master_statistics_attrs[] = {
&dev_attr_spi_master_messages.attr,
&dev_attr_spi_master_transfers.attr,
&dev_attr_spi_master_errors.attr,
&dev_attr_spi_master_timedout.attr,
&dev_attr_spi_master_spi_sync.attr,
&dev_attr_spi_master_spi_sync_immediate.attr,
&dev_attr_spi_master_spi_async.attr,
&dev_attr_spi_master_bytes.attr,
&dev_attr_spi_master_bytes_rx.attr,
&dev_attr_spi_master_bytes_tx.attr,
NULL,
};
static const struct attribute_group spi_master_statistics_group = {
.name = "statistics",
.attrs = spi_master_statistics_attrs,
};
static const struct attribute_group *spi_master_groups[] = {
&spi_master_statistics_group,
NULL,
};
void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
struct spi_transfer *xfer,
struct spi_master *master)
{
unsigned long flags;
spin_lock_irqsave(&stats->lock, flags);
stats->transfers++;
stats->bytes += xfer->len;
if ((xfer->tx_buf) &&
(xfer->tx_buf != master->dummy_tx))
stats->bytes_tx += xfer->len;
if ((xfer->rx_buf) &&
(xfer->rx_buf != master->dummy_rx))
stats->bytes_rx += xfer->len;
spin_unlock_irqrestore(&stats->lock, flags);
}
EXPORT_SYMBOL_GPL(spi_statistics_add_transfer_stats);
/* modalias support makes "modprobe $MODALIAS" new-style hotplug work, /* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
* and the sysfs version makes coldplug work too. * and the sysfs version makes coldplug work too.
...@@ -249,6 +379,9 @@ struct spi_device *spi_alloc_device(struct spi_master *master) ...@@ -249,6 +379,9 @@ struct spi_device *spi_alloc_device(struct spi_master *master)
spi->dev.bus = &spi_bus_type; spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release; spi->dev.release = spidev_release;
spi->cs_gpio = -ENOENT; spi->cs_gpio = -ENOENT;
spin_lock_init(&spi->statistics.lock);
device_initialize(&spi->dev); device_initialize(&spi->dev);
return spi; return spi;
} }
...@@ -476,21 +609,30 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, ...@@ -476,21 +609,30 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
const bool vmalloced_buf = is_vmalloc_addr(buf); const bool vmalloced_buf = is_vmalloc_addr(buf);
const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len; int desc_len;
const int sgs = DIV_ROUND_UP(len, desc_len); int sgs;
struct page *vm_page; struct page *vm_page;
void *sg_buf; void *sg_buf;
size_t min; size_t min;
int i, ret; int i, ret;
if (vmalloced_buf) {
desc_len = PAGE_SIZE;
sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len);
} else {
desc_len = master->max_dma_len;
sgs = DIV_ROUND_UP(len, desc_len);
}
ret = sg_alloc_table(sgt, sgs, GFP_KERNEL); ret = sg_alloc_table(sgt, sgs, GFP_KERNEL);
if (ret != 0) if (ret != 0)
return ret; return ret;
for (i = 0; i < sgs; i++) { for (i = 0; i < sgs; i++) {
min = min_t(size_t, len, desc_len);
if (vmalloced_buf) { if (vmalloced_buf) {
min = min_t(size_t,
len, desc_len - offset_in_page(buf));
vm_page = vmalloc_to_page(buf); vm_page = vmalloc_to_page(buf);
if (!vm_page) { if (!vm_page) {
sg_free_table(sgt); sg_free_table(sgt);
...@@ -499,6 +641,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, ...@@ -499,6 +641,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
sg_set_page(&sgt->sgl[i], vm_page, sg_set_page(&sgt->sgl[i], vm_page,
min, offset_in_page(buf)); min, offset_in_page(buf));
} else { } else {
min = min_t(size_t, len, desc_len);
sg_buf = buf; sg_buf = buf;
sg_set_buf(&sgt->sgl[i], sg_buf, min); sg_set_buf(&sgt->sgl[i], sg_buf, min);
} }
...@@ -539,8 +682,15 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) ...@@ -539,8 +682,15 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg)
if (!master->can_dma) if (!master->can_dma)
return 0; return 0;
tx_dev = master->dma_tx->device->dev; if (master->dma_tx)
rx_dev = master->dma_rx->device->dev; tx_dev = master->dma_tx->device->dev;
else
tx_dev = &master->dev;
if (master->dma_rx)
rx_dev = master->dma_rx->device->dev;
else
rx_dev = &master->dev;
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (!master->can_dma(master, msg->spi, xfer)) if (!master->can_dma(master, msg->spi, xfer))
...@@ -579,8 +729,15 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) ...@@ -579,8 +729,15 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
if (!master->cur_msg_mapped || !master->can_dma) if (!master->cur_msg_mapped || !master->can_dma)
return 0; return 0;
tx_dev = master->dma_tx->device->dev; if (master->dma_tx)
rx_dev = master->dma_rx->device->dev; tx_dev = master->dma_tx->device->dev;
else
tx_dev = &master->dev;
if (master->dma_rx)
rx_dev = master->dma_rx->device->dev;
else
rx_dev = &master->dev;
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (!master->can_dma(master, msg->spi, xfer)) if (!master->can_dma(master, msg->spi, xfer))
...@@ -689,17 +846,29 @@ static int spi_transfer_one_message(struct spi_master *master, ...@@ -689,17 +846,29 @@ static int spi_transfer_one_message(struct spi_master *master,
bool keep_cs = false; bool keep_cs = false;
int ret = 0; int ret = 0;
unsigned long ms = 1; unsigned long ms = 1;
struct spi_statistics *statm = &master->statistics;
struct spi_statistics *stats = &msg->spi->statistics;
spi_set_cs(msg->spi, true); spi_set_cs(msg->spi, true);
SPI_STATISTICS_INCREMENT_FIELD(statm, messages);
SPI_STATISTICS_INCREMENT_FIELD(stats, messages);
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
trace_spi_transfer_start(msg, xfer); trace_spi_transfer_start(msg, xfer);
spi_statistics_add_transfer_stats(statm, xfer, master);
spi_statistics_add_transfer_stats(stats, xfer, master);
if (xfer->tx_buf || xfer->rx_buf) { if (xfer->tx_buf || xfer->rx_buf) {
reinit_completion(&master->xfer_completion); reinit_completion(&master->xfer_completion);
ret = master->transfer_one(master, msg->spi, xfer); ret = master->transfer_one(master, msg->spi, xfer);
if (ret < 0) { if (ret < 0) {
SPI_STATISTICS_INCREMENT_FIELD(statm,
errors);
SPI_STATISTICS_INCREMENT_FIELD(stats,
errors);
dev_err(&msg->spi->dev, dev_err(&msg->spi->dev,
"SPI transfer failed: %d\n", ret); "SPI transfer failed: %d\n", ret);
goto out; goto out;
...@@ -715,6 +884,10 @@ static int spi_transfer_one_message(struct spi_master *master, ...@@ -715,6 +884,10 @@ static int spi_transfer_one_message(struct spi_master *master,
} }
if (ms == 0) { if (ms == 0) {
SPI_STATISTICS_INCREMENT_FIELD(statm,
timedout);
SPI_STATISTICS_INCREMENT_FIELD(stats,
timedout);
dev_err(&msg->spi->dev, dev_err(&msg->spi->dev,
"SPI transfer timed out\n"); "SPI transfer timed out\n");
msg->status = -ETIMEDOUT; msg->status = -ETIMEDOUT;
...@@ -1416,10 +1589,10 @@ static struct class spi_master_class = { ...@@ -1416,10 +1589,10 @@ static struct class spi_master_class = {
.name = "spi_master", .name = "spi_master",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dev_release = spi_master_release, .dev_release = spi_master_release,
.dev_groups = spi_master_groups,
}; };
/** /**
* spi_alloc_master - allocate SPI master controller * spi_alloc_master - allocate SPI master controller
* @dev: the controller, possibly using the platform_bus * @dev: the controller, possibly using the platform_bus
...@@ -1585,6 +1758,8 @@ int spi_register_master(struct spi_master *master) ...@@ -1585,6 +1758,8 @@ int spi_register_master(struct spi_master *master)
goto done; goto done;
} }
} }
/* add statistics */
spin_lock_init(&master->statistics.lock);
mutex_lock(&board_lock); mutex_lock(&board_lock);
list_add_tail(&master->list, &spi_master_list); list_add_tail(&master->list, &spi_master_list);
...@@ -1740,6 +1915,20 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master); ...@@ -1740,6 +1915,20 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
* other core methods are currently defined as inline functions. * other core methods are currently defined as inline functions.
*/ */
static int __spi_validate_bits_per_word(struct spi_master *master, u8 bits_per_word)
{
if (master->bits_per_word_mask) {
/* Only 32 bits fit in the mask */
if (bits_per_word > 32)
return -EINVAL;
if (!(master->bits_per_word_mask &
SPI_BPW_MASK(bits_per_word)))
return -EINVAL;
}
return 0;
}
/** /**
* spi_setup - setup SPI mode and clock rate * spi_setup - setup SPI mode and clock rate
* @spi: the device whose settings are being modified * @spi: the device whose settings are being modified
...@@ -1798,6 +1987,9 @@ int spi_setup(struct spi_device *spi) ...@@ -1798,6 +1987,9 @@ int spi_setup(struct spi_device *spi)
if (!spi->bits_per_word) if (!spi->bits_per_word)
spi->bits_per_word = 8; spi->bits_per_word = 8;
if (__spi_validate_bits_per_word(spi->master, spi->bits_per_word))
return -EINVAL;
if (!spi->max_speed_hz) if (!spi->max_speed_hz)
spi->max_speed_hz = spi->master->max_speed_hz; spi->max_speed_hz = spi->master->max_speed_hz;
...@@ -1860,19 +2052,15 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) ...@@ -1860,19 +2052,15 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
if (!xfer->speed_hz) if (!xfer->speed_hz)
xfer->speed_hz = spi->max_speed_hz; xfer->speed_hz = spi->max_speed_hz;
if (!xfer->speed_hz)
xfer->speed_hz = master->max_speed_hz;
if (master->max_speed_hz && if (master->max_speed_hz &&
xfer->speed_hz > master->max_speed_hz) xfer->speed_hz > master->max_speed_hz)
xfer->speed_hz = master->max_speed_hz; xfer->speed_hz = master->max_speed_hz;
if (master->bits_per_word_mask) { if (__spi_validate_bits_per_word(master, xfer->bits_per_word))
/* Only 32 bits fit in the mask */ return -EINVAL;
if (xfer->bits_per_word > 32)
return -EINVAL;
if (!(master->bits_per_word_mask &
BIT(xfer->bits_per_word - 1)))
return -EINVAL;
}
/* /*
* SPI transfer length should be multiple of SPI word size * SPI transfer length should be multiple of SPI word size
...@@ -1939,6 +2127,9 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) ...@@ -1939,6 +2127,9 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
message->spi = spi; message->spi = spi;
SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_async);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_async);
trace_spi_message_submit(message); trace_spi_message_submit(message);
return master->transfer(spi, message); return master->transfer(spi, message);
...@@ -2075,6 +2266,9 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, ...@@ -2075,6 +2266,9 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
message->context = &done; message->context = &done;
message->spi = spi; message->spi = spi;
SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
if (!bus_locked) if (!bus_locked)
mutex_lock(&master->bus_lock_mutex); mutex_lock(&master->bus_lock_mutex);
...@@ -2102,8 +2296,13 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, ...@@ -2102,8 +2296,13 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
/* Push out the messages in the calling context if we /* Push out the messages in the calling context if we
* can. * can.
*/ */
if (master->transfer == spi_queued_transfer) if (master->transfer == spi_queued_transfer) {
SPI_STATISTICS_INCREMENT_FIELD(&master->statistics,
spi_sync_immediate);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
spi_sync_immediate);
__spi_pump_messages(master, false); __spi_pump_messages(master, false);
}
wait_for_completion(&done); wait_for_completion(&done);
status = message->status; status = message->status;
......
...@@ -602,11 +602,11 @@ static int spidev_open(struct inode *inode, struct file *filp) ...@@ -602,11 +602,11 @@ static int spidev_open(struct inode *inode, struct file *filp)
if (!spidev->tx_buffer) { if (!spidev->tx_buffer) {
spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL);
if (!spidev->tx_buffer) { if (!spidev->tx_buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
status = -ENOMEM; status = -ENOMEM;
goto err_find_dev; goto err_find_dev;
}
} }
}
if (!spidev->rx_buffer) { if (!spidev->rx_buffer) {
spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);
...@@ -709,7 +709,7 @@ static int spidev_probe(struct spi_device *spi) ...@@ -709,7 +709,7 @@ static int spidev_probe(struct spi_device *spi)
/* /*
* spidev should never be referenced in DT without a specific * spidev should never be referenced in DT without a specific
* compatbile string, it is a Linux implementation thing * compatible string, it is a Linux implementation thing
* rather than a description of the hardware. * rather than a description of the hardware.
*/ */
if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) { if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
......
...@@ -49,6 +49,7 @@ struct davinci_spi_platform_data { ...@@ -49,6 +49,7 @@ struct davinci_spi_platform_data {
u8 num_chipselect; u8 num_chipselect;
u8 intr_line; u8 intr_line;
u8 *chip_sel; u8 *chip_sel;
u8 prescaler_limit;
bool cshold_bug; bool cshold_bug;
enum dma_event_q dma_event_q; enum dma_event_q dma_event_q;
}; };
......
/*
* MTK SPI bus driver definitions
*
* Copyright (c) 2015 MediaTek Inc.
* Author: Leilk Liu <leilk.liu@mediatek.com>
*
* 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.
*/
#ifndef ____LINUX_PLATFORM_DATA_SPI_MTK_H
#define ____LINUX_PLATFORM_DATA_SPI_MTK_H
/* Board specific platform_data */
struct mtk_chip_config {
u32 tx_mlsb;
u32 rx_mlsb;
};
#endif
...@@ -197,6 +197,7 @@ enum pxa_ssp_type { ...@@ -197,6 +197,7 @@ enum pxa_ssp_type {
QUARK_X1000_SSP, QUARK_X1000_SSP,
LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */ LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */
LPSS_BYT_SSP, LPSS_BYT_SSP,
LPSS_SPT_SSP,
}; };
struct ssp_device { struct ssp_device {
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
struct dma_chan; struct dma_chan;
struct spi_master;
struct spi_transfer;
/* /*
* INTERFACES between SPI master-side drivers and SPI infrastructure. * INTERFACES between SPI master-side drivers and SPI infrastructure.
...@@ -30,6 +32,59 @@ struct dma_chan; ...@@ -30,6 +32,59 @@ struct dma_chan;
*/ */
extern struct bus_type spi_bus_type; extern struct bus_type spi_bus_type;
/**
* struct spi_statistics - statistics for spi transfers
* @clock: lock protecting this structure
*
* @messages: number of spi-messages handled
* @transfers: number of spi_transfers handled
* @errors: number of errors during spi_transfer
* @timedout: number of timeouts during spi_transfer
*
* @spi_sync: number of times spi_sync is used
* @spi_sync_immediate:
* number of times spi_sync is executed immediately
* in calling context without queuing and scheduling
* @spi_async: number of times spi_async is used
*
* @bytes: number of bytes transferred to/from device
* @bytes_tx: number of bytes sent to device
* @bytes_rx: number of bytes received from device
*
*/
struct spi_statistics {
spinlock_t lock; /* lock for the whole structure */
unsigned long messages;
unsigned long transfers;
unsigned long errors;
unsigned long timedout;
unsigned long spi_sync;
unsigned long spi_sync_immediate;
unsigned long spi_async;
unsigned long long bytes;
unsigned long long bytes_rx;
unsigned long long bytes_tx;
};
void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
struct spi_transfer *xfer,
struct spi_master *master);
#define SPI_STATISTICS_ADD_TO_FIELD(stats, field, count) \
do { \
unsigned long flags; \
spin_lock_irqsave(&(stats)->lock, flags); \
(stats)->field += count; \
spin_unlock_irqrestore(&(stats)->lock, flags); \
} while (0)
#define SPI_STATISTICS_INCREMENT_FIELD(stats, field) \
SPI_STATISTICS_ADD_TO_FIELD(stats, field, 1)
/** /**
* struct spi_device - Master side proxy for an SPI slave device * struct spi_device - Master side proxy for an SPI slave device
* @dev: Driver model representation of the device. * @dev: Driver model representation of the device.
...@@ -60,6 +115,8 @@ extern struct bus_type spi_bus_type; ...@@ -60,6 +115,8 @@ extern struct bus_type spi_bus_type;
* @cs_gpio: gpio number of the chipselect line (optional, -ENOENT when * @cs_gpio: gpio number of the chipselect line (optional, -ENOENT when
* when not using a GPIO line) * when not using a GPIO line)
* *
* @statistics: statistics for the spi_device
*
* A @spi_device is used to interchange data between an SPI slave * A @spi_device is used to interchange data between an SPI slave
* (usually a discrete chip) and CPU memory. * (usually a discrete chip) and CPU memory.
* *
...@@ -98,6 +155,9 @@ struct spi_device { ...@@ -98,6 +155,9 @@ struct spi_device {
char modalias[SPI_NAME_SIZE]; char modalias[SPI_NAME_SIZE];
int cs_gpio; /* chip select gpio */ int cs_gpio; /* chip select gpio */
/* the statistics */
struct spi_statistics statistics;
/* /*
* likely need more hooks for more protocol options affecting how * likely need more hooks for more protocol options affecting how
* the controller talks to each chip, like: * the controller talks to each chip, like:
...@@ -296,6 +356,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) ...@@ -296,6 +356,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
* number. Any individual value may be -ENOENT for CS lines that * number. Any individual value may be -ENOENT for CS lines that
* are not GPIOs (driven by the SPI controller itself). * are not GPIOs (driven by the SPI controller itself).
* @statistics: statistics for the spi_master
* @dma_tx: DMA transmit channel * @dma_tx: DMA transmit channel
* @dma_rx: DMA receive channel * @dma_rx: DMA receive channel
* @dummy_rx: dummy receive buffer for full-duplex devices * @dummy_rx: dummy receive buffer for full-duplex devices
...@@ -452,6 +513,9 @@ struct spi_master { ...@@ -452,6 +513,9 @@ struct spi_master {
/* gpio chip select */ /* gpio chip select */
int *cs_gpios; int *cs_gpios;
/* statistics */
struct spi_statistics statistics;
/* DMA channels for use with core dmaengine helpers */ /* DMA channels for use with core dmaengine helpers */
struct dma_chan *dma_tx; struct dma_chan *dma_tx;
struct dma_chan *dma_rx; struct dma_chan *dma_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