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

Pull spi updates from Mark Brown:
 "A fairly quiet release for SPI, nothing really going on in the core
  although there's been quite a bit of driver related activity.

  This includes the addition of some shared code in drivers/memory for
  the Renesas RPC-IF which is used by a newly added SPI driver, the
  memory subsystem doesn't seem to have a fixed maintainer at the minute
  and this seemed like the most sensible way to get that hardware
  supported.

   - Quite a few cleanups and optimizations for the Altera, Qualcomm
     GENI, sun6i and lantiq drivers.

   - Several more GPIO descriptor conversions.

   - Move the Cadence QuadSPI driver from drivers/mtd to drivers/spi.

   - New support for Mediatek MT8192 and Renesas RPC-IF, R8A7742 and
     R8A774e1"

* tag 'spi-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (119 commits)
  dt-bindings: lpspi: New property in document DT bindings for LPSPI
  spi: lpspi: fix using CS discontinuously on i.MX8DXLEVK
  spi: lpspi: remove unused fsl_lpspi->chipselect
  spi: lpspi: Fix kernel warning dump when probe fail after calling spi_register
  spi: rockchip: Fix error in SPI slave pio read
  spi: rockchip: Support 64-location deep FIFOs
  spi: rockchip: Config spi rx dma burst size depend on xfer length
  spi: spi-topcliff-pch: drop call to wakeup-disable
  spi: spidev: Align buffers for DMA
  spi: correct kernel-doc inconsistency
  spi: sun4i: update max transfer size reported
  spi: imx: enable runtime pm support
  spi: update bindings for MT8192 SoC
  spi: mediatek: add spi support for mt8192 IC
  spi: Add bindings for Lightning Mountain SoC
  spi: lantiq: Add support to Lightning Mountain SoC
  spi: lantiq: Move interrupt configuration to SoC specific data structure
  spi: lantiq: Add fifo size bit mask in SoC specific data structure
  spi: lantiq: Add support to acknowledge interrupt
  spi: lantiq: Move interrupt control register offesets to SoC specific data structure
  ...
This commit is contained in:
Linus Torvalds
2020-08-03 20:08:51 -07:00
88 changed files with 2518 additions and 1374 deletions

View File

@@ -59,6 +59,7 @@ comment "SPI Master Controller Drivers"
config SPI_ALTERA
tristate "Altera SPI Controller"
select REGMAP_MMIO
help
This is the driver for the Altera SPI Controller.
@@ -102,7 +103,7 @@ config SPI_AT91_USART
config SPI_ATMEL_QUADSPI
tristate "Atmel Quad SPI Controller"
depends on ARCH_AT91 || (ARM && COMPILE_TEST && !ARCH_EBSA110)
depends on ARCH_AT91 || COMPILE_TEST
depends on OF && HAS_IOMEM
help
This enables support for the Quad SPI controller in master mode.
@@ -149,13 +150,13 @@ config SPI_BCM2835AUX
config SPI_BCM63XX
tristate "Broadcom BCM63xx SPI controller"
depends on BCM63XX || COMPILE_TEST
depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
help
Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
config SPI_BCM63XX_HSSPI
tristate "Broadcom BCM63XX HS SPI controller driver"
depends on BCM63XX || ARCH_BCM_63XX || COMPILE_TEST
depends on BCM63XX || BMIPS_GENERIC || ARCH_BCM_63XX || COMPILE_TEST
help
This enables support for the High Speed SPI controller present on
newer Broadcom BCM63XX SoCs.
@@ -168,7 +169,7 @@ config SPI_BCM_QSPI
help
Enables support for the Broadcom SPI flash and MSPI controller.
Select this option for any one of BRCMSTB, iProc NSP and NS2 SoCs
based platforms. This driver works for both SPI master for spi-nor
based platforms. This driver works for both SPI master for SPI NOR
flash device as well as MSPI device.
config SPI_BITBANG
@@ -200,6 +201,17 @@ config SPI_CADENCE
This selects the Cadence SPI controller master driver
used by Xilinx Zynq and ZynqMP.
config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller"
depends on OF && (ARM || ARM64 || COMPILE_TEST)
help
Enable support for the Cadence Quad SPI Flash controller.
Cadence QSPI is a specialized controller for connecting an SPI
Flash over 1/2/4-bit wide bus. Enable this option if you have a
device with a Cadence QSPI controller and want to access the
Flash as an MTD device.
config SPI_CLPS711X
tristate "CLPS711X host SPI controller"
depends on ARCH_CLPS711X || COMPILE_TEST
@@ -299,11 +311,11 @@ config SPI_FSL_QUADSPI
supports the high-level SPI memory interface.
config SPI_HISI_SFC_V3XX
tristate "HiSilicon SPI-NOR Flash Controller for Hi16XX chipsets"
tristate "HiSilicon SPI NOR Flash Controller for Hi16XX chipsets"
depends on (ARM64 && ACPI) || COMPILE_TEST
depends on HAS_IOMEM
help
This enables support for HiSilicon v3xx SPI-NOR flash controller
This enables support for HiSilicon v3xx SPI NOR flash controller
found in hi16xx chipsets.
config SPI_NXP_FLEXSPI
@@ -465,9 +477,9 @@ config SPI_MTK_NOR
depends on ARCH_MEDIATEK || COMPILE_TEST
help
This enables support for SPI NOR controller found on MediaTek
ARM SoCs. This is a controller specifically for SPI-NOR flash.
ARM SoCs. This is a controller specifically for SPI NOR flash.
It can perform generic SPI transfers up to 6 bytes via generic
SPI interface as well as several SPI-NOR specific instructions
SPI interface as well as several SPI NOR specific instructions
via SPI MEM interface.
config SPI_NPCM_FIU
@@ -489,11 +501,11 @@ config SPI_NPCM_PSPI
config SPI_LANTIQ_SSC
tristate "Lantiq SSC SPI controller"
depends on LANTIQ || COMPILE_TEST
depends on LANTIQ || X86 || COMPILE_TEST
help
This driver supports the Lantiq SSC SPI controller in master
mode. This controller is found on Intel (former Lantiq) SoCs like
the Danube, Falcon, xRX200, xRX300.
the Danube, Falcon, xRX200, xRX300, Lightning Mountain.
config SPI_OC_TINY
tristate "OpenCores tiny SPI"
@@ -605,6 +617,12 @@ config SPI_RB4XX
help
SPI controller driver for the Mikrotik RB4xx series boards.
config SPI_RPCIF
tristate "Renesas RPC-IF SPI driver"
depends on RENESAS_RPCIF
help
SPI driver for Renesas R-Car Gen3 RPC-IF.
config SPI_RSPI
tristate "Renesas RSPI/QSPI controller"
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST

View File

@@ -31,6 +31,7 @@ obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
@@ -92,6 +93,7 @@ obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o

View File

@@ -285,6 +285,12 @@ static bool atmel_qspi_supports_op(struct spi_mem *mem,
op->dummy.nbytes == 0)
return false;
/* DTR ops not supported. */
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
return false;
if (op->cmd.nbytes != 1)
return false;
return true;
}
@@ -424,11 +430,11 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
/* Send/Receive data */
if (op->data.dir == SPI_MEM_DATA_IN)
_memcpy_fromio(op->data.buf.in, aq->mem + offset,
op->data.nbytes);
memcpy_fromio(op->data.buf.in, aq->mem + offset,
op->data.nbytes);
else
_memcpy_toio(aq->mem + offset, op->data.buf.out,
op->data.nbytes);
memcpy_toio(aq->mem + offset, op->data.buf.out,
op->data.nbytes);
/* Release the chip-select */
atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);

View File

