spi: Updates for v5.11
The big change this release has been some excellent work from Lukas Wunner which closes a bunch of holes in the cleanup paths for drivers, mainly introduced as a result of devm conversions causing bad interactions with the support SPI has for allocating the bus and driver data together. Together with some of the other work done it feels like we've turned the corner on several long standing pain points with the API. - Many cleanups around probe/remove and error handling from Lukas Wunner and Uwe Kleine-König, and further fixes around PM from Zhang Qilong. - Provide a mask for which bits of the mode can safely be configured by drivers and use that to fix an issue with the ADS7846 driver. - Documentation of the expected interactions between SPI and GPIO level chip select polarity configuration from H. Nikolaus Schaller, hopefully we're pretty much at the end of sorting out the interactions there. Thanks to Nikolaus, Sven Van Asbroeck and Linus Walleij for this. - DMA support for Allwinner sun6i controllers. - Support for Canaan K210 Designware implementations and Intel Adler Lake. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl/Xeg4ACgkQJNaLcl1U h9BbXQf8DwmtP/biVsB0yxag11Ac9xxDL2OdMXia/DBQZsVSxqGld4l7Bwl8CMVi TISCmzO1f53l3KZK5wu1C5mV8tXgCu4zrsPErEsrK2V2+s+4lWy10MOfAHqq/lBR L2kifZ/uoeMBaPvJqpRimM8tv2uPXPHOKsdy2G82LzMdk0OhE5p9IkL5Nc5JbKOl X1iWTAxtUsDb8+B57AwHSMnL4R3pb/01N0PguJJ8DGol7Oj6VcDf7nh/tqvVkEot Ku731oCBQwBhkZKOqd7mvQAjPyoJiFPI8nofC4Bj+a1BDlr+pRcILQ4469zaIAWT nPV6BoHTu/tVV63j8YhuamjWYAsS0g== =ezV7 -----END PGP SIGNATURE----- Merge tag 'spi-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi updates from Mark Brown: "The big change this release has been some excellent work from Lukas Wunner which closes a bunch of holes in the cleanup paths for drivers, mainly introduced as a result of devm conversions causing bad interactions with the support SPI has for allocating the bus and driver data together. Together with some of the other work done it feels like we've turned the corner on several long standing pain points with the API. Summary: - Many cleanups around probe/remove and error handling from Lukas Wunner and Uwe Kleine-König, and further fixes around PM from Zhang Qilong. - Provide a mask for which bits of the mode can safely be configured by drivers and use that to fix an issue with the ADS7846 driver. - Documentation of the expected interactions between SPI and GPIO level chip select polarity configuration from H. Nikolaus Schaller, hopefully we're pretty much at the end of sorting out the interactions there. Thanks to Nikolaus, Sven Van Asbroeck and Linus Walleij for this. - DMA support for Allwinner sun6i controllers. - Support for Canaan K210 Designware implementations and Intel Adler Lake" * tag 'spi-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (69 commits) spi: dt-bindings: clarify CS behavior for spi-cs-high and gpio descriptors spi: Limit the spi device max speed to controller's max speed spi: spi-geni-qcom: Use the new method of gpio CS control platform/chrome: cros_ec_spi: Drop bits_per_word assignment platform/chrome: cros_ec_spi: Don't overwrite spi::mode spi: dw: Add support for the Canaan K210 SoC SPI spi: dw: Add support for 32-bits max xfer size dt-bindings: spi: dw-apb-ssi: Add Canaan K210 SPI controller spi: Update DT binding docs to support SiFive FU740 SoC spi: atmel-quadspi: Fix use-after-free on unbind spi: npcm-fiu: Disable clock in probe error path spi: ar934x: Don't leak SPI master in probe error path spi: mt7621: Don't leak SPI master in probe error path spi: mt7621: Disable clock in probe error path media: netup_unidvb: Don't leak SPI master in probe error path spi: sc18is602: Don't leak SPI master in probe error path spi: rb4xx: Don't leak SPI master in probe error path spi: gpio: Don't leak SPI master in probe error path spi: spi-mtk-nor: Don't leak SPI master in probe error path spi: mxic: Don't leak SPI master in probe error path ...
This commit is contained in:
commit
605ea5aafe
@ -65,6 +65,8 @@ properties:
|
||||
const: baikal,bt1-ssi
|
||||
- description: Baikal-T1 System Boot SPI Controller
|
||||
const: baikal,bt1-sys-ssi
|
||||
- description: Canaan Kendryte K210 SoS SPI Controller
|
||||
const: canaan,k210-spi
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
|
@ -42,6 +42,33 @@ properties:
|
||||
cs2 : &gpio1 1 0
|
||||
cs3 : &gpio1 2 0
|
||||
|
||||
The second flag of a gpio descriptor can be GPIO_ACTIVE_HIGH (0)
|
||||
or GPIO_ACTIVE_LOW(1). Legacy device trees often use 0.
|
||||
|
||||
There is a special rule set for combining the second flag of an
|
||||
cs-gpio with the optional spi-cs-high flag for SPI slaves.
|
||||
|
||||
Each table entry defines how the CS pin is to be physically
|
||||
driven (not considering potential gpio inversions by pinmux):
|
||||
|
||||
device node | cs-gpio | CS pin state active | Note
|
||||
================+===============+=====================+=====
|
||||
spi-cs-high | - | H |
|
||||
- | - | L |
|
||||
spi-cs-high | ACTIVE_HIGH | H |
|
||||
- | ACTIVE_HIGH | L | 1
|
||||
spi-cs-high | ACTIVE_LOW | H | 2
|
||||
- | ACTIVE_LOW | L |
|
||||
|
||||
Notes:
|
||||
1) Should print a warning about polarity inversion.
|
||||
Here it would be wise to avoid and define the gpio as
|
||||
ACTIVE_LOW.
|
||||
2) Should print a warning about polarity inversion
|
||||
because ACTIVE_LOW is overridden by spi-cs-high.
|
||||
Should be generally avoided and be replaced by
|
||||
spi-cs-high + ACTIVE_HIGH.
|
||||
|
||||
num-cs:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
|
@ -17,15 +17,17 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sifive,fu540-c000-spi
|
||||
- enum:
|
||||
- sifive,fu540-c000-spi
|
||||
- sifive,fu740-c000-spi
|
||||
- const: sifive,spi0
|
||||
|
||||
description:
|
||||
Should be "sifive,<chip>-spi" and "sifive,spi<version>".
|
||||
Supported compatible strings are -
|
||||
"sifive,fu540-c000-spi" for the SiFive SPI v0 as integrated
|
||||
onto the SiFive FU540 chip, and "sifive,spi0" for the SiFive
|
||||
SPI v0 IP block with no chip integration tweaks.
|
||||
"sifive,fu540-c000-spi" and "sifive,fu740-c000-spi" for the SiFive SPI v0
|
||||
as integrated onto the SiFive FU540 and FU740 chip resp, and "sifive,spi0"
|
||||
for the SiFive SPI v0 IP block with no chip integration tweaks.
|
||||
Please refer to sifive-blocks-ip-versioning.txt for details
|
||||
|
||||
SPI RTL that corresponds to the IP block version numbers can be found here -
|
||||
|
@ -1288,7 +1288,8 @@ static int ads7846_probe(struct spi_device *spi)
|
||||
* may not. So we stick to very-portable 8 bit words, both RX and TX.
|
||||
*/
|
||||
spi->bits_per_word = 8;
|
||||
spi->mode = SPI_MODE_0;
|
||||
spi->mode &= ~SPI_MODE_X_MASK;
|
||||
spi->mode |= SPI_MODE_0;
|
||||
err = spi_setup(spi);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -175,7 +175,7 @@ int netup_spi_init(struct netup_unidvb_dev *ndev)
|
||||
struct spi_master *master;
|
||||
struct netup_spi *nspi;
|
||||
|
||||
master = spi_alloc_master(&ndev->pci_dev->dev,
|
||||
master = devm_spi_alloc_master(&ndev->pci_dev->dev,
|
||||
sizeof(struct netup_spi));
|
||||
if (!master) {
|
||||
dev_err(&ndev->pci_dev->dev,
|
||||
@ -208,6 +208,7 @@ int netup_spi_init(struct netup_unidvb_dev *ndev)
|
||||
ndev->pci_slot,
|
||||
ndev->pci_func);
|
||||
if (!spi_new_device(master, &netup_spi_board)) {
|
||||
spi_unregister_master(master);
|
||||
ndev->spi = NULL;
|
||||
dev_err(&ndev->pci_dev->dev,
|
||||
"%s(): unable to create SPI device\n", __func__);
|
||||
@ -226,13 +227,13 @@ void netup_spi_release(struct netup_unidvb_dev *ndev)
|
||||
if (!spi)
|
||||
return;
|
||||
|
||||
spi_unregister_master(spi->master);
|
||||
spin_lock_irqsave(&spi->lock, flags);
|
||||
reg = readw(&spi->regs->control_stat);
|
||||
writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat);
|
||||
reg = readw(&spi->regs->control_stat);
|
||||
writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat);
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
spi_unregister_master(spi->master);
|
||||
ndev->spi = NULL;
|
||||
}
|
||||
|
||||
|
@ -741,8 +741,6 @@ static int cros_ec_spi_probe(struct spi_device *spi)
|
||||
struct cros_ec_spi *ec_spi;
|
||||
int err;
|
||||
|
||||
spi->bits_per_word = 8;
|
||||
spi->mode = SPI_MODE_0;
|
||||
spi->rt = true;
|
||||
err = spi_setup(spi);
|
||||
if (err < 0)
|
||||
|
@ -255,6 +255,8 @@ config SPI_DW_MMIO
|
||||
config SPI_DW_BT1
|
||||
tristate "Baikal-T1 SPI driver for DW SPI core"
|
||||
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
|
||||
select MULTIPLEXER
|
||||
select MUX_MMIO
|
||||
help
|
||||
Baikal-T1 SoC is equipped with three DW APB SSI-based MMIO SPI
|
||||
controllers. Two of them are pretty much normal: with IRQ, DMA,
|
||||
@ -268,8 +270,6 @@ config SPI_DW_BT1
|
||||
config SPI_DW_BT1_DIRMAP
|
||||
bool "Directly mapped Baikal-T1 Boot SPI flash support"
|
||||
depends on SPI_DW_BT1
|
||||
select MULTIPLEXER
|
||||
select MUX_MMIO
|
||||
help
|
||||
Directly mapped SPI flash memory is an interface specific to the
|
||||
Baikal-T1 System Boot Controller. It is a 16MB MMIO region, which
|
||||
|
@ -365,10 +365,14 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
|
||||
if (dummy_cycles)
|
||||
ifr |= QSPI_IFR_NBDUM(dummy_cycles);
|
||||
|
||||
/* Set data enable */
|
||||
if (op->data.nbytes)
|
||||
/* Set data enable and data transfer type. */
|
||||
if (op->data.nbytes) {
|
||||
ifr |= QSPI_IFR_DATAEN;
|
||||
|
||||
if (op->addr.nbytes)
|
||||
ifr |= QSPI_IFR_TFRTYP_MEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the QSPI controller is set in regular SPI mode, set it in
|
||||
* Serial Memory Mode (SMM).
|
||||
@ -381,27 +385,24 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
|
||||
/* Clear pending interrupts */
|
||||
(void)atmel_qspi_read(aq, QSPI_SR);
|
||||
|
||||
if (aq->caps->has_ricr) {
|
||||
if (!op->addr.nbytes && op->data.dir == SPI_MEM_DATA_IN)
|
||||
ifr |= QSPI_IFR_APBTFRTYP_READ;
|
||||
|
||||
/* Set QSPI Instruction Frame registers */
|
||||
/* Set QSPI Instruction Frame registers. */
|
||||
if (op->addr.nbytes && !op->data.nbytes)
|
||||
atmel_qspi_write(iar, aq, QSPI_IAR);
|
||||
|
||||
if (aq->caps->has_ricr) {
|
||||
if (op->data.dir == SPI_MEM_DATA_IN)
|
||||
atmel_qspi_write(icr, aq, QSPI_RICR);
|
||||
else
|
||||
atmel_qspi_write(icr, aq, QSPI_WICR);
|
||||
atmel_qspi_write(ifr, aq, QSPI_IFR);
|
||||
} else {
|
||||
if (op->data.dir == SPI_MEM_DATA_OUT)
|
||||
if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
|
||||
ifr |= QSPI_IFR_SAMA5D2_WRITE_TRSFR;
|
||||
|
||||
/* Set QSPI Instruction Frame registers */
|
||||
atmel_qspi_write(iar, aq, QSPI_IAR);
|
||||
atmel_qspi_write(icr, aq, QSPI_ICR);
|
||||
atmel_qspi_write(ifr, aq, QSPI_IFR);
|
||||
}
|
||||
|
||||
atmel_qspi_write(ifr, aq, QSPI_IFR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -535,7 +536,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int irq, err = 0;
|
||||
|
||||
ctrl = spi_alloc_master(&pdev->dev, sizeof(*aq));
|
||||
ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*aq));
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -557,8 +558,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
aq->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(aq->regs)) {
|
||||
dev_err(&pdev->dev, "missing registers\n");
|
||||
err = PTR_ERR(aq->regs);
|
||||
goto exit;
|
||||
return PTR_ERR(aq->regs);
|
||||
}
|
||||
|
||||
/* Map the AHB memory */
|
||||
@ -566,8 +566,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
aq->mem = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(aq->mem)) {
|
||||
dev_err(&pdev->dev, "missing AHB memory\n");
|
||||
err = PTR_ERR(aq->mem);
|
||||
goto exit;
|
||||
return PTR_ERR(aq->mem);
|
||||
}
|
||||
|
||||
aq->mmap_size = resource_size(res);
|
||||
@ -579,22 +578,21 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
|
||||
if (IS_ERR(aq->pclk)) {
|
||||
dev_err(&pdev->dev, "missing peripheral clock\n");
|
||||
err = PTR_ERR(aq->pclk);
|
||||
goto exit;
|
||||
return PTR_ERR(aq->pclk);
|
||||
}
|
||||
|
||||
/* Enable the peripheral clock */
|
||||
err = clk_prepare_enable(aq->pclk);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to enable the peripheral clock\n");
|
||||
goto exit;
|
||||
return err;
|
||||
}
|
||||
|
||||
aq->caps = of_device_get_match_data(&pdev->dev);
|
||||
if (!aq->caps) {
|
||||
dev_err(&pdev->dev, "Could not retrieve QSPI caps\n");
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
goto disable_pclk;
|
||||
}
|
||||
|
||||
if (aq->caps->has_qspick) {
|
||||
@ -638,8 +636,6 @@ disable_qspick:
|
||||
clk_disable_unprepare(aq->qspick);
|
||||
disable_pclk:
|
||||
clk_disable_unprepare(aq->pclk);
|
||||
exit:
|
||||
spi_controller_put(ctrl);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -250,7 +250,6 @@ static int amd_spi_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spi_master *master;
|
||||
struct amd_spi *amd_spi;
|
||||
struct resource *res;
|
||||
int err = 0;
|
||||
|
||||
/* Allocate storage for spi_master and driver private data */
|
||||
@ -261,9 +260,7 @@ static int amd_spi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
amd_spi = spi_master_get_devdata(master);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
amd_spi->io_remap_addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(amd_spi->io_remap_addr)) {
|
||||
err = PTR_ERR(amd_spi->io_remap_addr);
|
||||
dev_err(dev, "error %d ioremap of SPI registers failed\n", err);
|
||||
|
@ -176,10 +176,11 @@ static int ar934x_spi_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||
ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||
if (!ctlr) {
|
||||
dev_info(&pdev->dev, "failed to allocate spi controller\n");
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
/* disable flash mapping and expose spi controller registers */
|
||||
@ -202,7 +203,13 @@ static int ar934x_spi_probe(struct platform_device *pdev)
|
||||
sp->clk_freq = clk_get_rate(clk);
|
||||
sp->ctlr = ctlr;
|
||||
|
||||
return devm_spi_register_controller(&pdev->dev, ctlr);
|
||||
ret = spi_register_controller(ctlr);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
err_clk_disable:
|
||||
clk_disable_unprepare(clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ar934x_spi_remove(struct platform_device *pdev)
|
||||
@ -213,6 +220,7 @@ static int ar934x_spi_remove(struct platform_device *pdev)
|
||||
ctlr = dev_get_drvdata(&pdev->dev);
|
||||
sp = spi_controller_get_devdata(ctlr);
|
||||
|
||||
spi_unregister_controller(ctlr);
|
||||
clk_disable_unprepare(sp->clk);
|
||||
|
||||
return 0;
|
||||
|
@ -512,8 +512,8 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
||||
|
||||
master->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
err = dev_err_probe(dev, PTR_ERR(master->dma_tx),
|
||||
"No TX DMA channel, DMA is disabled\n");
|
||||
err = PTR_ERR(master->dma_tx);
|
||||
dev_dbg(dev, "No TX DMA channel, DMA is disabled\n");
|
||||
goto error_clear;
|
||||
}
|
||||
|
||||
@ -524,7 +524,7 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
||||
* No reason to check EPROBE_DEFER here since we have already
|
||||
* requested tx channel.
|
||||
*/
|
||||
dev_err(dev, "No RX DMA channel, DMA is disabled\n");
|
||||
dev_dbg(dev, "No RX DMA channel, DMA is disabled\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -494,8 +494,10 @@ static int bcm63xx_hsspi_resume(struct device *dev)
|
||||
|
||||
if (bs->pll_clk) {
|
||||
ret = clk_prepare_enable(bs->pll_clk);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
clk_disable_unprepare(bs->clk);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
spi_master_resume(master);
|
||||
|
@ -1040,13 +1040,13 @@ static int davinci_spi_remove(struct platform_device *pdev)
|
||||
spi_bitbang_stop(&dspi->bitbang);
|
||||
|
||||
clk_disable_unprepare(dspi->clk);
|
||||
spi_master_put(master);
|
||||
|
||||
if (dspi->dma_rx) {
|
||||
dma_release_channel(dspi->dma_rx);
|
||||
dma_release_channel(dspi->dma_tx);
|
||||
}
|
||||
|
||||
spi_master_put(master);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ static int dw_spi_bt1_sys_init(struct platform_device *pdev,
|
||||
if (mem) {
|
||||
dwsbt1->map = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (!IS_ERR(dwsbt1->map)) {
|
||||
dwsbt1->map_len = (mem->end - mem->start + 1);
|
||||
dwsbt1->map_len = resource_size(mem);
|
||||
dws->mem_ops.dirmap_create = dw_spi_bt1_dirmap_create;
|
||||
dws->mem_ops.dirmap_read = dw_spi_bt1_dirmap_read;
|
||||
} else {
|
||||
@ -280,8 +280,10 @@ static int dw_spi_bt1_probe(struct platform_device *pdev)
|
||||
dws->bus_num = pdev->id;
|
||||
dws->reg_io_width = 4;
|
||||
dws->max_freq = clk_get_rate(dwsbt1->clk);
|
||||
if (!dws->max_freq)
|
||||
if (!dws->max_freq) {
|
||||
ret = -EINVAL;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
init_func = device_get_match_data(&pdev->dev);
|
||||
ret = init_func(pdev, dwsbt1);
|
||||
|
@ -137,14 +137,16 @@ static inline u32 rx_max(struct dw_spi *dws)
|
||||
static void dw_writer(struct dw_spi *dws)
|
||||
{
|
||||
u32 max = tx_max(dws);
|
||||
u16 txw = 0;
|
||||
u32 txw = 0;
|
||||
|
||||
while (max--) {
|
||||
if (dws->tx) {
|
||||
if (dws->n_bytes == 1)
|
||||
txw = *(u8 *)(dws->tx);
|
||||
else
|
||||
else if (dws->n_bytes == 2)
|
||||
txw = *(u16 *)(dws->tx);
|
||||
else
|
||||
txw = *(u32 *)(dws->tx);
|
||||
|
||||
dws->tx += dws->n_bytes;
|
||||
}
|
||||
@ -156,15 +158,17 @@ static void dw_writer(struct dw_spi *dws)
|
||||
static void dw_reader(struct dw_spi *dws)
|
||||
{
|
||||
u32 max = rx_max(dws);
|
||||
u16 rxw;
|
||||
u32 rxw;
|
||||
|
||||
while (max--) {
|
||||
rxw = dw_read_io_reg(dws, DW_SPI_DR);
|
||||
if (dws->rx) {
|
||||
if (dws->n_bytes == 1)
|
||||
*(u8 *)(dws->rx) = rxw;
|
||||
else
|
||||
else if (dws->n_bytes == 2)
|
||||
*(u16 *)(dws->rx) = rxw;
|
||||
else
|
||||
*(u32 *)(dws->rx) = rxw;
|
||||
|
||||
dws->rx += dws->n_bytes;
|
||||
}
|
||||
@ -311,8 +315,8 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
|
||||
u32 speed_hz;
|
||||
u16 clk_div;
|
||||
|
||||
/* CTRLR0[ 4/3: 0] Data Frame Size */
|
||||
cr0 |= (cfg->dfs - 1);
|
||||
/* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */
|
||||
cr0 |= (cfg->dfs - 1) << dws->dfs_offset;
|
||||
|
||||
if (!(dws->caps & DW_SPI_CAP_DWC_SSI))
|
||||
/* CTRLR0[ 9:8] Transfer Mode */
|
||||
@ -828,6 +832,29 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
|
||||
dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect CTRLR0.DFS field size and offset by testing the lowest bits
|
||||
* writability. Note DWC SSI controller also has the extended DFS, but
|
||||
* with zero offset.
|
||||
*/
|
||||
if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) {
|
||||
u32 cr0, tmp = dw_readl(dws, DW_SPI_CTRLR0);
|
||||
|
||||
spi_enable_chip(dws, 0);
|
||||
dw_writel(dws, DW_SPI_CTRLR0, 0xffffffff);
|
||||
cr0 = dw_readl(dws, DW_SPI_CTRLR0);
|
||||
dw_writel(dws, DW_SPI_CTRLR0, tmp);
|
||||
spi_enable_chip(dws, 1);
|
||||
|
||||
if (!(cr0 & SPI_DFS_MASK)) {
|
||||
dws->caps |= DW_SPI_CAP_DFS32;
|
||||
dws->dfs_offset = SPI_DFS32_OFFSET;
|
||||
dev_dbg(dev, "Detected 32-bits max data frame size\n");
|
||||
}
|
||||
} else {
|
||||
dws->caps |= DW_SPI_CAP_DFS32;
|
||||
}
|
||||
|
||||
/* enable HW fixup for explicit CS deselect for Amazon's alpine chip */
|
||||
if (dws->caps & DW_SPI_CAP_CS_OVERRIDE)
|
||||
dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);
|
||||
@ -864,7 +891,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||
|
||||
master->use_gpio_descriptors = true;
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
|
||||
if (dws->caps & DW_SPI_CAP_DFS32)
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||
else
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
|
||||
master->bus_num = dws->bus_num;
|
||||
master->num_chipselect = dws->num_cs;
|
||||
master->setup = dw_spi_setup;
|
||||
|
@ -222,6 +222,21 @@ static int dw_spi_keembay_init(struct platform_device *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_spi_canaan_k210_init(struct platform_device *pdev,
|
||||
struct dw_spi_mmio *dwsmmio)
|
||||
{
|
||||
/*
|
||||
* The Canaan Kendryte K210 SoC DW apb_ssi v4 spi controller is
|
||||
* documented to have a 32 word deep TX and RX FIFO, which
|
||||
* spi_hw_init() detects. However, when the RX FIFO is filled up to
|
||||
* 32 entries (RXFLR = 32), an RX FIFO overrun error occurs. Avoid this
|
||||
* problem by force setting fifo_len to 31.
|
||||
*/
|
||||
dwsmmio->dws.fifo_len = 31;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int (*init_func)(struct platform_device *pdev,
|
||||
@ -335,6 +350,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
|
||||
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
|
||||
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
|
||||
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
|
||||
{ .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
|
||||
{ /* end of table */}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
/* Register offsets */
|
||||
#define DW_SPI_CTRLR0 0x00
|
||||
@ -41,6 +42,8 @@
|
||||
|
||||
/* Bit fields in CTRLR0 */
|
||||
#define SPI_DFS_OFFSET 0
|
||||
#define SPI_DFS_MASK GENMASK(3, 0)
|
||||
#define SPI_DFS32_OFFSET 16
|
||||
|
||||
#define SPI_FRF_OFFSET 4
|
||||
#define SPI_FRF_SPI 0x0
|
||||
@ -121,6 +124,7 @@ enum dw_ssi_type {
|
||||
#define DW_SPI_CAP_CS_OVERRIDE BIT(0)
|
||||
#define DW_SPI_CAP_KEEMBAY_MST BIT(1)
|
||||
#define DW_SPI_CAP_DWC_SSI BIT(2)
|
||||
#define DW_SPI_CAP_DFS32 BIT(3)
|
||||
|
||||
/* Slave spi_transfer/spi_mem_op related */
|
||||
struct dw_spi_cfg {
|
||||
@ -148,6 +152,7 @@ struct dw_spi {
|
||||
unsigned long paddr;
|
||||
int irq;
|
||||
u32 fifo_len; /* depth of the FIFO buffer */
|
||||
unsigned int dfs_offset; /* CTRLR0 DFS field offset */
|
||||
u32 max_mem_freq; /* max mem-ops bus freq */
|
||||
u32 max_freq; /* max bus freq supported */
|
||||
|
||||
|
@ -1165,7 +1165,7 @@ static int dspi_init(struct fsl_dspi *dspi)
|
||||
unsigned int mcr;
|
||||
|
||||
/* Set idle states for all chip select signals to high */
|
||||
mcr = SPI_MCR_PCSIS(GENMASK(dspi->ctlr->num_chipselect - 1, 0));
|
||||
mcr = SPI_MCR_PCSIS(GENMASK(dspi->ctlr->max_native_cs - 1, 0));
|
||||
|
||||
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
|
||||
mcr |= SPI_MCR_XSPI;
|
||||
@ -1250,7 +1250,7 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
if (pdata) {
|
||||
ctlr->num_chipselect = pdata->cs_num;
|
||||
ctlr->num_chipselect = ctlr->max_native_cs = pdata->cs_num;
|
||||
ctlr->bus_num = pdata->bus_num;
|
||||
|
||||
/* Only Coldfire uses platform data */
|
||||
@ -1263,7 +1263,7 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "can't get spi-num-chipselects\n");
|
||||
goto out_ctlr_put;
|
||||
}
|
||||
ctlr->num_chipselect = cs_num;
|
||||
ctlr->num_chipselect = ctlr->max_native_cs = cs_num;
|
||||
|
||||
of_property_read_u32(np, "bus-num", &bus_num);
|
||||
ctlr->bus_num = bus_num;
|
||||
|
@ -716,10 +716,11 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
|
||||
type = fsl_spi_get_type(&ofdev->dev);
|
||||
if (type == TYPE_FSL) {
|
||||
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
|
||||
bool spisel_boot = false;
|
||||
#if IS_ENABLED(CONFIG_FSL_SOC)
|
||||
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
|
||||
bool spisel_boot = of_property_read_bool(np, "fsl,spisel_boot");
|
||||
|
||||
spisel_boot = of_property_read_bool(np, "fsl,spisel_boot");
|
||||
if (spisel_boot) {
|
||||
pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4);
|
||||
if (!pinfo->immr_spi_cs)
|
||||
@ -734,10 +735,14 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
|
||||
* supported on the GRLIB variant.
|
||||
*/
|
||||
ret = gpiod_count(dev, "cs");
|
||||
if (ret <= 0)
|
||||
if (ret < 0)
|
||||
ret = 0;
|
||||
if (ret == 0 && !spisel_boot) {
|
||||
pdata->max_chipselect = 1;
|
||||
else
|
||||
} else {
|
||||
pdata->max_chipselect = ret + spisel_boot;
|
||||
pdata->cs_control = fsl_spi_cs_control;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(np, 0, &mem);
|
||||
|
@ -603,7 +603,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
spi = spi_alloc_master(dev, sizeof(*mas));
|
||||
spi = devm_spi_alloc_master(dev, sizeof(*mas));
|
||||
if (!spi)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -636,6 +636,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
spi->auto_runtime_pm = true;
|
||||
spi->handle_err = handle_fifo_timeout;
|
||||
spi->set_cs = spi_geni_set_cs;
|
||||
spi->use_gpio_descriptors = true;
|
||||
|
||||
init_completion(&mas->cs_done);
|
||||
init_completion(&mas->cancel_done);
|
||||
@ -673,7 +674,6 @@ spi_geni_probe_free_irq:
|
||||
free_irq(mas->irq, spi);
|
||||
spi_geni_probe_runtime_disable:
|
||||
pm_runtime_disable(dev);
|
||||
spi_master_put(spi);
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
put_clkname:
|
||||
dev_pm_opp_put_clkname(mas->se.opp_table);
|
||||
|
@ -350,11 +350,6 @@ static int spi_gpio_probe_pdata(struct platform_device *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spi_gpio_put(void *data)
|
||||
{
|
||||
spi_master_put(data);
|
||||
}
|
||||
|
||||
static int spi_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int status;
|
||||
@ -363,16 +358,10 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spi_bitbang *bb;
|
||||
|
||||
master = spi_alloc_master(dev, sizeof(*spi_gpio));
|
||||
master = devm_spi_alloc_master(dev, sizeof(*spi_gpio));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
status = devm_add_action_or_reset(&pdev->dev, spi_gpio_put, master);
|
||||
if (status) {
|
||||
spi_master_put(master);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
status = spi_gpio_probe_dt(pdev, master);
|
||||
else
|
||||
@ -432,7 +421,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return devm_spi_register_master(&pdev->dev, spi_master_get(master));
|
||||
return devm_spi_register_master(&pdev->dev, master);
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
|
@ -731,8 +731,10 @@ static int img_spfi_resume(struct device *dev)
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
return ret;
|
||||
}
|
||||
spfi_reset(spfi);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
|
@ -1019,33 +1019,6 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
|
||||
.devtype = IMX53_ECSPI,
|
||||
};
|
||||
|
||||
static const struct platform_device_id spi_imx_devtype[] = {
|
||||
{
|
||||
.name = "imx1-cspi",
|
||||
.driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data,
|
||||
}, {
|
||||
.name = "imx21-cspi",
|
||||
.driver_data = (kernel_ulong_t) &imx21_cspi_devtype_data,
|
||||
}, {
|
||||
.name = "imx27-cspi",
|
||||
.driver_data = (kernel_ulong_t) &imx27_cspi_devtype_data,
|
||||
}, {
|
||||
.name = "imx31-cspi",
|
||||
.driver_data = (kernel_ulong_t) &imx31_cspi_devtype_data,
|
||||
}, {
|
||||
.name = "imx35-cspi",
|
||||
.driver_data = (kernel_ulong_t) &imx35_cspi_devtype_data,
|
||||
}, {
|
||||
.name = "imx51-ecspi",
|
||||
.driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data,
|
||||
}, {
|
||||
.name = "imx53-ecspi",
|
||||
.driver_data = (kernel_ulong_t) &imx53_ecspi_devtype_data,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
|
||||
static const struct of_device_id spi_imx_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
|
||||
{ .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, },
|
||||
@ -1538,6 +1511,7 @@ spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg)
|
||||
|
||||
ret = pm_runtime_get_sync(spi_imx->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(spi_imx->dev);
|
||||
dev_err(spi_imx->dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
@ -1580,8 +1554,7 @@ static int spi_imx_probe(struct platform_device *pdev)
|
||||
struct spi_imx_data *spi_imx;
|
||||
struct resource *res;
|
||||
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;
|
||||
const struct spi_imx_devtype_data *devtype_data = of_id->data;
|
||||
bool slave_mode;
|
||||
u32 val;
|
||||
|
||||
@ -1748,6 +1721,7 @@ static int spi_imx_remove(struct platform_device *pdev)
|
||||
|
||||
ret = pm_runtime_get_sync(spi_imx->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(spi_imx->dev);
|
||||
dev_err(spi_imx->dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
@ -1822,7 +1796,6 @@ static struct platform_driver spi_imx_driver = {
|
||||
.of_match_table = spi_imx_dt_ids,
|
||||
.pm = &imx_spi_pm,
|
||||
},
|
||||
.id_table = spi_imx_devtype,
|
||||
.probe = spi_imx_probe,
|
||||
.remove = spi_imx_remove,
|
||||
};
|
||||
|
@ -243,6 +243,7 @@ static int spi_mem_access_start(struct spi_mem *mem)
|
||||
|
||||
ret = pm_runtime_get_sync(ctlr->dev.parent);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(ctlr->dev.parent);
|
||||
dev_err(&ctlr->dev, "Failed to power device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
@ -743,7 +744,7 @@ static int spi_mem_probe(struct spi_device *spi)
|
||||
mem->name = dev_name(&spi->dev);
|
||||
|
||||
if (IS_ERR_OR_NULL(mem->name))
|
||||
return PTR_ERR(mem->name);
|
||||
return PTR_ERR_OR_ZERO(mem->name);
|
||||
|
||||
spi_set_drvdata(spi, mem);
|
||||
|
||||
|
@ -350,9 +350,10 @@ static int mt7621_spi_probe(struct platform_device *pdev)
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*rs));
|
||||
master = devm_spi_alloc_master(&pdev->dev, sizeof(*rs));
|
||||
if (!master) {
|
||||
dev_info(&pdev->dev, "master allocation failed\n");
|
||||
clk_disable_unprepare(clk);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -377,10 +378,15 @@ static int mt7621_spi_probe(struct platform_device *pdev)
|
||||
ret = device_reset(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "SPI reset failed!\n");
|
||||
clk_disable_unprepare(clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_spi_register_controller(&pdev->dev, master);
|
||||
ret = spi_register_controller(master);
|
||||
if (ret)
|
||||
clk_disable_unprepare(clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt7621_spi_remove(struct platform_device *pdev)
|
||||
@ -391,6 +397,7 @@ static int mt7621_spi_remove(struct platform_device *pdev)
|
||||
master = dev_get_drvdata(&pdev->dev);
|
||||
rs = spi_controller_get_devdata(master);
|
||||
|
||||
spi_unregister_controller(master);
|
||||
clk_disable_unprepare(rs->clk);
|
||||
|
||||
return 0;
|
||||
|
@ -103,6 +103,7 @@ struct mtk_nor {
|
||||
dma_addr_t buffer_dma;
|
||||
struct clk *spi_clk;
|
||||
struct clk *ctlr_clk;
|
||||
struct clk *axi_clk;
|
||||
unsigned int spi_freq;
|
||||
bool wbuf_en;
|
||||
bool has_irq;
|
||||
@ -672,6 +673,7 @@ static void mtk_nor_disable_clk(struct mtk_nor *sp)
|
||||
{
|
||||
clk_disable_unprepare(sp->spi_clk);
|
||||
clk_disable_unprepare(sp->ctlr_clk);
|
||||
clk_disable_unprepare(sp->axi_clk);
|
||||
}
|
||||
|
||||
static int mtk_nor_enable_clk(struct mtk_nor *sp)
|
||||
@ -688,6 +690,13 @@ static int mtk_nor_enable_clk(struct mtk_nor *sp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(sp->axi_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(sp->spi_clk);
|
||||
clk_disable_unprepare(sp->ctlr_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -746,7 +755,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
|
||||
struct spi_controller *ctlr;
|
||||
struct mtk_nor *sp;
|
||||
void __iomem *base;
|
||||
struct clk *spi_clk, *ctlr_clk;
|
||||
struct clk *spi_clk, *ctlr_clk, *axi_clk;
|
||||
int ret, irq;
|
||||
unsigned long dma_bits;
|
||||
|
||||
@ -762,13 +771,17 @@ static int mtk_nor_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(ctlr_clk))
|
||||
return PTR_ERR(ctlr_clk);
|
||||
|
||||
axi_clk = devm_clk_get_optional(&pdev->dev, "axi");
|
||||
if (IS_ERR(axi_clk))
|
||||
return PTR_ERR(axi_clk);
|
||||
|
||||
dma_bits = (unsigned long)of_device_get_match_data(&pdev->dev);
|
||||
if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits))) {
|
||||
dev_err(&pdev->dev, "failed to set dma mask(%lu)\n", dma_bits);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||
ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||
if (!ctlr) {
|
||||
dev_err(&pdev->dev, "failed to allocate spi controller\n");
|
||||
return -ENOMEM;
|
||||
@ -794,6 +807,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
|
||||
sp->dev = &pdev->dev;
|
||||
sp->spi_clk = spi_clk;
|
||||
sp->ctlr_clk = ctlr_clk;
|
||||
sp->axi_clk = axi_clk;
|
||||
sp->high_dma = (dma_bits > 32);
|
||||
sp->buffer = dmam_alloc_coherent(&pdev->dev,
|
||||
MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
|
||||
|
@ -529,7 +529,7 @@ static int mxic_spi_probe(struct platform_device *pdev)
|
||||
struct mxic_spi *mxic;
|
||||
int ret;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi));
|
||||
master = devm_spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -574,15 +574,9 @@ static int mxic_spi_probe(struct platform_device *pdev)
|
||||
ret = spi_register_master(master);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "spi_register_master failed\n");
|
||||
goto err_put_master;
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_master:
|
||||
spi_master_put(master);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -607,6 +607,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
|
||||
|
||||
ret = pm_runtime_get_sync(ssp->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(ssp->dev);
|
||||
dev_err(ssp->dev, "runtime_get_sync failed\n");
|
||||
goto out_pm_runtime_disable;
|
||||
}
|
||||
|
@ -677,7 +677,7 @@ static int npcm_fiu_probe(struct platform_device *pdev)
|
||||
struct npcm_fiu_spi *fiu;
|
||||
void __iomem *regbase;
|
||||
struct resource *res;
|
||||
int id;
|
||||
int id, ret;
|
||||
|
||||
ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
|
||||
if (!ctrl)
|
||||
@ -735,7 +735,11 @@ static int npcm_fiu_probe(struct platform_device *pdev)
|
||||
ctrl->num_chipselect = fiu->info->max_cs;
|
||||
ctrl->dev.of_node = dev->of_node;
|
||||
|
||||
return devm_spi_register_master(dev, ctrl);
|
||||
ret = devm_spi_register_master(dev, ctrl);
|
||||
if (ret)
|
||||
clk_disable_unprepare(fiu->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int npcm_fiu_remove(struct platform_device *pdev)
|
||||
|
@ -839,6 +839,7 @@ static int pic32_spi_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_bailout:
|
||||
pic32_spi_dma_unprep(pic32s);
|
||||
clk_disable_unprepare(pic32s->clk);
|
||||
err_master:
|
||||
spi_master_put(master);
|
||||
|
@ -1496,6 +1496,11 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ac6), LPSS_BXT_SSP },
|
||||
/* ADL-S */
|
||||
{ PCI_VDEVICE(INTEL, 0x7aaa), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x7aab), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x7af9), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x7afb), LPSS_CNL_SSP },
|
||||
/* CNL-LP */
|
||||
{ PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP },
|
||||
@ -1686,9 +1691,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (platform_info->is_slave)
|
||||
controller = spi_alloc_slave(dev, sizeof(struct driver_data));
|
||||
controller = devm_spi_alloc_slave(dev, sizeof(*drv_data));
|
||||
else
|
||||
controller = spi_alloc_master(dev, sizeof(struct driver_data));
|
||||
controller = devm_spi_alloc_master(dev, sizeof(*drv_data));
|
||||
|
||||
if (!controller) {
|
||||
dev_err(&pdev->dev, "cannot alloc spi_controller\n");
|
||||
@ -1911,7 +1916,6 @@ out_error_dma_irq_alloc:
|
||||
free_irq(ssp->irq, drv_data);
|
||||
|
||||
out_error_controller_alloc:
|
||||
spi_controller_put(controller);
|
||||
pxa_ssp_free(ssp);
|
||||
return status;
|
||||
}
|
||||
|
@ -462,7 +462,7 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
||||
|
||||
dev = &pdev->dev;
|
||||
|
||||
master = spi_alloc_master(dev, sizeof(*ctrl));
|
||||
master = devm_spi_alloc_master(dev, sizeof(*ctrl));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -473,54 +473,49 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&ctrl->lock);
|
||||
ctrl->dev = dev;
|
||||
ctrl->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ctrl->base)) {
|
||||
ret = PTR_ERR(ctrl->base);
|
||||
goto exit_probe_master_put;
|
||||
}
|
||||
if (IS_ERR(ctrl->base))
|
||||
return PTR_ERR(ctrl->base);
|
||||
|
||||
ctrl->clks = devm_kcalloc(dev, QSPI_NUM_CLKS,
|
||||
sizeof(*ctrl->clks), GFP_KERNEL);
|
||||
if (!ctrl->clks) {
|
||||
ret = -ENOMEM;
|
||||
goto exit_probe_master_put;
|
||||
}
|
||||
if (!ctrl->clks)
|
||||
return -ENOMEM;
|
||||
|
||||
ctrl->clks[QSPI_CLK_CORE].id = "core";
|
||||
ctrl->clks[QSPI_CLK_IFACE].id = "iface";
|
||||
ret = devm_clk_bulk_get(dev, QSPI_NUM_CLKS, ctrl->clks);
|
||||
if (ret)
|
||||
goto exit_probe_master_put;
|
||||
return ret;
|
||||
|
||||
ctrl->icc_path_cpu_to_qspi = devm_of_icc_get(dev, "qspi-config");
|
||||
if (IS_ERR(ctrl->icc_path_cpu_to_qspi)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(ctrl->icc_path_cpu_to_qspi),
|
||||
"Failed to get cpu path\n");
|
||||
goto exit_probe_master_put;
|
||||
}
|
||||
if (IS_ERR(ctrl->icc_path_cpu_to_qspi))
|
||||
return dev_err_probe(dev, PTR_ERR(ctrl->icc_path_cpu_to_qspi),
|
||||
"Failed to get cpu path\n");
|
||||
|
||||
/* Set BW vote for register access */
|
||||
ret = icc_set_bw(ctrl->icc_path_cpu_to_qspi, Bps_to_icc(1000),
|
||||
Bps_to_icc(1000));
|
||||
if (ret) {
|
||||
dev_err(ctrl->dev, "%s: ICC BW voting failed for cpu: %d\n",
|
||||
__func__, ret);
|
||||
goto exit_probe_master_put;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = icc_disable(ctrl->icc_path_cpu_to_qspi);
|
||||
if (ret) {
|
||||
dev_err(ctrl->dev, "%s: ICC disable failed for cpu: %d\n",
|
||||
__func__, ret);
|
||||
goto exit_probe_master_put;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
goto exit_probe_master_put;
|
||||
return ret;
|
||||
ret = devm_request_irq(dev, ret, qcom_qspi_irq,
|
||||
IRQF_TRIGGER_HIGH, dev_name(dev), ctrl);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request irq %d\n", ret);
|
||||
goto exit_probe_master_put;
|
||||
return ret;
|
||||
}
|
||||
|
||||
master->max_speed_hz = 300000000;
|
||||
@ -537,10 +532,8 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
||||
master->auto_runtime_pm = true;
|
||||
|
||||
ctrl->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core");
|
||||
if (IS_ERR(ctrl->opp_table)) {
|
||||
ret = PTR_ERR(ctrl->opp_table);
|
||||
goto exit_probe_master_put;
|
||||
}
|
||||
if (IS_ERR(ctrl->opp_table))
|
||||
return PTR_ERR(ctrl->opp_table);
|
||||
/* OPP table is optional */
|
||||
ret = dev_pm_opp_of_add_table(&pdev->dev);
|
||||
if (ret && ret != -ENODEV) {
|
||||
@ -562,9 +555,6 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
||||
exit_probe_put_clkname:
|
||||
dev_pm_opp_put_clkname(ctrl->opp_table);
|
||||
|
||||
exit_probe_master_put:
|
||||
spi_master_put(master);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(spi_base))
|
||||
return PTR_ERR(spi_base);
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*rbspi));
|
||||
master = devm_spi_alloc_master(&pdev->dev, sizeof(*rbspi));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -160,6 +160,8 @@
|
||||
#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002
|
||||
#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002
|
||||
|
||||
#define ROCKCHIP_AUTOSUSPEND_TIMEOUT 2000
|
||||
|
||||
struct rockchip_spi {
|
||||
struct device *dev;
|
||||
|
||||
@ -715,6 +717,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)
|
||||
goto err_disable_spiclk;
|
||||
}
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, ROCKCHIP_AUTOSUSPEND_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
|
@ -134,7 +134,7 @@ static int rpcif_spi_probe(struct platform_device *pdev)
|
||||
struct rpcif *rpc;
|
||||
int error;
|
||||
|
||||
ctlr = spi_alloc_master(&pdev->dev, sizeof(*rpc));
|
||||
ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*rpc));
|
||||
if (!ctlr)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -159,13 +159,8 @@ static int rpcif_spi_probe(struct platform_device *pdev)
|
||||
error = spi_register_controller(ctlr);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "spi_register_controller failed\n");
|
||||
goto err_put_ctlr;
|
||||
rpcif_disable_rpm(rpc);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_put_ctlr:
|
||||
rpcif_disable_rpm(rpc);
|
||||
spi_controller_put(ctlr);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -238,13 +238,12 @@ static int sc18is602_probe(struct i2c_client *client,
|
||||
struct sc18is602_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct sc18is602 *hw;
|
||||
struct spi_master *master;
|
||||
int error;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||
return -EINVAL;
|
||||
|
||||
master = spi_alloc_master(dev, sizeof(struct sc18is602));
|
||||
master = devm_spi_alloc_master(dev, sizeof(struct sc18is602));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -298,15 +297,7 @@ static int sc18is602_probe(struct i2c_client *client,
|
||||
master->min_speed_hz = hw->freq / 128;
|
||||
master->max_speed_hz = hw->freq / 4;
|
||||
|
||||
error = devm_spi_register_master(dev, master);
|
||||
if (error)
|
||||
goto error_reg;
|
||||
|
||||
return 0;
|
||||
|
||||
error_reg:
|
||||
spi_master_put(master);
|
||||
return error;
|
||||
return devm_spi_register_master(dev, master);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sc18is602_id[] = {
|
||||
|
@ -440,7 +440,7 @@ static int spi_sh_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data));
|
||||
master = devm_spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data));
|
||||
if (master == NULL) {
|
||||
dev_err(&pdev->dev, "spi_alloc_master error.\n");
|
||||
return -ENOMEM;
|
||||
@ -458,16 +458,14 @@ static int spi_sh_probe(struct platform_device *pdev)
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "No support width\n");
|
||||
ret = -ENODEV;
|
||||
goto error1;
|
||||
return -ENODEV;
|
||||
}
|
||||
ss->irq = irq;
|
||||
ss->master = master;
|
||||
ss->addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (ss->addr == NULL) {
|
||||
dev_err(&pdev->dev, "ioremap error.\n");
|
||||
ret = -ENOMEM;
|
||||
goto error1;
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_LIST_HEAD(&ss->queue);
|
||||
spin_lock_init(&ss->lock);
|
||||
@ -477,7 +475,7 @@ static int spi_sh_probe(struct platform_device *pdev)
|
||||
ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "request_irq error\n");
|
||||
goto error1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
master->num_chipselect = 2;
|
||||
@ -496,9 +494,6 @@ static int spi_sh_probe(struct platform_device *pdev)
|
||||
|
||||
error3:
|
||||
free_irq(irq, ss);
|
||||
error1:
|
||||
spi_master_put(master);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1010,6 +1010,7 @@ static int sprd_spi_remove(struct platform_device *pdev)
|
||||
|
||||
ret = pm_runtime_get_sync(ss->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(ss->dev);
|
||||
dev_err(ss->dev, "failed to resume SPI controller\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -375,13 +375,14 @@ static int spi_st_probe(struct platform_device *pdev)
|
||||
ret = devm_spi_register_master(&pdev->dev, master);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register master\n");
|
||||
goto clk_disable;
|
||||
goto rpm_disable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
clk_disable:
|
||||
rpm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
clk_disable:
|
||||
clk_disable_unprepare(spi_st->clk);
|
||||
put_master:
|
||||
spi_master_put(master);
|
||||
|
@ -434,8 +434,10 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(qspi->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(qspi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&qspi->lock);
|
||||
ret = stm32_qspi_send(mem, op);
|
||||
@ -462,8 +464,10 @@ static int stm32_qspi_setup(struct spi_device *spi)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pm_runtime_get_sync(qspi->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(qspi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1;
|
||||
|
||||
|
@ -2062,6 +2062,7 @@ static int stm32_spi_resume(struct device *dev)
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
dev_err(dev, "Unable to power device:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -18,9 +18,12 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define SUN6I_AUTOSUSPEND_TIMEOUT 2000
|
||||
|
||||
#define SUN6I_FIFO_DEPTH 128
|
||||
#define SUN8I_FIFO_DEPTH 64
|
||||
|
||||
@ -52,10 +55,12 @@
|
||||
|
||||
#define SUN6I_FIFO_CTL_REG 0x18
|
||||
#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK 0xff
|
||||
#define SUN6I_FIFO_CTL_RF_DRQ_EN BIT(8)
|
||||
#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS 0
|
||||
#define SUN6I_FIFO_CTL_RF_RST BIT(15)
|
||||
#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK 0xff
|
||||
#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS 16
|
||||
#define SUN6I_FIFO_CTL_TF_DRQ_EN BIT(24)
|
||||
#define SUN6I_FIFO_CTL_TF_RST BIT(31)
|
||||
|
||||
#define SUN6I_FIFO_STA_REG 0x1c
|
||||
@ -83,6 +88,8 @@
|
||||
struct sun6i_spi {
|
||||
struct spi_master *master;
|
||||
void __iomem *base_addr;
|
||||
dma_addr_t dma_addr_rx;
|
||||
dma_addr_t dma_addr_tx;
|
||||
struct clk *hclk;
|
||||
struct clk *mclk;
|
||||
struct reset_control *rstc;
|
||||
@ -182,6 +189,68 @@ static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
|
||||
return SUN6I_MAX_XFER_SIZE - 1;
|
||||
}
|
||||
|
||||
static int sun6i_spi_prepare_dma(struct sun6i_spi *sspi,
|
||||
struct spi_transfer *tfr)
|
||||
{
|
||||
struct dma_async_tx_descriptor *rxdesc, *txdesc;
|
||||
struct spi_master *master = sspi->master;
|
||||
|
||||
rxdesc = NULL;
|
||||
if (tfr->rx_buf) {
|
||||
struct dma_slave_config rxconf = {
|
||||
.direction = DMA_DEV_TO_MEM,
|
||||
.src_addr = sspi->dma_addr_rx,
|
||||
.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.src_maxburst = 8,
|
||||
};
|
||||
|
||||
dmaengine_slave_config(master->dma_rx, &rxconf);
|
||||
|
||||
rxdesc = dmaengine_prep_slave_sg(master->dma_rx,
|
||||
tfr->rx_sg.sgl,
|
||||
tfr->rx_sg.nents,
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!rxdesc)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
txdesc = NULL;
|
||||
if (tfr->tx_buf) {
|
||||
struct dma_slave_config txconf = {
|
||||
.direction = DMA_MEM_TO_DEV,
|
||||
.dst_addr = sspi->dma_addr_tx,
|
||||
.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.dst_maxburst = 8,
|
||||
};
|
||||
|
||||
dmaengine_slave_config(master->dma_tx, &txconf);
|
||||
|
||||
txdesc = dmaengine_prep_slave_sg(master->dma_tx,
|
||||
tfr->tx_sg.sgl,
|
||||
tfr->tx_sg.nents,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!txdesc) {
|
||||
if (rxdesc)
|
||||
dmaengine_terminate_sync(master->dma_rx);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (tfr->rx_buf) {
|
||||
dmaengine_submit(rxdesc);
|
||||
dma_async_issue_pending(master->dma_rx);
|
||||
}
|
||||
|
||||
if (tfr->tx_buf) {
|
||||
dmaengine_submit(txdesc);
|
||||
dma_async_issue_pending(master->dma_tx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun6i_spi_transfer_one(struct spi_master *master,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *tfr)
|
||||
@ -191,6 +260,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
|
||||
unsigned int start, end, tx_time;
|
||||
unsigned int trig_level;
|
||||
unsigned int tx_len = 0, rx_len = 0;
|
||||
bool use_dma;
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
|
||||
@ -201,6 +271,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
|
||||
sspi->tx_buf = tfr->tx_buf;
|
||||
sspi->rx_buf = tfr->rx_buf;
|
||||
sspi->len = tfr->len;
|
||||
use_dma = master->can_dma ? master->can_dma(master, spi, tfr) : false;
|
||||
|
||||
/* Clear pending interrupts */
|
||||
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
|
||||
@ -209,16 +280,34 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
|
||||
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
|
||||
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
|
||||
|
||||
/*
|
||||
* Setup FIFO interrupt trigger level
|
||||
* Here we choose 3/4 of the full fifo depth, as it's the hardcoded
|
||||
* value used in old generation of Allwinner SPI controller.
|
||||
* (See spi-sun4i.c)
|
||||
*/
|
||||
trig_level = sspi->fifo_depth / 4 * 3;
|
||||
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
|
||||
(trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
|
||||
(trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
|
||||
reg = 0;
|
||||
|
||||
if (!use_dma) {
|
||||
/*
|
||||
* Setup FIFO interrupt trigger level
|
||||
* Here we choose 3/4 of the full fifo depth, as it's
|
||||
* the hardcoded value used in old generation of Allwinner
|
||||
* SPI controller. (See spi-sun4i.c)
|
||||
*/
|
||||
trig_level = sspi->fifo_depth / 4 * 3;
|
||||
} else {
|
||||
/*
|
||||
* Setup FIFO DMA request trigger level
|
||||
* We choose 1/2 of the full fifo depth, that value will
|
||||
* be used as DMA burst length.
|
||||
*/
|
||||
trig_level = sspi->fifo_depth / 2;
|
||||
|
||||
if (tfr->tx_buf)
|
||||
reg |= SUN6I_FIFO_CTL_TF_DRQ_EN;
|
||||
if (tfr->rx_buf)
|
||||
reg |= SUN6I_FIFO_CTL_RF_DRQ_EN;
|
||||
}
|
||||
|
||||
reg |= (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
|
||||
(trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS);
|
||||
|
||||
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, reg);
|
||||
|
||||
/*
|
||||
* Setup the transfer control register: Chip Select,
|
||||
@ -300,16 +389,28 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
|
||||
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);
|
||||
if (!use_dma) {
|
||||
/* Fill the TX FIFO */
|
||||
sun6i_spi_fill_fifo(sspi);
|
||||
} else {
|
||||
ret = sun6i_spi_prepare_dma(sspi, tfr);
|
||||
if (ret) {
|
||||
dev_warn(&master->dev,
|
||||
"%s: prepare DMA failed, ret=%d",
|
||||
dev_name(&spi->dev), ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the interrupts */
|
||||
reg = SUN6I_INT_CTL_TC;
|
||||
|
||||
if (rx_len > sspi->fifo_depth)
|
||||
reg |= SUN6I_INT_CTL_RF_RDY;
|
||||
if (tx_len > sspi->fifo_depth)
|
||||
reg |= SUN6I_INT_CTL_TF_ERQ;
|
||||
if (!use_dma) {
|
||||
if (rx_len > sspi->fifo_depth)
|
||||
reg |= SUN6I_INT_CTL_RF_RDY;
|
||||
if (tx_len > sspi->fifo_depth)
|
||||
reg |= SUN6I_INT_CTL_TF_ERQ;
|
||||
}
|
||||
|
||||
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
|
||||
|
||||
@ -332,6 +433,11 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
|
||||
|
||||
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
|
||||
|
||||
if (ret && use_dma) {
|
||||
dmaengine_terminate_sync(master->dma_rx);
|
||||
dmaengine_terminate_sync(master->dma_tx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -422,10 +528,25 @@ static int sun6i_spi_runtime_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool sun6i_spi_can_dma(struct spi_master *master,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct sun6i_spi *sspi = spi_master_get_devdata(master);
|
||||
|
||||
/*
|
||||
* If the number of spi words to transfer is less or equal than
|
||||
* the fifo length we can just fill the fifo and wait for a single
|
||||
* irq, so don't bother setting up dma
|
||||
*/
|
||||
return xfer->len > sspi->fifo_depth;
|
||||
}
|
||||
|
||||
static int sun6i_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct sun6i_spi *sspi;
|
||||
struct resource *mem;
|
||||
int ret = 0, irq;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
|
||||
@ -437,7 +558,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, master);
|
||||
sspi = spi_master_get_devdata(master);
|
||||
|
||||
sspi->base_addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
sspi->base_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
|
||||
if (IS_ERR(sspi->base_addr)) {
|
||||
ret = PTR_ERR(sspi->base_addr);
|
||||
goto err_free_master;
|
||||
@ -494,6 +615,33 @@ static int sun6i_spi_probe(struct platform_device *pdev)
|
||||
goto err_free_master;
|
||||
}
|
||||
|
||||
master->dma_tx = dma_request_chan(&pdev->dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
/* Check tx to see if we need defer probing driver */
|
||||
if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_free_master;
|
||||
}
|
||||
dev_warn(&pdev->dev, "Failed to request TX DMA channel\n");
|
||||
master->dma_tx = NULL;
|
||||
}
|
||||
|
||||
master->dma_rx = dma_request_chan(&pdev->dev, "rx");
|
||||
if (IS_ERR(master->dma_rx)) {
|
||||
if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_free_dma_tx;
|
||||
}
|
||||
dev_warn(&pdev->dev, "Failed to request RX DMA channel\n");
|
||||
master->dma_rx = NULL;
|
||||
}
|
||||
|
||||
if (master->dma_tx && master->dma_rx) {
|
||||
sspi->dma_addr_tx = mem->start + SUN6I_TXDATA_REG;
|
||||
sspi->dma_addr_rx = mem->start + SUN6I_RXDATA_REG;
|
||||
master->can_dma = sun6i_spi_can_dma;
|
||||
}
|
||||
|
||||
/*
|
||||
* This wake-up/shutdown pattern is to be able to have the
|
||||
* device woken up, even if runtime_pm is disabled
|
||||
@ -501,12 +649,13 @@ static int sun6i_spi_probe(struct platform_device *pdev)
|
||||
ret = sun6i_spi_runtime_resume(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Couldn't resume the device\n");
|
||||
goto err_free_master;
|
||||
goto err_free_dma_rx;
|
||||
}
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, SUN6I_AUTOSUSPEND_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_idle(&pdev->dev);
|
||||
|
||||
ret = devm_spi_register_master(&pdev->dev, master);
|
||||
if (ret) {
|
||||
@ -519,6 +668,12 @@ static int sun6i_spi_probe(struct platform_device *pdev)
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
sun6i_spi_runtime_suspend(&pdev->dev);
|
||||
err_free_dma_rx:
|
||||
if (master->dma_rx)
|
||||
dma_release_channel(master->dma_rx);
|
||||
err_free_dma_tx:
|
||||
if (master->dma_tx)
|
||||
dma_release_channel(master->dma_tx);
|
||||
err_free_master:
|
||||
spi_master_put(master);
|
||||
return ret;
|
||||
@ -526,8 +681,14 @@ err_free_master:
|
||||
|
||||
static int sun6i_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_force_suspend(&pdev->dev);
|
||||
|
||||
if (master->dma_tx)
|
||||
dma_release_channel(master->dma_tx);
|
||||
if (master->dma_rx)
|
||||
dma_release_channel(master->dma_rx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -657,7 +657,8 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
||||
|
||||
if (!master->max_speed_hz) {
|
||||
dev_err(&pdev->dev, "missing clock source\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto disable_clk;
|
||||
}
|
||||
master->min_speed_hz = master->max_speed_hz / 254;
|
||||
|
||||
@ -670,7 +671,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
||||
rx_irq = platform_get_irq(pdev, 0);
|
||||
if (rx_irq <= 0) {
|
||||
ret = rx_irq;
|
||||
goto put_spi;
|
||||
goto disable_clk;
|
||||
}
|
||||
snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx",
|
||||
dev_name(&pdev->dev));
|
||||
@ -678,13 +679,13 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
||||
0, sspi->rx_irq_name, sspi);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret);
|
||||
goto put_spi;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
tx_irq = platform_get_irq(pdev, 1);
|
||||
if (tx_irq <= 0) {
|
||||
ret = tx_irq;
|
||||
goto put_spi;
|
||||
goto disable_clk;
|
||||
}
|
||||
snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx",
|
||||
dev_name(&pdev->dev));
|
||||
@ -692,7 +693,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
||||
0, sspi->tx_irq_name, sspi);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
|
||||
goto put_spi;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
master->dev.of_node = np;
|
||||
@ -710,7 +711,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
||||
|
||||
ret = synquacer_spi_enable(master);
|
||||
if (ret)
|
||||
goto fail_enable;
|
||||
goto disable_clk;
|
||||
|
||||
pm_runtime_set_active(sspi->dev);
|
||||
pm_runtime_enable(sspi->dev);
|
||||
@ -723,7 +724,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
||||
|
||||
disable_pm:
|
||||
pm_runtime_disable(sspi->dev);
|
||||
fail_enable:
|
||||
disable_clk:
|
||||
clk_disable_unprepare(sspi->clk);
|
||||
put_spi:
|
||||
spi_master_put(master);
|
||||
|
@ -966,6 +966,7 @@ static int tegra_spi_setup(struct spi_device *spi)
|
||||
|
||||
ret = pm_runtime_get_sync(tspi->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(tspi->dev);
|
||||
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
|
||||
if (cdata)
|
||||
tegra_spi_cleanup(spi);
|
||||
@ -1474,6 +1475,7 @@ static int tegra_spi_resume(struct device *dev)
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -552,6 +552,7 @@ static int tegra_sflash_resume(struct device *dev)
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -751,6 +751,7 @@ static int tegra_slink_setup(struct spi_device *spi)
|
||||
|
||||
ret = pm_runtime_get_sync(tspi->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(tspi->dev);
|
||||
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
@ -1188,6 +1189,7 @@ static int tegra_slink_resume(struct device *dev)
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -174,6 +174,7 @@ static int ti_qspi_setup(struct spi_device *spi)
|
||||
|
||||
ret = pm_runtime_get_sync(qspi->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(qspi->dev);
|
||||
dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -374,16 +374,7 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
|
||||
}
|
||||
|
||||
struct bus_type spi_bus_type = {
|
||||
.name = "spi",
|
||||
.dev_groups = spi_dev_groups,
|
||||
.match = spi_match_device,
|
||||
.uevent = spi_uevent,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(spi_bus_type);
|
||||
|
||||
|
||||
static int spi_drv_probe(struct device *dev)
|
||||
static int spi_probe(struct device *dev)
|
||||
{
|
||||
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
@ -405,31 +396,55 @@ static int spi_drv_probe(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sdrv->probe(spi);
|
||||
if (ret)
|
||||
dev_pm_domain_detach(dev, true);
|
||||
if (sdrv->probe) {
|
||||
ret = sdrv->probe(spi);
|
||||
if (ret)
|
||||
dev_pm_domain_detach(dev, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_drv_remove(struct device *dev)
|
||||
static int spi_remove(struct device *dev)
|
||||
{
|
||||
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
||||
int ret;
|
||||
|
||||
ret = sdrv->remove(to_spi_device(dev));
|
||||
if (sdrv->remove) {
|
||||
int ret;
|
||||
|
||||
ret = sdrv->remove(to_spi_device(dev));
|
||||
if (ret)
|
||||
dev_warn(dev,
|
||||
"Failed to unbind driver (%pe), ignoring\n",
|
||||
ERR_PTR(ret));
|
||||
}
|
||||
|
||||
dev_pm_domain_detach(dev, true);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spi_drv_shutdown(struct device *dev)
|
||||
static void spi_shutdown(struct device *dev)
|
||||
{
|
||||
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
||||
if (dev->driver) {
|
||||
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
||||
|
||||
sdrv->shutdown(to_spi_device(dev));
|
||||
if (sdrv->shutdown)
|
||||
sdrv->shutdown(to_spi_device(dev));
|
||||
}
|
||||
}
|
||||
|
||||
struct bus_type spi_bus_type = {
|
||||
.name = "spi",
|
||||
.dev_groups = spi_dev_groups,
|
||||
.match = spi_match_device,
|
||||
.uevent = spi_uevent,
|
||||
.probe = spi_probe,
|
||||
.remove = spi_remove,
|
||||
.shutdown = spi_shutdown,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(spi_bus_type);
|
||||
|
||||
/**
|
||||
* __spi_register_driver - register a SPI driver
|
||||
* @owner: owner module of the driver to register
|
||||
@ -442,12 +457,6 @@ int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
|
||||
{
|
||||
sdrv->driver.owner = owner;
|
||||
sdrv->driver.bus = &spi_bus_type;
|
||||
if (sdrv->probe)
|
||||
sdrv->driver.probe = spi_drv_probe;
|
||||
if (sdrv->remove)
|
||||
sdrv->driver.remove = spi_drv_remove;
|
||||
if (sdrv->shutdown)
|
||||
sdrv->driver.shutdown = spi_drv_shutdown;
|
||||
return driver_register(&sdrv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__spi_register_driver);
|
||||
@ -3238,9 +3247,9 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_split_tranfers_maxsize - split spi transfers into multiple transfers
|
||||
* when an individual transfer exceeds a
|
||||
* certain size
|
||||
* spi_split_transfers_maxsize - split spi transfers into multiple transfers
|
||||
* when an individual transfer exceeds a
|
||||
* certain size
|
||||
* @ctlr: the @spi_controller for this transfer
|
||||
* @msg: the @spi_message to transform
|
||||
* @maxsize: the maximum when to apply this
|
||||
@ -3369,7 +3378,8 @@ int spi_setup(struct spi_device *spi)
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (!spi->max_speed_hz)
|
||||
if (!spi->max_speed_hz ||
|
||||
spi->max_speed_hz > spi->controller->max_speed_hz)
|
||||
spi->max_speed_hz = spi->controller->max_speed_hz;
|
||||
|
||||
mutex_lock(&spi->controller->io_mutex);
|
||||
|
@ -171,6 +171,7 @@ struct spi_device {
|
||||
#define SPI_MODE_1 (0|SPI_CPHA)
|
||||
#define SPI_MODE_2 (SPI_CPOL|0)
|
||||
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
|
||||
#define SPI_MODE_X_MASK (SPI_CPOL|SPI_CPHA)
|
||||
#define SPI_CS_HIGH 0x04 /* chipselect active high? */
|
||||
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
|
||||
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
|
||||
|
Loading…
Reference in New Issue
Block a user