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:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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 = {
|
||||
|
@@ -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",
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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");
|
||||
|
@@ -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 */
|
||||
|
@@ -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)
|
||||
|
1419
drivers/spi/spi-cadence-quadspi.c
Normal file
1419
drivers/spi/spi-cadence-quadspi.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
@@ -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 = ®_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(®_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;
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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)) {
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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>
|
||||
*
|
||||
|
@@ -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>
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
216
drivers/spi/spi-rpc-if.c
Normal 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");
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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 */
|
||||
|
@@ -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>
|
||||
*/
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -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, ¶m);
|
||||
sched_setscheduler(ctlr->kworker->task, SCHED_FIFO, ¶m);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user