@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/altera.h>
#include <linux/spi/spi.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -40,19 +41,61 @@
#define ALTERA_SPI_CONTROL_IE_MSK 0x100
#define ALTERA_SPI_CONTROL_SSO_MSK 0x400
#define ALTERA_SPI_MAX_CS 32
enum altera_spi_type {
ALTERA_SPI_TYPE_UNKNOWN,
ALTERA_SPI_TYPE_SUBDEV,
};
struct altera_spi {
void __iomem *base;
int irq;
int len;
int count;
int bytes_per_word;
unsigned long imr;
u32 imr;
/* data buffers */
const unsigned char *tx;
unsigned char *rx;
struct regmap *regmap;
u32 regoff;
struct device *dev;
};
static const struct regmap_config spi_altera_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
};
static int altr_spi_writel(struct altera_spi *hw, unsigned int reg,
unsigned int val)
{
int ret;
ret = regmap_write(hw->regmap, hw->regoff + reg, val);
if (ret)
dev_err(hw->dev, "fail to write reg 0x%x val 0x%x: %d\n",
reg, val, ret);
return ret;
}
static int altr_spi_readl(struct altera_spi *hw, unsigned int reg,
unsigned int *val)
{
int ret;
ret = regmap_read(hw->regmap, hw->regoff + reg, val);
if (ret)
dev_err(hw->dev, "fail to read reg 0x%x: %d\n", reg, ret);
return ret;
}
static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
{
return spi_master_get_devdata(sdev->master);
@@ -64,12 +107,13 @@ static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
if (is_high) {
hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
writel(0, hw->base + ALTERA_SPI_SLAVE_SEL);
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, 0);
} else {
writel(BIT(spi->chip_select), hw->base + ALTERA_SPI_SLAVE_SEL);
altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL,
BIT(spi->chip_select));
hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
}
}
@@ -86,17 +130,24 @@ static void altera_spi_tx_word(struct altera_spi *hw)
txd = (hw->tx[hw->count * 2]
| (hw->tx[hw->count * 2 + 1] << 8));
break;
case 4:
txd = (hw->tx[hw->count * 4]
| (hw->tx[hw->count * 4 + 1] << 8)
| (hw->tx[hw->count * 4 + 2] << 16)
| (hw->tx[hw->count * 4 + 3] << 24));
break;
}
}
writel(txd, hw->base + ALTERA_SPI_TXDATA);
altr_spi_writel(hw, ALTERA_SPI_TXDATA, txd);
}
static void altera_spi_rx_word(struct altera_spi *hw)
{
unsigned int rxd;
rxd = readl(hw->base + ALTERA_SPI_RXDATA);
altr_spi_readl(hw, ALTERA_SPI_RXDATA, &rxd);
if (hw->rx) {
switch (hw->bytes_per_word) {
case 1:
@@ -106,6 +157,13 @@ static void altera_spi_rx_word(struct altera_spi *hw)
hw->rx[hw->count * 2] = rxd;
hw->rx[hw->count * 2 + 1] = rxd >> 8;
break;
case 4:
hw->rx[hw->count * 4] = rxd;
hw->rx[hw->count * 4 + 1] = rxd >> 8;
hw->rx[hw->count * 4 + 2] = rxd >> 16;
hw->rx[hw->count * 4 + 3] = rxd >> 24;
break;
}
}
@@ -116,6 +174,7 @@ static int altera_spi_txrx(struct spi_master *master,
struct spi_device *spi, struct spi_transfer *t)
{
struct altera_spi *hw = spi_master_get_devdata(master);
u32 val;
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
@@ -126,7 +185,7 @@ static int altera_spi_txrx(struct spi_master *master,
if (hw->irq >= 0) {
/* enable receive interrupt */
hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
/* send the first byte */
altera_spi_tx_word(hw);
@@ -134,9 +193,13 @@ static int altera_spi_txrx(struct spi_master *master,
while (hw->count < hw->len) {
altera_spi_tx_word(hw);
while (!(readl(hw->base + ALTERA_SPI_STATUS) &
ALTERA_SPI_STATUS_RRDY_MSK))
for (;;) {
altr_spi_readl(hw, ALTERA_SPI_STATUS, &val);
if (val & ALTERA_SPI_STATUS_RRDY_MSK)
break;
cpu_relax();
}
altera_spi_rx_word(hw);
}
@@ -158,7 +221,7 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
} else {
/* disable receive interrupt */
hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
spi_finalize_current_transfer(master);
}
@@ -168,9 +231,14 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
static int altera_spi_probe(struct platform_device *pdev)
{
const struct platform_device_id *platid = platform_get_device_id(pdev);
struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev);
enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN;
struct altera_spi *hw;
struct spi_master *master;
int err = -ENODEV;
u32 val;
u16 i;
master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
if (!master)
@@ -178,27 +246,72 @@ static int altera_spi_probe(struct platform_device *pdev)
/* setup the master state. */
master->bus_num = pdev->id;
master->num_chipselect = 16;
master->mode_bits = SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
if (pdata) {
if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) {
dev_err(&pdev->dev,
"Invalid number of chipselect: %hu\n",
pdata->num_chipselect);
return -EINVAL;
}
master->num_chipselect = pdata->num_chipselect;
master->mode_bits = pdata->mode_bits;
master->bits_per_word_mask = pdata->bits_per_word_mask;
} else {
master->num_chipselect = 16;
master->mode_bits = SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
}
master->dev.of_node = pdev->dev.of_node;
master->transfer_one = altera_spi_txrx;
master->set_cs = altera_spi_set_cs;
hw = spi_master_get_devdata(master);
hw->dev = &pdev->dev;
if (platid)
type = platid->driver_data;
/* find and map our resources */
hw->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hw->base)) {
err = PTR_ERR(hw->base);
goto exit;
if (type == ALTERA_SPI_TYPE_SUBDEV) {
struct resource *regoff;
hw->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!hw->regmap) {
dev_err(&pdev->dev, "get regmap failed\n");
goto exit;
}
regoff = platform_get_resource(pdev, IORESOURCE_REG, 0);
if (regoff)
hw->regoff = regoff->start;
} else {
void __iomem *res;
res = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(res)) {
err = PTR_ERR(res);
goto exit;
}
hw->regmap = devm_regmap_init_mmio(&pdev->dev, res,
&spi_altera_config);
if (IS_ERR(hw->regmap)) {
dev_err(&pdev->dev, "regmap mmio init failed\n");
err = PTR_ERR(hw->regmap);
goto exit;
}
}
/* program defaults into the registers */
hw->imr = 0; /* disable spi interrupts */
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
writel(0, hw->base + ALTERA_SPI_STATUS); /* clear status reg */
if (readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK)
readl(hw->base + ALTERA_SPI_RXDATA); /* flush rxdata */
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
altr_spi_writel(hw, ALTERA_SPI_STATUS, 0); /* clear status reg */
altr_spi_readl(hw, ALTERA_SPI_STATUS, &val);
if (val & ALTERA_SPI_STATUS_RRDY_MSK)
altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */
/* irq is optional */
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq >= 0) {
@@ -211,7 +324,17 @@ static int altera_spi_probe(struct platform_device *pdev)
err = devm_spi_register_master(&pdev->dev, master);
if (err)
goto exit;
dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
if (pdata) {
for (i = 0; i < pdata->num_devices; i++) {
if (!spi_new_device(master, pdata->devices + i))
dev_warn(&pdev->dev,
"unable to create SPI device: %s\n",
pdata->devices[i].modalias);
}
}
dev_info(&pdev->dev, "regoff %u, irq %d\n", hw->regoff, hw->irq);
return 0;
exit:
@@ -228,6 +351,13 @@ static const struct of_device_id altera_spi_match[] = {
MODULE_DEVICE_TABLE(of, altera_spi_match);
#endif /* CONFIG_OF */
static const struct platform_device_id altera_spi_ids[] = {
{ DRV_NAME, ALTERA_SPI_TYPE_UNKNOWN },
{ "subdev_spi_altera", ALTERA_SPI_TYPE_SUBDEV },
{ }
};
MODULE_DEVICE_TABLE(platform, altera_spi_ids);
static struct platform_driver altera_spi_driver = {
.probe = altera_spi_probe,
.driver = {
@@ -235,6 +365,7 @@ static struct platform_driver altera_spi_driver = {
.pm = NULL,
.of_match_table = of_match_ptr(altera_spi_match),
},
.id_table = altera_spi_ids,
};
module_platform_driver(altera_spi_driver);

View File

@@ -294,11 +294,13 @@ err_free_master:
return err;
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id spi_acpi_match[] = {
{ "AMDI0061", 0 },
{},
};
MODULE_DEVICE_TABLE(acpi, spi_acpi_match);
#endif
static struct platform_driver amd_spi_driver = {
.driver = {

View File

@@ -681,13 +681,6 @@ static const struct dev_pm_ops at91_usart_spi_pm_ops = {
at91_usart_spi_runtime_resume, NULL)
};
static const struct of_device_id at91_usart_spi_dt_ids[] = {
{ .compatible = "microchip,at91sam9g45-usart-spi"},
{ /* sentinel */}
};
MODULE_DEVICE_TABLE(of, at91_usart_spi_dt_ids);
static struct platform_driver at91_usart_spi_driver = {
.driver = {
.name = "at91_usart_spi",

View File

@@ -1546,10 +1546,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
return PTR_ERR(clk);
/* setup spi core then atmel-specific driver state */
ret = -ENOMEM;
master = spi_alloc_master(&pdev->dev, sizeof(*as));
if (!master)
goto out_free;
return -ENOMEM;
/* the spi->mode bits understood by this driver: */
master->use_gpio_descriptors = true;
@@ -1678,7 +1677,6 @@ out_free_dma:
clk_disable_unprepare(clk);
out_free_irq:
out_unmap_regs:
out_free:
spi_master_put(master);
return ret;
}

View File

@@ -86,6 +86,7 @@ MODULE_PARM_DESC(polling_limit_us,
* @clk: core clock, divided to calculate serial clock
* @irq: interrupt, signals TX FIFO empty or RX FIFO ¾ full
* @tfr: SPI transfer currently processed
* @ctlr: SPI controller reverse lookup
* @tx_buf: pointer whence next transmitted byte is read
* @rx_buf: pointer where next received byte is written
* @tx_len: remaining bytes to transmit
@@ -125,6 +126,7 @@ struct bcm2835_spi {
struct clk *clk;
int irq;
struct spi_transfer *tfr;
struct spi_controller *ctlr;
const u8 *tx_buf;
u8 *rx_buf;
int tx_len;
@@ -243,13 +245,13 @@ static inline void bcm2835_rd_fifo_count(struct bcm2835_spi *bs, int count)
bs->rx_len -= count;
while (count > 0) {
do {
val = bcm2835_rd(bs, BCM2835_SPI_FIFO);
len = min(count, 4);
memcpy(bs->rx_buf, &val, len);
bs->rx_buf += len;
count -= 4;
}
} while (count > 0);
}
/**
@@ -269,7 +271,7 @@ static inline void bcm2835_wr_fifo_count(struct bcm2835_spi *bs, int count)
bs->tx_len -= count;
while (count > 0) {
do {
if (bs->tx_buf) {
len = min(count, 4);
memcpy(&val, bs->tx_buf, len);
@@ -279,7 +281,7 @@ static inline void bcm2835_wr_fifo_count(struct bcm2835_spi *bs, int count)
}
bcm2835_wr(bs, BCM2835_SPI_FIFO, val);
count -= 4;
}
} while (count > 0);
}
/**
@@ -308,12 +310,11 @@ static inline void bcm2835_rd_fifo_blind(struct bcm2835_spi *bs, int count)
count = min(count, bs->rx_len);
bs->rx_len -= count;
while (count) {
do {
val = bcm2835_rd(bs, BCM2835_SPI_FIFO);
if (bs->rx_buf)
*bs->rx_buf++ = val;
count--;
}
} while (--count);
}
/**
@@ -328,16 +329,14 @@ static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count)
count = min(count, bs->tx_len);
bs->tx_len -= count;
while (count) {
do {
val = bs->tx_buf ? *bs->tx_buf++ : 0;
bcm2835_wr(bs, BCM2835_SPI_FIFO, val);
count--;
}
} while (--count);
}
static void bcm2835_spi_reset_hw(struct spi_controller *ctlr)
static void bcm2835_spi_reset_hw(struct bcm2835_spi *bs)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
/* Disable SPI interrupts and transfer */
@@ -363,8 +362,7 @@ static void bcm2835_spi_reset_hw(struct spi_controller *ctlr)
static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
{
struct spi_controller *ctlr = dev_id;
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
struct bcm2835_spi *bs = dev_id;
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
/*
@@ -386,9 +384,9 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
if (!bs->rx_len) {
/* Transfer complete - reset SPI HW */
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
/* wake up the framework */
complete(&ctlr->xfer_completion);
complete(&bs->ctlr->xfer_completion);
}
return IRQ_HANDLED;
@@ -607,7 +605,7 @@ static void bcm2835_spi_dma_rx_done(void *data)
bcm2835_spi_undo_prologue(bs);
/* reset fifo and HW */
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
/* and mark as completed */;
complete(&ctlr->xfer_completion);
@@ -641,7 +639,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
dmaengine_terminate_async(ctlr->dma_rx);
bcm2835_spi_undo_prologue(bs);
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
complete(&ctlr->xfer_completion);
}
@@ -825,14 +823,14 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
if (!bs->rx_buf && !bs->tx_dma_active &&
cmpxchg(&bs->rx_dma_active, true, false)) {
dmaengine_terminate_async(ctlr->dma_rx);
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
}
/* wait for wakeup in framework */
return 1;
err_reset_hw:
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
bcm2835_spi_undo_prologue(bs);
return ret;
}
@@ -1074,7 +1072,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr,
}
/* Transfer complete - reset SPI HW */
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
/* and return without waiting for completion */
return 0;
}
@@ -1084,7 +1082,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
struct spi_transfer *tfr)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
unsigned long spi_hz, clk_hz, cdiv, spi_used_hz;
unsigned long spi_hz, clk_hz, cdiv;
unsigned long hz_per_byte, byte_limit;
u32 cs = bs->prepare_cs[spi->chip_select];
@@ -1104,7 +1102,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
} else {
cdiv = 0; /* 0 is the slowest we can go */
}
spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536);
tfr->effective_speed_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536);
bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
/* handle all the 3-wire mode */
@@ -1124,7 +1122,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
* per 300,000 Hz of bus clock.
*/
hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0;
byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1;
byte_limit = hz_per_byte ? tfr->effective_speed_hz / hz_per_byte : 1;
/* run in polling mode for short transfers */
if (tfr->len < byte_limit)
@@ -1182,7 +1180,7 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
bcm2835_spi_undo_prologue(bs);
/* and reset */
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
}
static int chip_match_name(struct gpio_chip *chip, void *data)
@@ -1311,6 +1309,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
ctlr->dev.of_node = pdev->dev.of_node;
bs = spi_controller_get_devdata(ctlr);
bs->ctlr = ctlr;
bs->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(bs->regs)) {
@@ -1345,7 +1344,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
dev_name(&pdev->dev), ctlr);
dev_name(&pdev->dev), bs);
if (err) {
dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
goto out_dma_release;

View File

@@ -345,7 +345,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
struct spi_transfer *tfr)
{
struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
unsigned long spi_hz, clk_hz, speed, spi_used_hz;
unsigned long spi_hz, clk_hz, speed;
unsigned long hz_per_byte, byte_limit;
/* calculate the registers to handle
@@ -374,7 +374,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
/* set the new speed */
bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT;
spi_used_hz = clk_hz / (2 * (speed + 1));
tfr->effective_speed_hz = clk_hz / (2 * (speed + 1));
/* set transmit buffers and length */
bs->tx_buf = tfr->tx_buf;
@@ -391,7 +391,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
* 30 µs per 300,000 Hz of bus clock.
*/
hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0;
byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1;
byte_limit = hz_per_byte ? tfr->effective_speed_hz / hz_per_byte : 1;
/* run in polling mode for short transfers */
if (tfr->len < byte_limit)

View File

@@ -20,6 +20,7 @@
#include <linux/spi/spi.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/reset.h>
#define HSSPI_GLOBAL_CTRL_REG 0x0
#define GLOBAL_CTRL_CS_POLARITY_SHIFT 0
@@ -334,6 +335,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
struct clk *clk, *pll_clk = NULL;
int irq, ret;
u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
struct reset_control *reset;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -348,10 +350,20 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
reset = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(reset))
return PTR_ERR(reset);
ret = clk_prepare_enable(clk);
if (ret)
return ret;
ret = reset_control_reset(reset);
if (ret) {
dev_err(dev, "unable to reset device: %d\n", ret);
goto out_disable_clk;
}
rate = clk_get_rate(clk);
if (!rate) {
pll_clk = devm_clk_get(dev, "pll");

View File

@@ -18,6 +18,7 @@
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/reset.h>
/* BCM 6338/6348 SPI core */
#define SPI_6348_RSET_SIZE 64
@@ -493,6 +494,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
struct bcm63xx_spi *bs;
int ret;
u32 num_cs = BCM63XX_SPI_MAX_CS;
struct reset_control *reset;
if (dev->of_node) {
const struct of_device_id *match;
@@ -529,6 +531,10 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
return PTR_ERR(clk);
}
reset = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(reset))
return PTR_ERR(reset);
master = spi_alloc_master(dev, sizeof(*bs));
if (!master) {
dev_err(dev, "out of memory\n");
@@ -579,6 +585,12 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
if (ret)
goto out_err;
ret = reset_control_reset(reset);
if (ret) {
dev_err(dev, "unable to reset device: %d\n", ret);
goto out_clk_disable;
}
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
/* register and we are done */

View File

@@ -174,7 +174,7 @@ int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
}
EXPORT_SYMBOL_GPL(spi_bitbang_setup_transfer);
/**
/*
* spi_bitbang_setup - default setup for per-word I/O loops
*/
int spi_bitbang_setup(struct spi_device *spi)
@@ -208,7 +208,7 @@ int spi_bitbang_setup(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_bitbang_setup);
/**
/*
* spi_bitbang_cleanup - default cleanup for per-word I/O loops
*/
void spi_bitbang_cleanup(struct spi_device *spi)
@@ -427,7 +427,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
}
EXPORT_SYMBOL_GPL(spi_bitbang_start);
/**
/*
* spi_bitbang_stop - stops the task providing spi communication
*/
void spi_bitbang_stop(struct spi_bitbang *bitbang)

File diff suppressed because it is too large Load Diff

View File

@@ -556,7 +556,7 @@ static int cdns_spi_probe(struct platform_device *pdev)
master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware;
master->set_cs = cdns_spi_chipselect;
master->auto_runtime_pm = true;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
/* Set to default valid value */
master->max_speed_hz = clk_get_rate(xspi->ref_clk) / 4;

View File

@@ -64,6 +64,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
p->sys_freq = SYS_FREQ_DEFAULT;
dev_info(dev, "Set system clock to %u\n", p->sys_freq);
master->flags = SPI_MASTER_HALF_DUPLEX;
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
SPI_LSB_FIRST | SPI_3WIRE;

View File

@@ -387,7 +387,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
status = PTR_ERR(mcfqspi->clk);
goto fail0;
}
clk_enable(mcfqspi->clk);
clk_prepare_enable(mcfqspi->clk);
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->num_chipselect;
@@ -425,7 +425,7 @@ fail2:
pm_runtime_disable(&pdev->dev);
mcfqspi_cs_teardown(mcfqspi);
fail1:
clk_disable(mcfqspi->clk);
clk_disable_unprepare(mcfqspi->clk);
fail0:
spi_master_put(master);

View File

@@ -236,7 +236,8 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
/**
* davinci_spi_get_prescale - Calculates the correct prescale value
* @maxspeed_hz: the maximum rate the SPI clock can run at
* @dspi: the controller data
* @max_speed_hz: the maximum rate the SPI clock can run at
*
* This function calculates the prescale value that generates a clock rate
* less than or equal to the specified maximum.
@@ -711,7 +712,7 @@ err_desc:
/**
* dummy_thread_fn - dummy thread function
* @irq: IRQ number for this SPI Master
* @context_data: structure for SPI Master controller davinci_spi
* @data: structure for SPI Master controller davinci_spi
*
* This is to satisfy the request_threaded_irq() API so that the irq
* handler is called in interrupt context.
@@ -724,7 +725,7 @@ static irqreturn_t dummy_thread_fn(s32 irq, void *data)
/**
* davinci_spi_irq - Interrupt handler for SPI Master Controller
* @irq: IRQ number for this SPI Master
* @context_data: structure for SPI Master controller davinci_spi
* @data: structure for SPI Master controller davinci_spi
*
* ISR will determine that interrupt arrives either for READ or WRITE command.
* According to command it will do the appropriate action. It will check

View File

@@ -372,8 +372,20 @@ static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
{
u16 imr = 0, dma_ctrl = 0;
/*
* Having a Rx DMA channel serviced with higher priority than a Tx DMA
* channel might not be enough to provide a well balanced DMA-based
* SPI transfer interface. There might still be moments when the Tx DMA
* channel is occasionally handled faster than the Rx DMA channel.
* That in its turn will eventually cause the SPI Rx FIFO overflow if
* SPI bus speed is high enough to fill the SPI Rx FIFO in before it's
* cleared by the Rx DMA channel. In order to fix the problem the Tx
* DMA activity is intentionally slowed down by limiting the SPI Tx
* FIFO depth with a value twice bigger than the Tx burst length
* calculated earlier by the dw_spi_dma_maxburst_init() method.
*/
dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
dw_writel(dws, DW_SPI_DMATDLR, dws->fifo_len - dws->txburst);
dw_writel(dws, DW_SPI_DMATDLR, dws->txburst);
if (xfer->tx_buf)
dma_ctrl |= SPI_DMA_TDMAE;

View File

@@ -10,7 +10,7 @@
*
* For more information about the SPI controller see documentation on Cirrus
* Logic web site:
* http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
* https://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
*/
#include <linux/io.h>
@@ -214,7 +214,7 @@ static void ep93xx_do_read(struct spi_master *master)
/**
* ep93xx_spi_read_write() - perform next RX/TX transfer
* @espi: ep93xx SPI controller struct
* @master: SPI master
*
* This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
* called several times, the whole transfer will be completed. Returns

View File

@@ -11,7 +11,6 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -19,11 +18,9 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/platform_data/dma-imx.h>
#include <linux/platform_data/spi-imx.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
@@ -101,6 +98,7 @@ struct fsl_lpspi_data {
struct clk *clk_ipg;
struct clk *clk_per;
bool is_slave;
bool is_only_cs1;
bool is_first_byte;
void *rx_buf;
@@ -122,8 +120,6 @@ struct fsl_lpspi_data {
bool usedma;
struct completion dma_rx_completion;
struct completion dma_tx_completion;
int chipselect[];
};
static const struct of_device_id fsl_lpspi_dt_ids[] = {
@@ -224,20 +220,6 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
return 0;
}
static int fsl_lpspi_prepare_message(struct spi_controller *controller,
struct spi_message *msg)
{
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
struct spi_device *spi = msg->spi;
int gpio = fsl_lpspi->chipselect[spi->chip_select];
if (gpio_is_valid(gpio))
gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
return 0;
}
static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
{
u8 txfifo_cnt;
@@ -276,10 +258,9 @@ static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi)
temp |= fsl_lpspi->config.bpw - 1;
temp |= (fsl_lpspi->config.mode & 0x3) << 30;
temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
if (!fsl_lpspi->is_slave) {
temp |= fsl_lpspi->config.prescale << 27;
temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
/*
* Set TCR_CONT will keep SS asserted after current transfer.
* For the first transfer, clear TCR_CONTC to assert SS.
@@ -440,7 +421,10 @@ static int fsl_lpspi_setup_transfer(struct spi_controller *controller,
fsl_lpspi->config.mode = spi->mode;
fsl_lpspi->config.bpw = t->bits_per_word;
fsl_lpspi->config.speed_hz = t->speed_hz;
fsl_lpspi->config.chip_select = spi->chip_select;
if (fsl_lpspi->is_only_cs1)
fsl_lpspi->config.chip_select = 1;
else
fsl_lpspi->config.chip_select = spi->chip_select;
if (!fsl_lpspi->config.speed_hz)
fsl_lpspi->config.speed_hz = spi->max_speed_hz;
@@ -831,13 +815,10 @@ static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi)
static int fsl_lpspi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct fsl_lpspi_data *fsl_lpspi;
struct spi_controller *controller;
struct spi_imx_master *lpspi_platform_info =
dev_get_platdata(&pdev->dev);
struct resource *res;
int i, ret, irq;
int ret, irq;
u32 temp;
bool is_slave;
@@ -857,6 +838,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
fsl_lpspi = spi_controller_get_devdata(controller);
fsl_lpspi->dev = &pdev->dev;
fsl_lpspi->is_slave = is_slave;
fsl_lpspi->is_only_cs1 = of_property_read_bool((&pdev->dev)->of_node,
"fsl,spi-only-use-cs1-sel");
controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
controller->transfer_one = fsl_lpspi_transfer_one;
@@ -867,35 +850,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
controller->dev.of_node = pdev->dev.of_node;
controller->bus_num = pdev->id;
controller->slave_abort = fsl_lpspi_slave_abort;
ret = devm_spi_register_controller(&pdev->dev, controller);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_controller error.\n");
goto out_controller_put;
}
if (!fsl_lpspi->is_slave) {
for (i = 0; i < controller->num_chipselect; i++) {
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
if (!gpio_is_valid(cs_gpio) && lpspi_platform_info)
cs_gpio = lpspi_platform_info->chipselect[i];
fsl_lpspi->chipselect[i] = cs_gpio;
if (!gpio_is_valid(cs_gpio))
continue;
ret = devm_gpio_request(&pdev->dev,
fsl_lpspi->chipselect[i],
DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev, "can't get cs gpios\n");
goto out_controller_put;
}
}
controller->cs_gpios = fsl_lpspi->chipselect;
controller->prepare_message = fsl_lpspi_prepare_message;
}
if (!fsl_lpspi->is_slave)
controller->use_gpio_descriptors = true;
init_completion(&fsl_lpspi->xfer_done);
@@ -954,10 +910,21 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
if (ret < 0)
dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret);
ret = devm_spi_register_controller(&pdev->dev, controller);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_controller error.\n");
goto out_pm_get;
}
pm_runtime_mark_last_busy(fsl_lpspi->dev);
pm_runtime_put_autosuspend(fsl_lpspi->dev);
return 0;
out_pm_get:
pm_runtime_put_noidle(fsl_lpspi->dev);
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
pm_runtime_put_sync(fsl_lpspi->dev);
pm_runtime_disable(fsl_lpspi->dev);
out_controller_put:
spi_controller_put(controller);

View File

@@ -15,7 +15,7 @@
* Yogesh Gaur <yogeshnarayan.gaur@nxp.com>
* Suresh Gupta <suresh.gupta@nxp.com>
*
* Based on the original fsl-quadspi.c spi-nor driver:
* Based on the original fsl-quadspi.c SPI NOR driver:
* Author: Freescale Semiconductor, Inc.
*
*/

View File

@@ -90,7 +90,7 @@ static void fsl_spi_change_mode(struct spi_device *spi)
{
struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
struct spi_mpc8xxx_cs *cs = spi->controller_state;
struct fsl_spi_reg *reg_base = mspi->reg_base;
struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
__be32 __iomem *mode = &reg_base->mode;
unsigned long flags;
@@ -291,7 +291,7 @@ static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
struct spi_transfer *t, unsigned int len)
{
u32 word;
struct fsl_spi_reg *reg_base = mspi->reg_base;
struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
mspi->count = len;
@@ -309,7 +309,7 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
bool is_dma_mapped)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
struct fsl_spi_reg *reg_base;
struct fsl_spi_reg __iomem *reg_base;
unsigned int len = t->len;
u8 bits_per_word;
int ret;
@@ -440,7 +440,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master,
static int fsl_spi_setup(struct spi_device *spi)
{
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_spi_reg *reg_base;
struct fsl_spi_reg __iomem *reg_base;
int retval;
u32 hw_mode;
struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
@@ -495,7 +495,7 @@ static void fsl_spi_cleanup(struct spi_device *spi)
static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
{
struct fsl_spi_reg *reg_base = mspi->reg_base;
struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
/* We need handle RX first */
if (events & SPIE_NE) {
@@ -530,7 +530,7 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
struct mpc8xxx_spi *mspi = context_data;
irqreturn_t ret = IRQ_NONE;
u32 events;
struct fsl_spi_reg *reg_base = mspi->reg_base;
struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
/* Get interrupt events(tx/rx) */
events = mpc8xxx_spi_read_reg(&reg_base->event);
@@ -550,7 +550,7 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
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 fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base;
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
u32 slvsel;
u16 cs = spi->chip_select;
@@ -568,7 +568,7 @@ static void fsl_spi_grlib_probe(struct device *dev)
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master = dev_get_drvdata(dev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base;
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
int mbits;
u32 capabilities;
@@ -594,7 +594,7 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master;
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_spi_reg *reg_base;
struct fsl_spi_reg __iomem *reg_base;
u32 regval;
int ret = 0;

View File

@@ -52,7 +52,6 @@
/* M_CMD OP codes for SPI */
#define SPI_TX_ONLY 1
#define SPI_RX_ONLY 2
#define SPI_FULL_DUPLEX 3
#define SPI_TX_RX 7
#define SPI_CS_ASSERT 8
#define SPI_CS_DEASSERT 9
@@ -64,13 +63,6 @@
#define TIMESTAMP_AFTER BIT(3)
#define POST_CMD_DELAY BIT(4)
enum spi_m_cmd_opcode {
CMD_NONE,
CMD_XFER,
CMD_CS,
CMD_CANCEL,
};
struct spi_geni_master {
struct geni_se se;
struct device *dev;
@@ -84,11 +76,13 @@ struct spi_geni_master {
unsigned int tx_rem_bytes;
unsigned int rx_rem_bytes;
const struct spi_transfer *cur_xfer;
struct completion xfer_done;
struct completion cs_done;
struct completion cancel_done;
struct completion abort_done;
unsigned int oversampling;
spinlock_t lock;
enum spi_m_cmd_opcode cur_mcmd;
int irq;
bool cs_flag;
};
static int get_spi_clk_cfg(unsigned int speed_hz,
@@ -127,24 +121,26 @@ static void handle_fifo_timeout(struct spi_master *spi,
struct spi_message *msg)
{
struct spi_geni_master *mas = spi_master_get_devdata(spi);
unsigned long time_left, flags;
unsigned long time_left;
struct geni_se *se = &mas->se;
spin_lock_irqsave(&mas->lock, flags);
reinit_completion(&mas->xfer_done);
mas->cur_mcmd = CMD_CANCEL;
geni_se_cancel_m_cmd(se);
spin_lock_irq(&mas->lock);
reinit_completion(&mas->cancel_done);
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
spin_unlock_irqrestore(&mas->lock, flags);
time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
mas->cur_xfer = NULL;
geni_se_cancel_m_cmd(se);
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->cancel_done, HZ);
if (time_left)
return;
spin_lock_irqsave(&mas->lock, flags);
reinit_completion(&mas->xfer_done);
spin_lock_irq(&mas->lock);
reinit_completion(&mas->abort_done);
geni_se_abort_m_cmd(se);
spin_unlock_irqrestore(&mas->lock, flags);
time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->abort_done, HZ);
if (!time_left)
dev_err(mas->dev, "Failed to cancel/abort m_cmd\n");
}
@@ -156,18 +152,24 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
struct geni_se *se = &mas->se;
unsigned long time_left;
reinit_completion(&mas->xfer_done);
pm_runtime_get_sync(mas->dev);
if (!(slv->mode & SPI_CS_HIGH))
set_flag = !set_flag;
mas->cur_mcmd = CMD_CS;
if (set_flag == mas->cs_flag)
return;
mas->cs_flag = set_flag;
pm_runtime_get_sync(mas->dev);
spin_lock_irq(&mas->lock);
reinit_completion(&mas->cs_done);
if (set_flag)
geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);
else
geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0);
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->xfer_done, HZ);
time_left = wait_for_completion_timeout(&mas->cs_done, HZ);
if (!time_left)
handle_fifo_timeout(spi, NULL);
@@ -306,7 +308,7 @@ static int spi_geni_init(struct spi_geni_master *mas)
* Hardware programming guide suggests to configure
* RX FIFO RFR level to fifo_depth-2.
*/
geni_se_init(se, 0x0, mas->tx_fifo_depth - 2);
geni_se_init(se, mas->tx_fifo_depth / 2, mas->tx_fifo_depth - 2);
/* Transmit an entire FIFO worth of data per IRQ */
mas->tx_wm = 1;
ver = geni_se_get_qup_hw_version(se);
@@ -333,6 +335,21 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
struct geni_se *se = &mas->se;
int ret;
/*
* Ensure that our interrupt handler isn't still running from some
* prior command before we start messing with the hardware behind
* its back. We don't need to _keep_ the lock here since we're only
* worried about racing with out interrupt handler. The SPI core
* already handles making sure that we're not trying to do two
* transfers at once or setting a chip select and doing a transfer
* concurrently.
*
* NOTE: we actually _can't_ hold the lock here because possibly we
* might call clk_set_rate() which needs to be able to sleep.
*/
spin_lock_irq(&mas->lock);
spin_unlock_irq(&mas->lock);
spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG);
if (xfer->bits_per_word != mas->cur_bits_per_word) {
spi_setup_word_len(mas, mode, xfer->bits_per_word);
@@ -346,12 +363,6 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
mas->tx_rem_bytes = 0;
mas->rx_rem_bytes = 0;
if (xfer->tx_buf && xfer->rx_buf)
m_cmd = SPI_FULL_DUPLEX;
else if (xfer->tx_buf)
m_cmd = SPI_TX_ONLY;
else if (xfer->rx_buf)
m_cmd = SPI_RX_ONLY;
spi_tx_cfg &= ~CS_TOGGLE;
@@ -362,17 +373,24 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
len &= TRANS_LEN_MSK;
mas->cur_xfer = xfer;
if (m_cmd & SPI_TX_ONLY) {
if (xfer->tx_buf) {
m_cmd |= SPI_TX_ONLY;
mas->tx_rem_bytes = xfer->len;
writel(len, se->base + SE_SPI_TX_TRANS_LEN);
}
if (m_cmd & SPI_RX_ONLY) {
if (xfer->rx_buf) {
m_cmd |= SPI_RX_ONLY;
writel(len, se->base + SE_SPI_RX_TRANS_LEN);
mas->rx_rem_bytes = xfer->len;
}
writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
mas->cur_mcmd = CMD_XFER;
/*
* Lock around right before we start the transfer since our
* interrupt could come in at any time now.
*/
spin_lock_irq(&mas->lock);
geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION);
/*
@@ -382,6 +400,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
*/
if (m_cmd & SPI_TX_ONLY)
writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG);
spin_unlock_irq(&mas->lock);
}
static int spi_geni_transfer_one(struct spi_master *spi,
@@ -483,13 +502,17 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
struct spi_geni_master *mas = spi_master_get_devdata(spi);
struct geni_se *se = &mas->se;
u32 m_irq;
unsigned long flags;
if (mas->cur_mcmd == CMD_NONE)
m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
if (!m_irq)
return IRQ_NONE;
spin_lock_irqsave(&mas->lock, flags);
m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |
M_RX_FIFO_RD_ERR_EN | M_RX_FIFO_WR_ERR_EN |
M_TX_FIFO_RD_ERR_EN | M_TX_FIFO_WR_ERR_EN))
dev_warn(mas->dev, "Unexpected IRQ err status %#010x\n", m_irq);
spin_lock(&mas->lock);
if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
geni_spi_handle_rx(mas);
@@ -498,39 +521,57 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
geni_spi_handle_tx(mas);
if (m_irq & M_CMD_DONE_EN) {
if (mas->cur_mcmd == CMD_XFER)
if (mas->cur_xfer) {
spi_finalize_current_transfer(spi);
else if (mas->cur_mcmd == CMD_CS)
complete(&mas->xfer_done);
mas->cur_mcmd = CMD_NONE;
/*
* If this happens, then a CMD_DONE came before all the Tx
* buffer bytes were sent out. This is unusual, log this
* condition and disable the WM interrupt to prevent the
* system from stalling due an interrupt storm.
* If this happens when all Rx bytes haven't been received, log
* the condition.
* The only known time this can happen is if bits_per_word != 8
* and some registers that expect xfer lengths in num spi_words
* weren't written correctly.
*/
if (mas->tx_rem_bytes) {
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
mas->tx_rem_bytes, mas->cur_bits_per_word);
mas->cur_xfer = NULL;
/*
* If this happens, then a CMD_DONE came before all the
* Tx buffer bytes were sent out. This is unusual, log
* this condition and disable the WM interrupt to
* prevent the system from stalling due an interrupt
* storm.
*
* If this happens when all Rx bytes haven't been
* received, log the condition. The only known time
* this can happen is if bits_per_word != 8 and some
* registers that expect xfer lengths in num spi_words
* weren't written correctly.
*/
if (mas->tx_rem_bytes) {
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
mas->tx_rem_bytes, mas->cur_bits_per_word);
}
if (mas->rx_rem_bytes)
dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
mas->rx_rem_bytes, mas->cur_bits_per_word);
} else {
complete(&mas->cs_done);
}
if (mas->rx_rem_bytes)
dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
mas->rx_rem_bytes, mas->cur_bits_per_word);
}
if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN)) {
mas->cur_mcmd = CMD_NONE;
complete(&mas->xfer_done);
}
if (m_irq & M_CMD_CANCEL_EN)
complete(&mas->cancel_done);
if (m_irq & M_CMD_ABORT_EN)
complete(&mas->abort_done);
/*
* It's safe or a good idea to Ack all of our our interrupts at the
* end of the function. Specifically:
* - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and
* clearing Acks. Clearing at the end relies on nobody else having
* started a new transfer yet or else we could be clearing _their_
* done bit, but everyone grabs the spinlock before starting a new
* transfer.
* - M_RX_FIFO_WATERMARK_EN / M_TX_FIFO_WATERMARK_EN: These appear
* to be "latched level" interrupts so it's important to clear them
* _after_ you've handled the condition and always safe to do so
* since they'll re-assert if they're still happening.
*/
writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR);
spin_unlock_irqrestore(&mas->lock, flags);
spin_unlock(&mas->lock);
return IRQ_HANDLED;
}
@@ -591,8 +632,12 @@ static int spi_geni_probe(struct platform_device *pdev)
spi->handle_err = handle_fifo_timeout;
spi->set_cs = spi_geni_set_cs;
init_completion(&mas->xfer_done);
init_completion(&mas->cs_done);
init_completion(&mas->cancel_done);
init_completion(&mas->abort_done);
spin_lock_init(&mas->lock);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
pm_runtime_enable(dev);
ret = geni_icc_get(&mas->se, NULL);

View File

@@ -9,7 +9,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -102,10 +101,6 @@ struct img_spfi {
bool rx_dma_busy;
};
struct img_spfi_device_data {
bool gpio_requested;
};
static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
{
return readl(spfi->regs + reg);
@@ -442,54 +437,6 @@ static int img_spfi_unprepare(struct spi_master *master,
return 0;
}
static int img_spfi_setup(struct spi_device *spi)
{
int ret = -EINVAL;
struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
if (!spfi_data) {
spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL);
if (!spfi_data)
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);
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;
}
static void img_spfi_cleanup(struct spi_device *spi)
{
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,
struct spi_transfer *xfer)
{
@@ -659,12 +606,11 @@ static int img_spfi_probe(struct platform_device *pdev)
master->max_speed_hz = max_speed_hz;
}
master->setup = img_spfi_setup;
master->cleanup = img_spfi_cleanup;
master->transfer_one = img_spfi_transfer_one;
master->prepare_message = img_spfi_prepare;
master->unprepare_message = img_spfi_unprepare;
master->handle_err = img_spfi_handle_err;
master->use_gpio_descriptors = true;
spfi->tx_ch = dma_request_chan(spfi->dev, "tx");
if (IS_ERR(spfi->tx_ch)) {

View File

@@ -8,23 +8,23 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/types.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/property.h>
#include <linux/platform_data/dma-imx.h>
#include <linux/platform_data/spi-imx.h>
#define DRIVER_NAME "spi_imx"
@@ -32,6 +32,8 @@ static bool use_dma = true;
module_param(use_dma, bool, 0644);
MODULE_PARM_DESC(use_dma, "Enable usage of DMA when available (default)");
#define MXC_RPM_TIMEOUT 2000 /* 2000ms */
#define MXC_CSPIRXDATA 0x00
#define MXC_CSPITXDATA 0x04
#define MXC_CSPICTRL 0x08
@@ -224,7 +226,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
if (!use_dma)
if (!use_dma || master->fallback)
return false;
if (!master->dma_rx)
@@ -723,7 +725,7 @@ static int mx31_prepare_transfer(struct spi_imx_data *spi_imx,
reg |= MX31_CSPICTRL_POL;
if (spi->mode & SPI_CS_HIGH)
reg |= MX31_CSPICTRL_SSPOL;
if (!gpio_is_valid(spi->cs_gpio))
if (!spi->cs_gpiod)
reg |= (spi->chip_select) <<
(is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT :
MX31_CSPICTRL_CS_SHIFT);
@@ -824,7 +826,7 @@ static int mx21_prepare_transfer(struct spi_imx_data *spi_imx,
reg |= MX21_CSPICTRL_POL;
if (spi->mode & SPI_CS_HIGH)
reg |= MX21_CSPICTRL_SSPOL;
if (!gpio_is_valid(spi->cs_gpio))
if (!spi->cs_gpiod)
reg |= spi->chip_select << MX21_CSPICTRL_CS_SHIFT;
writel(reg, spi_imx->base + MXC_CSPICTRL);
@@ -1056,20 +1058,6 @@ static const struct of_device_id spi_imx_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
static void spi_imx_chipselect(struct spi_device *spi, int is_active)
{
int active = is_active != BITBANG_CS_INACTIVE;
int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);
if (spi->mode & SPI_NO_CS)
return;
if (!gpio_is_valid(spi->cs_gpio))
return;
gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active);
}
static void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits)
{
u32 ctrl;
@@ -1364,11 +1352,12 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
ret = spi_imx_dma_configure(master);
if (ret)
return ret;
goto dma_failure_no_start;
if (!spi_imx->devtype_data->setup_wml) {
dev_err(spi_imx->dev, "No setup_wml()?\n");
return -EINVAL;
ret = -EINVAL;
goto dma_failure_no_start;
}
spi_imx->devtype_data->setup_wml(spi_imx);
@@ -1379,8 +1368,10 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
rx->sgl, rx->nents, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx)
return -EINVAL;
if (!desc_rx) {
ret = -EINVAL;
goto dma_failure_no_start;
}
desc_rx->callback = spi_imx_dma_rx_callback;
desc_rx->callback_param = (void *)spi_imx;
@@ -1425,6 +1416,10 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
}
return transfer->len;
/* fallback to pio */
dma_failure_no_start:
transfer->error |= SPI_TRANS_FAIL_NO_START;
return ret;
}
static int spi_imx_pio_transfer(struct spi_device *spi,
@@ -1507,7 +1502,6 @@ static int spi_imx_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
int ret;
/* flush rxfifo before transfer */
while (spi_imx->devtype_data->rx_available(spi_imx))
@@ -1516,21 +1510,8 @@ static int spi_imx_transfer(struct spi_device *spi,
if (spi_imx->slave_mode)
return spi_imx_pio_transfer_slave(spi, transfer);
/*
* fallback PIO mode if dma setup error happen, for example sdma
* firmware may not be updated as ERR009165 required.
*/
if (spi_imx->usedma) {
ret = spi_imx_dma_transfer(spi_imx, transfer);
if (ret != -EINVAL)
return ret;
spi_imx->devtype_data->disable_dma(spi_imx);
spi_imx->usedma = false;
spi_imx->dynamic_burst = spi_imx->devtype_data->dynamic_burst;
dev_dbg(&spi->dev, "Fallback to PIO mode\n");
}
if (spi_imx->usedma)
return spi_imx_dma_transfer(spi_imx, transfer);
return spi_imx_pio_transfer(spi, transfer);
}
@@ -1540,15 +1521,6 @@ static int spi_imx_setup(struct spi_device *spi)
dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
spi->mode, spi->bits_per_word, spi->max_speed_hz);
if (spi->mode & SPI_NO_CS)
return 0;
if (gpio_is_valid(spi->cs_gpio))
gpio_direction_output(spi->cs_gpio,
spi->mode & SPI_CS_HIGH ? 0 : 1);
spi_imx_chipselect(spi, BITBANG_CS_INACTIVE);
return 0;
}
@@ -1562,20 +1534,16 @@ spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg)
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
int ret;
ret = clk_enable(spi_imx->clk_per);
if (ret)
return ret;
ret = clk_enable(spi_imx->clk_ipg);
if (ret) {
clk_disable(spi_imx->clk_per);
ret = pm_runtime_get_sync(spi_imx->dev);
if (ret < 0) {
dev_err(spi_imx->dev, "failed to enable clock\n");
return ret;
}
ret = spi_imx->devtype_data->prepare_message(spi_imx, msg);
if (ret) {
clk_disable(spi_imx->clk_ipg);
clk_disable(spi_imx->clk_per);
pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
}
return ret;
@@ -1586,8 +1554,8 @@ spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
clk_disable(spi_imx->clk_ipg);
clk_disable(spi_imx->clk_per);
pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
return 0;
}
@@ -1606,20 +1574,14 @@ static int spi_imx_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(spi_imx_dt_ids, &pdev->dev);
struct spi_imx_master *mxc_platform_info =
dev_get_platdata(&pdev->dev);
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
int i, ret, irq, spi_drctl;
int ret, irq, spi_drctl;
const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data :
(struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
bool slave_mode;
if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
return -EINVAL;
}
u32 val;
slave_mode = devtype_data->has_slavemode &&
of_property_read_bool(np, "spi-slave");
@@ -1642,6 +1604,7 @@ static int spi_imx_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->bus_num = np ? -1 : pdev->id;
master->use_gpio_descriptors = true;
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = master;
@@ -1650,28 +1613,17 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->devtype_data = devtype_data;
/* Get number of chip selects, either platform data or OF */
if (mxc_platform_info) {
master->num_chipselect = mxc_platform_info->num_chipselect;
if (mxc_platform_info->chipselect) {
master->cs_gpios = devm_kcalloc(&master->dev,
master->num_chipselect, sizeof(int),
GFP_KERNEL);
if (!master->cs_gpios)
return -ENOMEM;
/*
* Get number of chip selects from device properties. This can be
* coming from device tree or boardfiles, if it is not defined,
* a default value of 3 chip selects will be used, as all the legacy
* board files have <= 3 chip selects.
*/
if (!device_property_read_u32(&pdev->dev, "num-cs", &val))
master->num_chipselect = val;
else
master->num_chipselect = 3;
for (i = 0; i < master->num_chipselect; i++)
master->cs_gpios[i] = mxc_platform_info->chipselect[i];
}
} else {
u32 num_cs;
if (!of_property_read_u32(np, "num-cs", &num_cs))
master->num_chipselect = num_cs;
/* If not preset, default value of 1 is used */
}
spi_imx->bitbang.chipselect = spi_imx_chipselect;
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
spi_imx->bitbang.txrx_bufs = spi_imx_transfer;
spi_imx->bitbang.master->setup = spi_imx_setup;
@@ -1722,13 +1674,15 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_master_put;
}
ret = clk_prepare_enable(spi_imx->clk_per);
if (ret)
goto out_master_put;
pm_runtime_enable(spi_imx->dev);
pm_runtime_set_autosuspend_delay(spi_imx->dev, MXC_RPM_TIMEOUT);
pm_runtime_use_autosuspend(spi_imx->dev);
ret = clk_prepare_enable(spi_imx->clk_ipg);
if (ret)
goto out_put_per;
ret = pm_runtime_get_sync(spi_imx->dev);
if (ret < 0) {
dev_err(spi_imx->dev, "failed to enable clock\n");
goto out_runtime_pm_put;
}
spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per);
/*
@@ -1738,7 +1692,7 @@ static int spi_imx_probe(struct platform_device *pdev)
if (spi_imx->devtype_data->has_dmamode) {
ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master);
if (ret == -EPROBE_DEFER)
goto out_clk_put;
goto out_runtime_pm_put;
if (ret < 0)
dev_err(&pdev->dev, "dma setup error %d, use pio\n",
@@ -1753,38 +1707,20 @@ static int spi_imx_probe(struct platform_device *pdev)
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
goto out_clk_put;
}
/* Request GPIO CS lines, if any */
if (!spi_imx->slave_mode && master->cs_gpios) {
for (i = 0; i < master->num_chipselect; i++) {
if (!gpio_is_valid(master->cs_gpios[i]))
continue;
ret = devm_gpio_request(&pdev->dev,
master->cs_gpios[i],
DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev, "Can't get CS GPIO %i\n",
master->cs_gpios[i]);
goto out_spi_bitbang;
}
}
goto out_runtime_pm_put;
}
dev_info(&pdev->dev, "probed\n");
clk_disable(spi_imx->clk_ipg);
clk_disable(spi_imx->clk_per);
pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
return ret;
out_spi_bitbang:
spi_bitbang_stop(&spi_imx->bitbang);
out_clk_put:
clk_disable_unprepare(spi_imx->clk_ipg);
out_put_per:
clk_disable_unprepare(spi_imx->clk_per);
out_runtime_pm_put:
pm_runtime_dont_use_autosuspend(spi_imx->dev);
pm_runtime_put_sync(spi_imx->dev);
pm_runtime_disable(spi_imx->dev);
out_master_put:
spi_master_put(master);
@@ -1799,30 +1735,82 @@ static int spi_imx_remove(struct platform_device *pdev)
spi_bitbang_stop(&spi_imx->bitbang);
ret = clk_enable(spi_imx->clk_per);
if (ret)
return ret;
ret = clk_enable(spi_imx->clk_ipg);
if (ret) {
clk_disable(spi_imx->clk_per);
ret = pm_runtime_get_sync(spi_imx->dev);
if (ret < 0) {
dev_err(spi_imx->dev, "failed to enable clock\n");
return ret;
}
writel(0, spi_imx->base + MXC_CSPICTRL);
clk_disable_unprepare(spi_imx->clk_ipg);
clk_disable_unprepare(spi_imx->clk_per);
pm_runtime_dont_use_autosuspend(spi_imx->dev);
pm_runtime_put_sync(spi_imx->dev);
pm_runtime_disable(spi_imx->dev);
spi_imx_sdma_exit(spi_imx);
spi_master_put(master);
return 0;
}
static int __maybe_unused spi_imx_runtime_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct spi_imx_data *spi_imx;
int ret;
spi_imx = spi_master_get_devdata(master);
ret = clk_prepare_enable(spi_imx->clk_per);
if (ret)
return ret;
ret = clk_prepare_enable(spi_imx->clk_ipg);
if (ret) {
clk_disable_unprepare(spi_imx->clk_per);
return ret;
}
return 0;
}
static int __maybe_unused spi_imx_runtime_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct spi_imx_data *spi_imx;
spi_imx = spi_master_get_devdata(master);
clk_disable_unprepare(spi_imx->clk_per);
clk_disable_unprepare(spi_imx->clk_ipg);
return 0;
}
static int __maybe_unused spi_imx_suspend(struct device *dev)
{
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int __maybe_unused spi_imx_resume(struct device *dev)
{
pinctrl_pm_select_default_state(dev);
return 0;
}
static const struct dev_pm_ops imx_spi_pm = {
SET_RUNTIME_PM_OPS(spi_imx_runtime_suspend,
spi_imx_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume)
};
static struct platform_driver spi_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = spi_imx_dt_ids,
},
.pm = &imx_spi_pm,
},
.id_table = spi_imx_devtype,
.probe = spi_imx_probe,
.remove = spi_imx_remove,

View File

@@ -15,7 +15,6 @@
#include <linux/completion.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
@@ -50,8 +49,6 @@
#define LTQ_SPI_RXCNT 0x84
#define LTQ_SPI_DMACON 0xec
#define LTQ_SPI_IRNEN 0xf4
#define LTQ_SPI_IRNICR 0xf8
#define LTQ_SPI_IRNCR 0xfc
#define LTQ_SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */
#define LTQ_SPI_CLC_SMC_M (0xFF << LTQ_SPI_CLC_SMC_S)
@@ -61,9 +58,7 @@
#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */
#define LTQ_SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */
#define LTQ_SPI_ID_TXFS_M (0x3F << LTQ_SPI_ID_TXFS_S)
#define LTQ_SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */
#define LTQ_SPI_ID_RXFS_M (0x3F << LTQ_SPI_ID_RXFS_S)
#define LTQ_SPI_ID_MOD_S 8 /* Module ID */
#define LTQ_SPI_ID_MOD_M (0xff << LTQ_SPI_ID_MOD_S)
#define LTQ_SPI_ID_CFG_S 5 /* DMA interface support */
@@ -126,19 +121,15 @@
LTQ_SPI_WHBSTATE_CLRTUE)
#define LTQ_SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */
#define LTQ_SPI_RXFCON_RXFITL_M (0x3F << LTQ_SPI_RXFCON_RXFITL_S)
#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */
#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */
#define LTQ_SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */
#define LTQ_SPI_TXFCON_TXFITL_M (0x3F << LTQ_SPI_TXFCON_TXFITL_S)
#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */
#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */
#define LTQ_SPI_FSTAT_RXFFL_S 0
#define LTQ_SPI_FSTAT_RXFFL_M (0x3f << LTQ_SPI_FSTAT_RXFFL_S)
#define LTQ_SPI_FSTAT_TXFFL_S 8
#define LTQ_SPI_FSTAT_TXFFL_M (0x3f << LTQ_SPI_FSTAT_TXFFL_S)
#define LTQ_SPI_GPOCON_ISCSBN_S 8
#define LTQ_SPI_GPOCON_INVOUTN_S 0
@@ -158,9 +149,16 @@
#define LTQ_SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */
#define LTQ_SPI_IRNEN_ALL 0x1F
struct lantiq_ssc_spi;
struct lantiq_ssc_hwcfg {
unsigned int irnen_r;
unsigned int irnen_t;
int (*cfg_irq)(struct platform_device *pdev, struct lantiq_ssc_spi *spi);
unsigned int irnen_r;
unsigned int irnen_t;
unsigned int irncr;
unsigned int irnicr;
bool irq_ack;
u32 fifo_size_mask;
};
struct lantiq_ssc_spi {
@@ -184,6 +182,7 @@ struct lantiq_ssc_spi {
unsigned int tx_fifo_size;
unsigned int rx_fifo_size;
unsigned int base_cs;
unsigned int fdx_tx_level;
};
static u32 lantiq_ssc_readl(const struct lantiq_ssc_spi *spi, u32 reg)
@@ -209,16 +208,18 @@ static void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr,
static unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi)
{
const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT);
return (fstat & LTQ_SPI_FSTAT_TXFFL_M) >> LTQ_SPI_FSTAT_TXFFL_S;
return (fstat >> LTQ_SPI_FSTAT_TXFFL_S) & hwcfg->fifo_size_mask;
}
static unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi)
{
const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT);
return fstat & LTQ_SPI_FSTAT_RXFFL_M;
return (fstat >> LTQ_SPI_FSTAT_RXFFL_S) & hwcfg->fifo_size_mask;
}
static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi)
@@ -391,7 +392,7 @@ static int lantiq_ssc_setup(struct spi_device *spidev)
u32 gpocon;
/* GPIOs are used for CS */
if (gpio_is_valid(spidev->cs_gpio))
if (spidev->cs_gpiod)
return 0;
dev_dbg(spi->dev, "using internal chipselect %u\n", cs);
@@ -481,6 +482,7 @@ static void tx_fifo_write(struct lantiq_ssc_spi *spi)
u32 data;
unsigned int tx_free = tx_fifo_free(spi);
spi->fdx_tx_level = 0;
while (spi->tx_todo && tx_free) {
switch (spi->bits_per_word) {
case 2 ... 8:
@@ -509,6 +511,7 @@ static void tx_fifo_write(struct lantiq_ssc_spi *spi)
lantiq_ssc_writel(spi, data, LTQ_SPI_TB);
tx_free--;
spi->fdx_tx_level++;
}
}
@@ -520,6 +523,13 @@ static void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi)
u32 data;
unsigned int rx_fill = rx_fifo_level(spi);
/*
* Wait until all expected data to be shifted in.
* Otherwise, rx overrun may occur.
*/
while (rx_fill != spi->fdx_tx_level)
rx_fill = rx_fifo_level(spi);
while (rx_fill) {
data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
@@ -613,6 +623,13 @@ static void rx_request(struct lantiq_ssc_spi *spi)
static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data)
{
struct lantiq_ssc_spi *spi = data;
const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
unsigned long flags;
spin_lock_irqsave(&spi->lock, flags);
if (hwcfg->irq_ack)
lantiq_ssc_writel(spi, val, hwcfg->irncr);
if (spi->tx) {
if (spi->rx && spi->rx_todo)
@@ -635,10 +652,12 @@ static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data)
}
}
spin_unlock_irqrestore(&spi->lock, flags);
return IRQ_HANDLED;
completed:
queue_work(spi->wq, &spi->work);
spin_unlock_irqrestore(&spi->lock, flags);
return IRQ_HANDLED;
}
@@ -646,11 +665,18 @@ completed:
static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data)
{
struct lantiq_ssc_spi *spi = data;
const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
unsigned long flags;
if (!(stat & LTQ_SPI_STAT_ERRORS))
return IRQ_NONE;
spin_lock_irqsave(&spi->lock, flags);
if (hwcfg->irq_ack)
lantiq_ssc_writel(spi, val, hwcfg->irncr);
if (stat & LTQ_SPI_STAT_RUE)
dev_err(spi->dev, "receive underflow error\n");
if (stat & LTQ_SPI_STAT_TUE)
@@ -671,6 +697,25 @@ static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data)
if (spi->master->cur_msg)
spi->master->cur_msg->status = -EIO;
queue_work(spi->wq, &spi->work);
spin_unlock_irqrestore(&spi->lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t intel_lgm_ssc_isr(int irq, void *data)
{
struct lantiq_ssc_spi *spi = data;
const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
if (!(val & LTQ_SPI_IRNEN_ALL))
return IRQ_NONE;
if (val & LTQ_SPI_IRNEN_E)
return lantiq_ssc_err_interrupt(irq, data);
if ((val & hwcfg->irnen_t) || (val & hwcfg->irnen_r))
return lantiq_ssc_xmit_interrupt(irq, data);
return IRQ_HANDLED;
}
@@ -775,20 +820,84 @@ static int lantiq_ssc_transfer_one(struct spi_master *master,
return transfer_start(spi, spidev, t);
}
static int intel_lgm_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi)
{
int irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
return devm_request_irq(&pdev->dev, irq, intel_lgm_ssc_isr, 0, "spi", spi);
}
static int lantiq_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi)
{
int irq, err;
irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
if (irq < 0)
return irq;
err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt,
0, LTQ_SPI_RX_IRQ_NAME, spi);
if (err)
return err;
irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME);
if (irq < 0)
return irq;
err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt,
0, LTQ_SPI_TX_IRQ_NAME, spi);
if (err)
return err;
irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME);
if (irq < 0)
return irq;
err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_err_interrupt,
0, LTQ_SPI_ERR_IRQ_NAME, spi);
return err;
}
static const struct lantiq_ssc_hwcfg lantiq_ssc_xway = {
.irnen_r = LTQ_SPI_IRNEN_R_XWAY,
.irnen_t = LTQ_SPI_IRNEN_T_XWAY,
.cfg_irq = lantiq_cfg_irq,
.irnen_r = LTQ_SPI_IRNEN_R_XWAY,
.irnen_t = LTQ_SPI_IRNEN_T_XWAY,
.irnicr = 0xF8,
.irncr = 0xFC,
.fifo_size_mask = GENMASK(5, 0),
.irq_ack = false,
};
static const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = {
.irnen_r = LTQ_SPI_IRNEN_R_XRX,
.irnen_t = LTQ_SPI_IRNEN_T_XRX,
.cfg_irq = lantiq_cfg_irq,
.irnen_r = LTQ_SPI_IRNEN_R_XRX,
.irnen_t = LTQ_SPI_IRNEN_T_XRX,
.irnicr = 0xF8,
.irncr = 0xFC,
.fifo_size_mask = GENMASK(5, 0),
.irq_ack = false,
};
static const struct lantiq_ssc_hwcfg intel_ssc_lgm = {
.cfg_irq = intel_lgm_cfg_irq,
.irnen_r = LTQ_SPI_IRNEN_R_XRX,
.irnen_t = LTQ_SPI_IRNEN_T_XRX,
.irnicr = 0xFC,
.irncr = 0xF8,
.fifo_size_mask = GENMASK(7, 0),
.irq_ack = true,
};
static const struct of_device_id lantiq_ssc_match[] = {
{ .compatible = "lantiq,ase-spi", .data = &lantiq_ssc_xway, },
{ .compatible = "lantiq,falcon-spi", .data = &lantiq_ssc_xrx, },
{ .compatible = "lantiq,xrx100-spi", .data = &lantiq_ssc_xrx, },
{ .compatible = "intel,lgm-spi", .data = &intel_ssc_lgm, },
{},
};
MODULE_DEVICE_TABLE(of, lantiq_ssc_match);
@@ -800,9 +909,9 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
struct lantiq_ssc_spi *spi;
const struct lantiq_ssc_hwcfg *hwcfg;
const struct of_device_id *match;
int err, rx_irq, tx_irq, err_irq;
u32 id, supports_dma, revision;
unsigned int num_cs;
int err;
match = of_match_device(lantiq_ssc_match, dev);
if (!match) {
@@ -811,18 +920,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
}
hwcfg = match->data;
rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
if (rx_irq < 0)
return -ENXIO;
tx_irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME);
if (tx_irq < 0)
return -ENXIO;
err_irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME);
if (err_irq < 0)
return -ENXIO;
master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi));
if (!master)
return -ENOMEM;
@@ -838,18 +935,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
goto err_master_put;
}
err = devm_request_irq(dev, rx_irq, lantiq_ssc_xmit_interrupt,
0, LTQ_SPI_RX_IRQ_NAME, spi);
if (err)
goto err_master_put;
err = devm_request_irq(dev, tx_irq, lantiq_ssc_xmit_interrupt,
0, LTQ_SPI_TX_IRQ_NAME, spi);
if (err)
goto err_master_put;
err = devm_request_irq(dev, err_irq, lantiq_ssc_err_interrupt,
0, LTQ_SPI_ERR_IRQ_NAME, spi);
err = hwcfg->cfg_irq(pdev, spi);
if (err)
goto err_master_put;
@@ -888,6 +974,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = num_cs;
master->use_gpio_descriptors = true;
master->setup = lantiq_ssc_setup;
master->set_cs = lantiq_ssc_set_cs;
master->handle_err = lantiq_ssc_handle_err;
@@ -907,8 +994,8 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
INIT_WORK(&spi->work, lantiq_ssc_bussy_work);
id = lantiq_ssc_readl(spi, LTQ_SPI_ID);
spi->tx_fifo_size = (id & LTQ_SPI_ID_TXFS_M) >> LTQ_SPI_ID_TXFS_S;
spi->rx_fifo_size = (id & LTQ_SPI_ID_RXFS_M) >> LTQ_SPI_ID_RXFS_S;
spi->tx_fifo_size = (id >> LTQ_SPI_ID_TXFS_S) & hwcfg->fifo_size_mask;
spi->rx_fifo_size = (id >> LTQ_SPI_ID_RXFS_S) & hwcfg->fifo_size_mask;
supports_dma = (id & LTQ_SPI_ID_CFG_M) >> LTQ_SPI_ID_CFG_S;
revision = id & LTQ_SPI_ID_REV_M;

View File

@@ -885,10 +885,10 @@ static int spi_test_run_iter(struct spi_device *spi,
/**
* spi_test_execute_msg - default implementation to run a test
*
* spi: @spi_device on which to run the @spi_message
* test: the test to execute, which already contains @msg
* tx: the tx buffer allocated for the test sequence
* rx: the rx buffer allocated for the test sequence
* @spi: @spi_device on which to run the @spi_message
* @test: the test to execute, which already contains @msg
* @tx: the tx buffer allocated for the test sequence
* @rx: the rx buffer allocated for the test sequence
*
* Returns: error code of spi_sync as well as basic error checking
*/
@@ -957,10 +957,10 @@ EXPORT_SYMBOL_GPL(spi_test_execute_msg);
* including all the relevant iterations on:
* length and buffer alignment
*
* spi: the spi_device to send the messages to
* test: the test which we need to execute
* tx: the tx buffer allocated for the test sequence
* rx: the rx buffer allocated for the test sequence
* @spi: the spi_device to send the messages to
* @test: the test which we need to execute
* @tx: the tx buffer allocated for the test sequence
* @rx: the rx buffer allocated for the test sequence
*
* Returns: status code of spi_sync or other failures
*/

View File

@@ -156,6 +156,12 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
op->data.dir == SPI_MEM_DATA_OUT))
return false;
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
return false;
if (op->cmd.nbytes != 1)
return false;
return true;
}
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
@@ -170,7 +176,7 @@ static bool spi_mem_buswidth_is_valid(u8 buswidth)
static int spi_mem_check_op(const struct spi_mem_op *op)
{
if (!op->cmd.buswidth)
if (!op->cmd.buswidth || !op->cmd.nbytes)
return -EINVAL;
if ((op->addr.nbytes && !op->addr.buswidth) ||
@@ -306,8 +312,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
return ret;
}
tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes +
op->dummy.nbytes;
tmpbufsize = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
/*
* Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so
@@ -322,7 +327,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
tmpbuf[0] = op->cmd.opcode;
xfers[xferpos].tx_buf = tmpbuf;
xfers[xferpos].len = sizeof(op->cmd.opcode);
xfers[xferpos].len = op->cmd.nbytes;
xfers[xferpos].tx_nbits = op->cmd.buswidth;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
@@ -424,8 +429,7 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
return ctlr->mem_ops->adjust_op_size(mem, op);
if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) {
len = sizeof(op->cmd.opcode) + op->addr.nbytes +
op->dummy.nbytes;
len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
if (len > spi_max_transfer_size(mem->spi))
return -EINVAL;

View File

@@ -362,8 +362,6 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc)
{
u32 data;
if (spicc->data->has_oen)
writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO,
SPICC_ENH_MAIN_CLK_AO,
@@ -373,7 +371,7 @@ static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc)
spicc->base + SPICC_TESTREG);
while (meson_spicc_rxready(spicc))
data = readl_relaxed(spicc->base + SPICC_RXDATA);
readl_relaxed(spicc->base + SPICC_RXDATA);
if (spicc->data->has_oen)
writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, 0,

View File

@@ -70,7 +70,7 @@
* @master: the SPI master
* @regmap: regmap for device registers
* @clk: input clock of the built-in baud rate generator
* @device: the device structure
* @dev: the device structure
*/
struct meson_spifc {
struct spi_master *master;

View File

@@ -171,6 +171,9 @@ static const struct of_device_id mtk_spi_of_match[] = {
{ .compatible = "mediatek,mt8183-spi",
.data = (void *)&mt8183_compat,
},
{ .compatible = "mediatek,mt8192-spi",
.data = (void *)&mt6765_compat,
},
{}
};
MODULE_DEVICE_TABLE(of, mtk_spi_of_match);

View File

@@ -195,7 +195,7 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
}
}
len = MTK_NOR_PRG_MAX_SIZE - sizeof(op->cmd.opcode) - op->addr.nbytes -
len = MTK_NOR_PRG_MAX_SIZE - op->cmd.nbytes - op->addr.nbytes -
op->dummy.nbytes;
if (op->data.nbytes > len)
op->data.nbytes = len;
@@ -211,6 +211,12 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
if (op->cmd.buswidth != 1)
return false;
/* DTR ops not supported. */
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
return false;
if (op->cmd.nbytes != 1)
return false;
if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op))
return true;
@@ -219,7 +225,7 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
(op->dummy.buswidth == 0) &&
(op->data.buswidth == 1);
}
len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
if ((len > MTK_NOR_PRG_MAX_SIZE) ||
((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
return false;

View File

@@ -356,6 +356,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
int nio = 1, i, ret;
u32 ss_ctrl;
u8 addr[8];
u8 opcode = op->cmd.opcode;
ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz);
if (ret)
@@ -393,7 +394,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
mxic->regs + HC_CFG);
ret = mxic_spi_data_xfer(mxic, &op->cmd.opcode, NULL, 1);
ret = mxic_spi_data_xfer(mxic, &opcode, NULL, 1);
if (ret)
goto out;

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Nuvoton Technology corporation.
#include <linux/bits.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
@@ -177,7 +178,6 @@ enum {
#define MAP_SIZE_16MB 0x1000000
#define MAP_SIZE_8MB 0x800000
#define NUM_BITS_IN_BYTE 8
#define FIU_DRD_MAX_DUMMY_NUMBER 3
#define NPCM_MAX_CHIP_NUM 4
#define CHUNK_SIZE 16
@@ -252,8 +252,8 @@ static void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu,
fiu->drd_op.addr.buswidth = op->addr.buswidth;
regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
NPCM_FIU_DRD_CFG_DBW,
((op->dummy.nbytes * ilog2(op->addr.buswidth))
/ NUM_BITS_IN_BYTE) << NPCM_FIU_DRD_DBW_SHIFT);
((op->dummy.nbytes * ilog2(op->addr.buswidth)) / BITS_PER_BYTE)
<< NPCM_FIU_DRD_DBW_SHIFT);
fiu->drd_op.dummy.nbytes = op->dummy.nbytes;
regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode);

View File

@@ -10,8 +10,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/reset.h>
#include <asm/unaligned.h>
@@ -344,16 +342,9 @@ static int npcm_pspi_probe(struct platform_device *pdev)
struct npcm_pspi *priv;
struct spi_master *master;
unsigned long clk_hz;
struct device_node *np = pdev->dev.of_node;
int num_cs, i;
int csgpio;
int irq;
int ret;
num_cs = of_gpio_named_count(np, "cs-gpios");
if (num_cs < 0)
return num_cs;
master = spi_alloc_master(&pdev->dev, sizeof(*priv));
if (!master)
return -ENOMEM;
@@ -418,24 +409,7 @@ static int npcm_pspi_probe(struct platform_device *pdev)
npcm_pspi_prepare_transfer_hardware;
master->unprepare_transfer_hardware =
npcm_pspi_unprepare_transfer_hardware;
master->num_chipselect = num_cs;
for (i = 0; i < num_cs; i++) {
csgpio = of_get_named_gpio(np, "cs-gpios", i);
if (csgpio < 0) {
dev_err(&pdev->dev, "failed to get csgpio#%u\n", i);
goto out_disable_clk;
}
dev_dbg(&pdev->dev, "csgpio#%u = %d\n", i, csgpio);
ret = devm_gpio_request_one(&pdev->dev, csgpio,
GPIOF_OUT_INIT_HIGH, DRIVER_NAME);
if (ret < 0) {
dev_err(&pdev->dev,
"failed to configure csgpio#%u %d\n"
, i, csgpio);
goto out_disable_clk;
}
}
master->use_gpio_descriptors = true;
/* set to default clock rate */
npcm_pspi_set_baudrate(priv, NPCM_PSPI_DEFAULT_CLK);

View File

@@ -2,7 +2,7 @@
/*
* OpenCores tiny SPI master driver
*
* http://opencores.org/project,tiny_spi
* https://opencores.org/project,tiny_spi
*
* Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw>
*

View File

@@ -19,7 +19,6 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>

View File

@@ -443,7 +443,7 @@ static void uwire_cleanup(struct spi_device *spi)
static void uwire_off(struct uwire_spi *uwire)
{
uwire_write_reg(UWIRE_SR3, 0);
clk_disable(uwire->ck);
clk_disable_unprepare(uwire->ck);
spi_master_put(uwire->bitbang.master);
}
@@ -475,7 +475,7 @@ static int uwire_probe(struct platform_device *pdev)
spi_master_put(master);
return status;
}
clk_enable(uwire->ck);
clk_prepare_enable(uwire->ck);
if (cpu_is_omap7xx())
uwire_idx_shift = 1;

View File

@@ -27,7 +27,6 @@
#include <linux/iopoll.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
@@ -1043,16 +1042,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
spi->controller_state = cs;
/* Link this to context save list */
list_add_tail(&cs->node, &ctx->cs);
if (gpio_is_valid(spi->cs_gpio)) {
ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev));
if (ret) {
dev_err(&spi->dev, "failed to request gpio\n");
return ret;
}
gpio_direction_output(spi->cs_gpio,
!(spi->mode & SPI_CS_HIGH));
}
}
ret = pm_runtime_get_sync(mcspi->dev);
@@ -1080,9 +1069,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
kfree(cs);
}
if (gpio_is_valid(spi->cs_gpio))
gpio_free(spi->cs_gpio);
}
static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
@@ -1152,7 +1138,7 @@ static int omap2_mcspi_transfer_one(struct spi_master *master,
omap2_mcspi_set_enable(spi, 0);
if (gpio_is_valid(spi->cs_gpio))
if (spi->cs_gpiod)
omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH);
if (par_override ||
@@ -1241,7 +1227,7 @@ out:
omap2_mcspi_set_enable(spi, 0);
if (gpio_is_valid(spi->cs_gpio))
if (spi->cs_gpiod)
omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH));
if (mcspi->fifo_depth > 0 && t)
@@ -1431,6 +1417,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->dev.of_node = node;
master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
master->use_gpio_descriptors = true;
platform_set_drvdata(pdev, master);

View File

@@ -708,7 +708,7 @@ static int orion_spi_probe(struct platform_device *pdev)
/*
* Only map one page for direct access. This is enough for the
* simple TX transfer which only writes to the first word.
* This needs to get extended for the direct SPI-NOR / SPI-NAND
* This needs to get extended for the direct SPI NOR / SPI NAND
* support, once this gets implemented.
*/
dir_acc = &spi->child[cs].direct_access;

View File

@@ -298,7 +298,7 @@ enum ssp_reading {
READING_U32
};
/**
/*
* The type of writing going on on this chip
*/
enum ssp_writing {
@@ -317,6 +317,7 @@ enum ssp_writing {
* @extended_cr: 32 bit wide control register 0 with extra
* features and extra features in CR1 as found in the ST variants
* @pl023: supports a subset of the ST extensions called "PL023"
* @loopback: supports loopback mode
* @internal_cs_ctrl: supports chip select control register
*/
struct vendor_data {
@@ -353,11 +354,14 @@ struct vendor_data {
* @read: the type of read currently going on
* @write: the type of write currently going on
* @exp_fifo_level: expected FIFO level
* @rx_lev_trig: receive FIFO watermark level which triggers IRQ
* @tx_lev_trig: transmit FIFO watermark level which triggers IRQ
* @dma_rx_channel: optional channel for RX DMA
* @dma_tx_channel: optional channel for TX DMA
* @sgt_rx: scattertable for the RX transfer
* @sgt_tx: scattertable for the TX transfer
* @dummypage: a dummy page used for driving data on the bus with DMA
* @dma_running: indicates whether DMA is in operation
* @cur_cs: current chip select (gpio)
* @chipselects: list of chipselects (gpios)
*/
@@ -662,7 +666,7 @@ static void load_ssp_default_config(struct pl022 *pl022)
writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
}
/**
/*
* This will write to TX and read from RX according to the parameters
* set in pl022.
*/
@@ -1237,6 +1241,8 @@ static inline void pl022_dma_remove(struct pl022 *pl022)
/**
* pl022_interrupt_handler - Interrupt handler for SSP controller
* @irq: IRQ number
* @dev_id: Local device data
*
* This function handles interrupts generated for an interrupt based transfer.
* If a receive overrun (ROR) interrupt is there then we disable SSP, flag the
@@ -1334,7 +1340,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
/**
/*
* This sets up the pointers to memory for the next message to
* send out on the SPI bus.
*/

View File

@@ -28,11 +28,9 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
@@ -127,8 +125,6 @@ struct ppc4xx_spi {
const unsigned char *tx;
unsigned char *rx;
int *gpios;
struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
struct spi_master *master;
struct device *dev;
@@ -260,27 +256,6 @@ static int spi_ppc4xx_setup(struct spi_device *spi)
return 0;
}
static void spi_ppc4xx_chipsel(struct spi_device *spi, int value)
{
struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
unsigned int cs = spi->chip_select;
unsigned int cspol;
/*
* If there are no chip selects at all, or if this is the special
* case of a non-existent (dummy) chip select, do nothing.
*/
if (!hw->master->num_chipselect || hw->gpios[cs] == -EEXIST)
return;
cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
if (value == BITBANG_CS_INACTIVE)
cspol = !cspol;
gpio_set_value(hw->gpios[cs], cspol);
}
static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id)
{
struct ppc4xx_spi *hw;
@@ -359,19 +334,6 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
dcri_clrset(SDR0, SDR0_PFC1, 0x80000000 >> 14, 0);
}
static void free_gpios(struct ppc4xx_spi *hw)
{
if (hw->master->num_chipselect) {
int i;
for (i = 0; i < hw->master->num_chipselect; i++)
if (gpio_is_valid(hw->gpios[i]))
gpio_free(hw->gpios[i]);
kfree(hw->gpios);
hw->gpios = NULL;
}
}
/*
* platform_device layer stuff...
*/
@@ -385,7 +347,6 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
struct device *dev = &op->dev;
struct device_node *opbnp;
int ret;
int num_gpios;
const unsigned int *clk;
master = spi_alloc_master(dev, sizeof *hw);
@@ -399,74 +360,32 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
init_completion(&hw->done);
/*
* A count of zero implies a single SPI device without any chip-select.
* Note that of_gpio_count counts all gpios assigned to this spi master.
* This includes both "null" gpio's and real ones.
*/
num_gpios = of_gpio_count(np);
if (num_gpios > 0) {
int i;
hw->gpios = kcalloc(num_gpios, sizeof(*hw->gpios), GFP_KERNEL);
if (!hw->gpios) {
ret = -ENOMEM;
goto free_master;
}
for (i = 0; i < num_gpios; i++) {
int gpio;
enum of_gpio_flags flags;
gpio = of_get_gpio_flags(np, i, &flags);
hw->gpios[i] = gpio;
if (gpio_is_valid(gpio)) {
/* Real CS - set the initial state. */
ret = gpio_request(gpio, np->name);
if (ret < 0) {
dev_err(dev,
"can't request gpio #%d: %d\n",
i, ret);
goto free_gpios;
}
gpio_direction_output(gpio,
!!(flags & OF_GPIO_ACTIVE_LOW));
} else if (gpio == -EEXIST) {
; /* No CS, but that's OK. */
} else {
dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
ret = -EINVAL;
goto free_gpios;
}
}
}
/* Setup the state for the bitbang driver */
bbp = &hw->bitbang;
bbp->master = hw->master;
bbp->setup_transfer = spi_ppc4xx_setupxfer;
bbp->chipselect = spi_ppc4xx_chipsel;
bbp->txrx_bufs = spi_ppc4xx_txrx;
bbp->use_dma = 0;
bbp->master->setup = spi_ppc4xx_setup;
bbp->master->cleanup = spi_ppc4xx_cleanup;
bbp->master->bits_per_word_mask = SPI_BPW_MASK(8);
bbp->master->use_gpio_descriptors = true;
/*
* The SPI core will count the number of GPIO descriptors to figure
* out the number of chip selects available on the platform.
*/
bbp->master->num_chipselect = 0;
/* the spi->mode bits understood by this driver: */
bbp->master->mode_bits =
SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
/* this many pins in all GPIO controllers */
bbp->master->num_chipselect = num_gpios > 0 ? num_gpios : 0;
/* Get the clock for the OPB */
opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb");
if (opbnp == NULL) {
dev_err(dev, "OPB: cannot find node\n");
ret = -ENODEV;
goto free_gpios;
goto free_master;
}
/* Get the clock (Hz) for the OPB */
clk = of_get_property(opbnp, "clock-frequency", NULL);
@@ -474,7 +393,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
dev_err(dev, "OPB: no clock-frequency property set\n");
of_node_put(opbnp);
ret = -ENODEV;
goto free_gpios;
goto free_master;
}
hw->opb_freq = *clk;
hw->opb_freq >>= 2;
@@ -483,7 +402,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
ret = of_address_to_resource(np, 0, &resource);
if (ret) {
dev_err(dev, "error while parsing device node resource\n");
goto free_gpios;
goto free_master;
}
hw->mapbase = resource.start;
hw->mapsize = resource_size(&resource);
@@ -492,7 +411,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
dev_err(dev, "too small to map registers\n");
ret = -EINVAL;
goto free_gpios;
goto free_master;
}
/* Request IRQ */
@@ -501,7 +420,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
0, "spi_ppc4xx_of", (void *)hw);
if (ret) {
dev_err(dev, "unable to allocate interrupt\n");
goto free_gpios;
goto free_master;
}
if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
@@ -538,8 +457,6 @@ map_io_error:
release_mem_region(hw->mapbase, hw->mapsize);
request_mem_error:
free_irq(hw->irqnum, hw);
free_gpios:
free_gpios(hw);
free_master:
spi_master_put(master);
@@ -556,7 +473,6 @@ static int spi_ppc4xx_of_remove(struct platform_device *op)
release_mem_region(hw->mapbase, hw->mapsize);
free_irq(hw->irqnum, hw);
iounmap(hw->regs);
free_gpios(hw);
spi_master_put(master);
return 0;
}

View File

@@ -1432,6 +1432,7 @@ static void cleanup(struct spi_device *spi)
kfree(chip);
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "INT33C0", LPSS_LPT_SSP },
{ "INT33C1", LPSS_LPT_SSP },
@@ -1442,6 +1443,7 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ },
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
#endif
/*
* PCI IDs of compound devices that integrate both host controller and private

View File

@@ -39,8 +39,9 @@
#define ROCKCHIP_SPI_RISR 0x0034
#define ROCKCHIP_SPI_ICR 0x0038
#define ROCKCHIP_SPI_DMACR 0x003c
#define ROCKCHIP_SPI_DMATDLR 0x0040
#define ROCKCHIP_SPI_DMARDLR 0x0044
#define ROCKCHIP_SPI_DMATDLR 0x0040
#define ROCKCHIP_SPI_DMARDLR 0x0044
#define ROCKCHIP_SPI_VERSION 0x0048
#define ROCKCHIP_SPI_TXDR 0x0400
#define ROCKCHIP_SPI_RXDR 0x0800
@@ -156,6 +157,8 @@
#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff
#define ROCKCHIP_SPI_MAX_CS_NUM 2
#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002
#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002
struct rockchip_spi {
struct device *dev;
@@ -206,17 +209,17 @@ static inline void wait_for_idle(struct rockchip_spi *rs)
static u32 get_fifo_len(struct rockchip_spi *rs)
{
u32 fifo;
u32 ver;
for (fifo = 2; fifo < 32; fifo++) {
writel_relaxed(fifo, rs->regs + ROCKCHIP_SPI_TXFTLR);
if (fifo != readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFTLR))
break;
ver = readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION);
switch (ver) {
case ROCKCHIP_SPI_VER2_TYPE1:
case ROCKCHIP_SPI_VER2_TYPE2:
return 64;
default:
return 32;
}
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_TXFTLR);
return (fifo == 31) ? 0 : fifo;
}
static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
@@ -288,7 +291,7 @@ static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
static void rockchip_spi_pio_reader(struct rockchip_spi *rs)
{
u32 words = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR);
u32 rx_left = rs->rx_left - words;
u32 rx_left = (rs->rx_left > words) ? rs->rx_left - words : 0;
/* the hardware doesn't allow us to change fifo threshold
* level while spi is enabled, so instead make sure to leave
@@ -384,6 +387,19 @@ static void rockchip_spi_dma_txcb(void *data)
spi_finalize_current_transfer(ctlr);
}
static u32 rockchip_spi_calc_burst_size(u32 data_len)
{
u32 i;
/* burst size: 1, 2, 4, 8 */
for (i = 1; i < 8; i <<= 1) {
if (data_len & i)
break;
}
return i;
}
static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
struct spi_controller *ctlr, struct spi_transfer *xfer)
{
@@ -397,7 +413,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
.direction = DMA_DEV_TO_MEM,
.src_addr = rs->dma_addr_rx,
.src_addr_width = rs->n_bytes,
.src_maxburst = 1,
.src_maxburst = rockchip_spi_calc_burst_size(xfer->len /
rs->n_bytes),
};
dmaengine_slave_config(ctlr->dma_rx, &rxconf);
@@ -525,7 +542,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1,
rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
/* the hardware only supports an even clock divisor, so

216
drivers/spi/spi-rpc-if.c Normal file
View File

@@ -0,0 +1,216 @@
// SPDX-License-Identifier: GPL-2.0
//
// RPC-IF SPI/QSPI/Octa driver
//
// Copyright (C) 2018 ~ 2019 Renesas Solutions Corp.
// Copyright (C) 2019 Macronix International Co., Ltd.
// Copyright (C) 2019 - 2020 Cogent Embedded, Inc.
//
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#include <memory/renesas-rpc-if.h>
#include <asm/unaligned.h>
static void rpcif_spi_mem_prepare(struct spi_device *spi_dev,
const struct spi_mem_op *spi_op,
u64 *offs, size_t *len)
{
struct rpcif *rpc = spi_controller_get_devdata(spi_dev->controller);
struct rpcif_op rpc_op = { };
rpc_op.cmd.opcode = spi_op->cmd.opcode;
rpc_op.cmd.buswidth = spi_op->cmd.buswidth;
if (spi_op->addr.nbytes) {
rpc_op.addr.buswidth = spi_op->addr.buswidth;
rpc_op.addr.nbytes = spi_op->addr.nbytes;
rpc_op.addr.val = spi_op->addr.val;
}
if (spi_op->dummy.nbytes) {
rpc_op.dummy.buswidth = spi_op->dummy.buswidth;
rpc_op.dummy.ncycles = spi_op->dummy.nbytes * 8 /
spi_op->dummy.buswidth;
}
if (spi_op->data.nbytes || (offs && len)) {
rpc_op.data.buswidth = spi_op->data.buswidth;
rpc_op.data.nbytes = spi_op->data.nbytes;
switch (spi_op->data.dir) {
case SPI_MEM_DATA_IN:
rpc_op.data.dir = RPCIF_DATA_IN;
rpc_op.data.buf.in = spi_op->data.buf.in;
break;
case SPI_MEM_DATA_OUT:
rpc_op.data.dir = RPCIF_DATA_OUT;
rpc_op.data.buf.out = spi_op->data.buf.out;
break;
case SPI_MEM_NO_DATA:
rpc_op.data.dir = RPCIF_NO_DATA;
break;
}
} else {
rpc_op.data.dir = RPCIF_NO_DATA;
}
rpcif_prepare(rpc, &rpc_op, offs, len);
}
static bool rpcif_spi_mem_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
if (!spi_mem_default_supports_op(mem, op))
return false;
if (op->data.buswidth > 4 || op->addr.buswidth > 4 ||
op->dummy.buswidth > 4 || op->cmd.buswidth > 4 ||
op->addr.nbytes > 4)
return false;
return true;
}
static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
struct rpcif *rpc =
spi_controller_get_devdata(desc->mem->spi->controller);
if (offs + desc->info.offset + len > U32_MAX)
return -EINVAL;
rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len);
return rpcif_dirmap_read(rpc, offs, len, buf);
}
static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
struct rpcif *rpc =
spi_controller_get_devdata(desc->mem->spi->controller);
if (desc->info.offset + desc->info.length > U32_MAX)
return -ENOTSUPP;
if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
return -ENOTSUPP;
if (!rpc->dirmap && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN)
return -ENOTSUPP;
if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT)
return -ENOTSUPP;
return 0;
}
static int rpcif_spi_mem_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct rpcif *rpc =
spi_controller_get_devdata(mem->spi->controller);
rpcif_spi_mem_prepare(mem->spi, op, NULL, NULL);
return rpcif_manual_xfer(rpc);
}
static const struct spi_controller_mem_ops rpcif_spi_mem_ops = {
.supports_op = rpcif_spi_mem_supports_op,
.exec_op = rpcif_spi_mem_exec_op,
.dirmap_create = rpcif_spi_mem_dirmap_create,
.dirmap_read = rpcif_spi_mem_dirmap_read,
};
static int rpcif_spi_probe(struct platform_device *pdev)
{
struct device *parent = pdev->dev.parent;
struct spi_controller *ctlr;
struct rpcif *rpc;
int error;
ctlr = spi_alloc_master(&pdev->dev, sizeof(*rpc));
if (!ctlr)
return -ENOMEM;
rpc = spi_controller_get_devdata(ctlr);
rpcif_sw_init(rpc, parent);
platform_set_drvdata(pdev, ctlr);
ctlr->dev.of_node = parent->of_node;
rpcif_enable_rpm(rpc);
ctlr->num_chipselect = 1;
ctlr->mem_ops = &rpcif_spi_mem_ops;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD;
ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
rpcif_hw_init(rpc, false);
error = spi_register_controller(ctlr);
if (error) {
dev_err(&pdev->dev, "spi_register_controller failed\n");
goto err_put_ctlr;
}
return 0;
err_put_ctlr:
rpcif_disable_rpm(rpc);
spi_controller_put(ctlr);
return error;
}
static int rpcif_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct rpcif *rpc = spi_controller_get_devdata(ctlr);
spi_unregister_controller(ctlr);
rpcif_disable_rpm(rpc);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rpcif_spi_suspend(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
return spi_controller_suspend(ctlr);
}
static int rpcif_spi_resume(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
return spi_controller_resume(ctlr);
}
static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume);
#define DEV_PM_OPS (&rpcif_spi_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif
static struct platform_driver rpcif_spi_driver = {
.probe = rpcif_spi_probe,
.remove = rpcif_spi_remove,
.driver = {
.name = "rpc-if-spi",
.pm = DEV_PM_OPS,
},
};
module_platform_driver(rpcif_spi_driver);
MODULE_DESCRIPTION("Renesas RPC-IF SPI driver");
MODULE_LICENSE("GPL v2");

View File

@@ -130,9 +130,11 @@ struct s3c64xx_spi_dma_data {
* @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register.
* @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter.
* @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter.
* @quirks: Bitmask of known quirks
* @high_speed: True, if the controller supports HIGH_SPEED_EN bit.
* @clk_from_cmu: True, if the controller does not include a clock mux and
* prescaler unit.
* @clk_ioclk: True if clock is present on this device
*
* The Samsung s3c64xx SPI controller are used on various Samsung SoC's but
* differ in some aspects such as the size of the fifo and spi bus clock
@@ -154,6 +156,7 @@ struct s3c64xx_spi_port_config {
* @clk: Pointer to the spi clock.
* @src_clk: Pointer to the clock used to generate SPI signals.
* @ioclk: Pointer to the i/o clock between master and slave
* @pdev: Pointer to device's platform device data
* @master: Pointer to the SPI Protocol master.
* @cntrlr_info: Platform specific data for the controller this driver manages.
* @lock: Controller specific lock.
@@ -166,7 +169,11 @@ struct s3c64xx_spi_port_config {
* @xfer_completion: To indicate completion of xfer task.
* @cur_mode: Stores the active configuration of the controller.
* @cur_bpw: Stores the active bits per word settings.
* @cur_speed: Stores the active xfer clock speed.
* @cur_speed: Current clock speed
* @rx_dma: Local receive DMA data (e.g. chan and direction)
* @tx_dma: Local transmit DMA data (e.g. chan and direction)
* @port_conf: Local SPI port configuartion data
* @port_id: Port identification number
*/
struct s3c64xx_spi_driver_data {
void __iomem *regs;

View File

@@ -198,7 +198,7 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
{
return SUN4I_FIFO_DEPTH - 1;
return SUN4I_MAX_XFER_SIZE - 1;
}
static int sun4i_spi_transfer_one(struct spi_master *master,

View File

@@ -7,6 +7,7 @@
* Maxime Ripard <maxime.ripard@free-electrons.com>
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -58,10 +59,8 @@
#define SUN6I_FIFO_CTL_TF_RST BIT(31)
#define SUN6I_FIFO_STA_REG 0x1c
#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
#define SUN6I_FIFO_STA_RF_CNT_BITS 0
#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f
#define SUN6I_FIFO_STA_TF_CNT_BITS 16
#define SUN6I_FIFO_STA_RF_CNT_MASK GENMASK(7, 0)
#define SUN6I_FIFO_STA_TF_CNT_MASK GENMASK(23, 16)
#define SUN6I_CLK_CTL_REG 0x24
#define SUN6I_CLK_CTL_CDR2_MASK 0xff
@@ -73,13 +72,10 @@
#define SUN6I_MAX_XFER_SIZE 0xffffff
#define SUN6I_BURST_CNT_REG 0x30
#define SUN6I_BURST_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
#define SUN6I_XMIT_CNT_REG 0x34
#define SUN6I_XMIT_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
#define SUN6I_BURST_CTL_CNT_REG 0x38
#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
#define SUN6I_TXDATA_REG 0x200
#define SUN6I_RXDATA_REG 0x300
@@ -109,21 +105,18 @@ static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
writel(value, sspi->base_addr + reg);
}
static inline u32 sun6i_spi_get_rx_fifo_count(struct sun6i_spi *sspi)
{
u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
return FIELD_GET(SUN6I_FIFO_STA_RF_CNT_MASK, reg);
}
static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
{
u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
}
static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask)
{
u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
reg |= mask;
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
return FIELD_GET(SUN6I_FIFO_STA_TF_CNT_MASK, reg);
}
static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask)
@@ -134,18 +127,13 @@ static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask)
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
}
static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi)
{
u32 reg, cnt;
u32 len;
u8 byte;
/* See how much data is available */
reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
if (len > cnt)
len = cnt;
len = sun6i_spi_get_rx_fifo_count(sspi);
while (len--) {
byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
@@ -154,15 +142,16 @@ static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
}
}
static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
{
u32 cnt;
int len;
u8 byte;
/* See how much data we can fit */
cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
len = min3(len, (int)cnt, sspi->len);
len = min((int)cnt, sspi->len);
while (len--) {
byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
@@ -201,7 +190,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout;
unsigned int start, end, tx_time;
unsigned int trig_level;
unsigned int tx_len = 0;
unsigned int tx_len = 0, rx_len = 0;
int ret = 0;
u32 reg;
@@ -256,10 +245,12 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
* If it's a TX only transfer, we don't want to fill the RX
* FIFO with bogus data
*/
if (sspi->rx_buf)
if (sspi->rx_buf) {
reg &= ~SUN6I_TFR_CTL_DHB;
else
rx_len = tfr->len;
} else {
reg |= SUN6I_TFR_CTL_DHB;
}
/* We want to control the chip select manually */
reg |= SUN6I_TFR_CTL_CS_MANUAL;
@@ -291,9 +282,11 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
} else {
div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
reg = SUN6I_CLK_CTL_CDR1(div);
tfr->effective_speed_hz = mclk_rate / (1 << div);
}
sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
@@ -303,20 +296,22 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
tx_len = tfr->len;
/* Setup the counters */
sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len));
sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len));
sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
SUN6I_BURST_CTL_CNT_STC(tx_len));
sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, tfr->len);
sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len);
sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len);
/* Fill the TX FIFO */
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
sun6i_spi_fill_fifo(sspi);
/* Enable the interrupts */
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
SUN6I_INT_CTL_RF_RDY);
reg = SUN6I_INT_CTL_TC;
if (rx_len > sspi->fifo_depth)
reg |= SUN6I_INT_CTL_RF_RDY;
if (tx_len > sspi->fifo_depth)
sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
reg |= SUN6I_INT_CTL_TF_ERQ;
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
/* Start the transfer */
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -333,10 +328,8 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
dev_name(&spi->dev), tfr->len, tfr->speed_hz,
jiffies_to_msecs(end - start), tx_time);
ret = -ETIMEDOUT;
goto out;
}
out:
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
return ret;
@@ -350,14 +343,14 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
/* Transfer complete */
if (status & SUN6I_INT_CTL_TC) {
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
sun6i_spi_drain_fifo(sspi);
complete(&sspi->done);
return IRQ_HANDLED;
}
/* Receive FIFO 3/4 full */
if (status & SUN6I_INT_CTL_RF_RDY) {
sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
sun6i_spi_drain_fifo(sspi);
/* Only clear the interrupt _after_ draining the FIFO */
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY);
return IRQ_HANDLED;
@@ -365,7 +358,7 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
/* Transmit FIFO 3/4 empty */
if (status & SUN6I_INT_CTL_TF_ERQ) {
sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
sun6i_spi_fill_fifo(sspi);
if (!sspi->len)
/* nothing left to transmit */

View File

@@ -2,7 +2,7 @@
/*
* TI QSPI driver
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
* Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com
* Author: Sourav Poddar <sourav.poddar@ti.com>
*/

View File

@@ -122,6 +122,7 @@ struct pch_spi_dma_ctrl {
/**
* struct pch_spi_data - Holds the SPI channel specific details
* @io_remap_addr: The remapped PCI base address
* @io_base_addr: Base address
* @master: Pointer to the SPI master structure
* @work: Reference to work queue handler
* @wait: Wait queue for waking up upon receiving an
@@ -138,8 +139,8 @@ struct pch_spi_dma_ctrl {
* transfer
* @rx_index: Receive data count; for bookkeeping during
* transfer
* @tx_buff: Buffer for data to be transmitted
* @rx_index: Buffer for Received data
* @pkt_tx_buff: Buffer for data to be transmitted
* @pkt_rx_buff: Buffer for received data
* @n_curnt_chip: The chip number that this SPI driver currently
* operates on
* @current_chip: Reference to the current chip that this SPI
@@ -151,7 +152,10 @@ struct pch_spi_dma_ctrl {
* @board_dat: Reference to the SPI device data structure
* @plat_dev: platform_device structure
* @ch: SPI channel number
* @dma: Local DMA information
* @use_dma: True if DMA is to be used
* @irq_reg_sts: Status of IRQ registration
* @save_total_len: Save length while data is being transferred
*/
struct pch_spi_data {
void __iomem *io_remap_addr;
@@ -1631,64 +1635,37 @@ static void pch_spi_remove(struct pci_dev *pdev)
kfree(pd_dev_save);
}
#ifdef CONFIG_PM
static int pch_spi_suspend(struct pci_dev *pdev, pm_message_t state)
static int __maybe_unused pch_spi_suspend(struct device *dev)
{
int retval;
struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev);
struct pch_pd_dev_save *pd_dev_save = dev_get_drvdata(dev);
dev_dbg(&pdev->dev, "%s ENTRY\n", __func__);
dev_dbg(dev, "%s ENTRY\n", __func__);
pd_dev_save->board_dat->suspend_sts = true;
/* save config space */
retval = pci_save_state(pdev);
if (retval == 0) {
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
} else {
dev_err(&pdev->dev, "%s pci_save_state failed\n", __func__);
}
return retval;
return 0;
}
static int pch_spi_resume(struct pci_dev *pdev)
static int __maybe_unused pch_spi_resume(struct device *dev)
{
int retval;
struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev);
dev_dbg(&pdev->dev, "%s ENTRY\n", __func__);
struct pch_pd_dev_save *pd_dev_save = dev_get_drvdata(dev);
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
dev_dbg(dev, "%s ENTRY\n", __func__);
retval = pci_enable_device(pdev);
if (retval < 0) {
dev_err(&pdev->dev,
"%s pci_enable_device failed\n", __func__);
} else {
pci_enable_wake(pdev, PCI_D3hot, 0);
/* set suspend status to false */
pd_dev_save->board_dat->suspend_sts = false;
/* set suspend status to false */
pd_dev_save->board_dat->suspend_sts = false;
}
return retval;
return 0;
}
#else
#define pch_spi_suspend NULL
#define pch_spi_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(pch_spi_pm_ops, pch_spi_suspend, pch_spi_resume);
static struct pci_driver pch_spi_pcidev_driver = {
.name = "pch_spi",
.id_table = pch_spi_pcidev_id,
.probe = pch_spi_probe,
.remove = pch_spi_remove,
.suspend = pch_spi_suspend,
.resume = pch_spi_resume,
.driver.pm = &pch_spi_pm_ops,
};
static int __init pch_spi_init(void)

View File

@@ -119,6 +119,7 @@
/**
* struct zynq_qspi - Defines qspi driver instance
* @dev: Pointer to the this device's information
* @regs: Virtual address of the QSPI controller registers
* @refclk: Pointer to the peripheral clock
* @pclk: Pointer to the APB clock
@@ -316,7 +317,7 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
/**
* zynq_qspi_config_op - Configure QSPI controller for specified transfer
* @xqspi: Pointer to the zynq_qspi structure
* @qspi: Pointer to the spi_device structure
* @spi: Pointer to the spi_device structure
*
* Sets the operational mode of QSPI controller for the next QSPI transfer and
* sets the requested clock frequency.
@@ -527,20 +528,21 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem,
struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master);
int err = 0, i;
u8 *tmpbuf;
u8 opcode = op->cmd.opcode;
dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n",
op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
opcode, op->cmd.buswidth, op->addr.buswidth,
op->dummy.buswidth, op->data.buswidth);
zynq_qspi_chipselect(mem->spi, true);
zynq_qspi_config_op(xqspi, mem->spi);
if (op->cmd.opcode) {
if (op->cmd.nbytes) {
reinit_completion(&xqspi->data_completion);
xqspi->txbuf = (u8 *)&op->cmd.opcode;
xqspi->txbuf = &opcode;
xqspi->rxbuf = NULL;
xqspi->tx_bytes = sizeof(op->cmd.opcode);
xqspi->rx_bytes = sizeof(op->cmd.opcode);
xqspi->tx_bytes = op->cmd.nbytes;
xqspi->rx_bytes = op->cmd.nbytes;
zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true);
zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET,
ZYNQ_QSPI_IXR_RXTX_MASK);

View File

@@ -197,8 +197,8 @@ static inline void zynqmp_gqspi_write(struct zynqmp_qspi *xqspi, u32 offset,
/**
* zynqmp_gqspi_selectslave: For selection of slave device
* @instanceptr: Pointer to the zynqmp_qspi structure
* @flashcs: For chip select
* @flashbus: To check which bus is selected- upper or lower
* @slavecs: For chip select
* @slavebus: To check which bus is selected- upper or lower
*/
static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
u8 slavecs, u8 slavebus)
@@ -892,7 +892,7 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master,
/**
* zynqmp_qspi_suspend: Suspend method for the QSPI driver
* @_dev: Address of the platform_device structure
* @dev: Address of the platform_device structure
*
* This function stops the QSPI driver queue and disables the QSPI controller
*

View File

@@ -778,6 +778,17 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
{
bool enable1 = enable;
/*
* Avoid calling into the driver (or doing delays) if the chip select
* isn't actually changing from the last time this was called.
*/
if ((spi->controller->last_cs_enable == enable) &&
(spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
return;
spi->controller->last_cs_enable = enable;
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
if (!spi->controller->set_cs_timing) {
if (enable1)
spi_delay_exec(&spi->controller->cs_setup, NULL);
@@ -982,6 +993,8 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg)
spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
}
ctlr->cur_msg_mapped = false;
return 0;
}
#else /* !CONFIG_HAS_DMA */
@@ -1234,8 +1247,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
if (xfer->tx_buf || xfer->rx_buf) {
reinit_completion(&ctlr->xfer_completion);
fallback_pio:
ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
if (ret < 0) {
if (ctlr->cur_msg_mapped &&
(xfer->error & SPI_TRANS_FAIL_NO_START)) {
__spi_unmap_msg(ctlr, msg);
ctlr->fallback = true;
xfer->error &= ~SPI_TRANS_FAIL_NO_START;
goto fallback_pio;
}
SPI_STATISTICS_INCREMENT_FIELD(statm,
errors);
SPI_STATISTICS_INCREMENT_FIELD(stats,
@@ -1314,6 +1336,14 @@ void spi_finalize_current_transfer(struct spi_controller *ctlr)
}
EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
static void spi_idle_runtime_pm(struct spi_controller *ctlr)
{
if (ctlr->auto_runtime_pm) {
pm_runtime_mark_last_busy(ctlr->dev.parent);
pm_runtime_put_autosuspend(ctlr->dev.parent);
}
}
/**
* __spi_pump_messages - function which processes spi message queue
* @ctlr: controller to process queue for
@@ -1346,7 +1376,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
/* If another context is idling the device then defer */
if (ctlr->idling) {
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return;
}
@@ -1358,10 +1388,17 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
return;
}
/* Only do teardown in the thread */
/* Defer any non-atomic teardown to the thread */
if (!in_kthread) {
kthread_queue_work(&ctlr->kworker,
&ctlr->pump_messages);
if (!ctlr->dummy_rx && !ctlr->dummy_tx &&
!ctlr->unprepare_transfer_hardware) {
spi_idle_runtime_pm(ctlr);
ctlr->busy = false;
trace_spi_controller_idle(ctlr);
} else {
kthread_queue_work(ctlr->kworker,
&ctlr->pump_messages);
}
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return;
}
@@ -1378,10 +1415,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
ctlr->unprepare_transfer_hardware(ctlr))
dev_err(&ctlr->dev,
"failed to unprepare transfer hardware\n");
if (ctlr->auto_runtime_pm) {
pm_runtime_mark_last_busy(ctlr->dev.parent);
pm_runtime_put_autosuspend(ctlr->dev.parent);
}
spi_idle_runtime_pm(ctlr);
trace_spi_controller_idle(ctlr);
spin_lock_irqsave(&ctlr->queue_lock, flags);
@@ -1596,7 +1630,7 @@ static void spi_set_thread_rt(struct spi_controller *ctlr)
dev_info(&ctlr->dev,
"will run message pump with realtime priority\n");
sched_setscheduler(ctlr->kworker_task, SCHED_FIFO, &param);
sched_setscheduler(ctlr->kworker->task, SCHED_FIFO, &param);
}
static int spi_init_queue(struct spi_controller *ctlr)
@@ -1604,13 +1638,12 @@ static int spi_init_queue(struct spi_controller *ctlr)
ctlr->running = false;
ctlr->busy = false;
kthread_init_worker(&ctlr->kworker);
ctlr->kworker_task = kthread_run(kthread_worker_fn, &ctlr->kworker,
"%s", dev_name(&ctlr->dev));
if (IS_ERR(ctlr->kworker_task)) {
dev_err(&ctlr->dev, "failed to create message pump task\n");
return PTR_ERR(ctlr->kworker_task);
ctlr->kworker = kthread_create_worker(0, dev_name(&ctlr->dev));
if (IS_ERR(ctlr->kworker)) {
dev_err(&ctlr->dev, "failed to create message pump kworker\n");
return PTR_ERR(ctlr->kworker);
}
kthread_init_work(&ctlr->pump_messages, spi_pump_messages);
/*
@@ -1693,7 +1726,8 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
spin_lock_irqsave(&ctlr->queue_lock, flags);
ctlr->cur_msg = NULL;
ctlr->cur_msg_prepared = false;
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
ctlr->fallback = false;
kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
trace_spi_message_done(mesg);
@@ -1719,7 +1753,7 @@ static int spi_start_queue(struct spi_controller *ctlr)
ctlr->cur_msg = NULL;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
return 0;
}
@@ -1775,8 +1809,7 @@ static int spi_destroy_queue(struct spi_controller *ctlr)
return ret;
}
kthread_flush_worker(&ctlr->kworker);
kthread_stop(ctlr->kworker_task);
kthread_destroy_worker(ctlr->kworker);
return 0;
}
@@ -1799,7 +1832,7 @@ static int __spi_queued_transfer(struct spi_device *spi,
list_add_tail(&msg->queue, &ctlr->queue);
if (!ctlr->busy && need_pump)
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
kthread_queue_work(ctlr->kworker, &ctlr->pump_messages);
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return 0;

View File

@@ -224,6 +224,11 @@ static int spidev_message(struct spidev_data *spidev,
for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
n;
n--, k_tmp++, u_tmp++) {
/* Ensure that also following allocations from rx_buf/tx_buf will meet
* DMA alignment requirements.
*/
unsigned int len_aligned = ALIGN(u_tmp->len, ARCH_KMALLOC_MINALIGN);
k_tmp->len = u_tmp->len;
total += k_tmp->len;
@@ -239,17 +244,17 @@ static int spidev_message(struct spidev_data *spidev,
if (u_tmp->rx_buf) {
/* this transfer needs space in RX bounce buffer */
rx_total += k_tmp->len;
rx_total += len_aligned;
if (rx_total > bufsiz) {
status = -EMSGSIZE;
goto done;
}
k_tmp->rx_buf = rx_buf;
rx_buf += k_tmp->len;
rx_buf += len_aligned;
}
if (u_tmp->tx_buf) {
/* this transfer needs space in TX bounce buffer */
tx_total += k_tmp->len;
tx_total += len_aligned;
if (tx_total > bufsiz) {
status = -EMSGSIZE;
goto done;
@@ -259,7 +264,7 @@ static int spidev_message(struct spidev_data *spidev,
(uintptr_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
tx_buf += k_tmp->len;
tx_buf += len_aligned;
}
k_tmp->cs_change = !!u_tmp->cs_change;
@@ -293,16 +298,16 @@ static int spidev_message(struct spidev_data *spidev,
goto done;
/* copy any rx data out of bounce buffer */
rx_buf = spidev->rx_buffer;
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
n;
n--, k_tmp++, u_tmp++) {
if (u_tmp->rx_buf) {
if (copy_to_user((u8 __user *)
(uintptr_t) u_tmp->rx_buf, rx_buf,
(uintptr_t) u_tmp->rx_buf, k_tmp->rx_buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
}
rx_buf += u_tmp->len;
}
}
status = total;