mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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:
@@ -65,6 +65,8 @@ properties:
|
|||||||
const: baikal,bt1-ssi
|
const: baikal,bt1-ssi
|
||||||
- description: Baikal-T1 System Boot SPI Controller
|
- description: Baikal-T1 System Boot SPI Controller
|
||||||
const: baikal,bt1-sys-ssi
|
const: baikal,bt1-sys-ssi
|
||||||
|
- description: Canaan Kendryte K210 SoS SPI Controller
|
||||||
|
const: canaan,k210-spi
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
minItems: 1
|
minItems: 1
|
||||||
|
|||||||
@@ -42,6 +42,33 @@ properties:
|
|||||||
cs2 : &gpio1 1 0
|
cs2 : &gpio1 1 0
|
||||||
cs3 : &gpio1 2 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:
|
num-cs:
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -17,15 +17,17 @@ allOf:
|
|||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
items:
|
items:
|
||||||
- const: sifive,fu540-c000-spi
|
- enum:
|
||||||
|
- sifive,fu540-c000-spi
|
||||||
|
- sifive,fu740-c000-spi
|
||||||
- const: sifive,spi0
|
- const: sifive,spi0
|
||||||
|
|
||||||
description:
|
description:
|
||||||
Should be "sifive,<chip>-spi" and "sifive,spi<version>".
|
Should be "sifive,<chip>-spi" and "sifive,spi<version>".
|
||||||
Supported compatible strings are -
|
Supported compatible strings are -
|
||||||
"sifive,fu540-c000-spi" for the SiFive SPI v0 as integrated
|
"sifive,fu540-c000-spi" and "sifive,fu740-c000-spi" for the SiFive SPI v0
|
||||||
onto the SiFive FU540 chip, and "sifive,spi0" for the SiFive
|
as integrated onto the SiFive FU540 and FU740 chip resp, and "sifive,spi0"
|
||||||
SPI v0 IP block with no chip integration tweaks.
|
for the SiFive SPI v0 IP block with no chip integration tweaks.
|
||||||
Please refer to sifive-blocks-ip-versioning.txt for details
|
Please refer to sifive-blocks-ip-versioning.txt for details
|
||||||
|
|
||||||
SPI RTL that corresponds to the IP block version numbers can be found here -
|
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.
|
* may not. So we stick to very-portable 8 bit words, both RX and TX.
|
||||||
*/
|
*/
|
||||||
spi->bits_per_word = 8;
|
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);
|
err = spi_setup(spi);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ int netup_spi_init(struct netup_unidvb_dev *ndev)
|
|||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct netup_spi *nspi;
|
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));
|
sizeof(struct netup_spi));
|
||||||
if (!master) {
|
if (!master) {
|
||||||
dev_err(&ndev->pci_dev->dev,
|
dev_err(&ndev->pci_dev->dev,
|
||||||
@@ -208,6 +208,7 @@ int netup_spi_init(struct netup_unidvb_dev *ndev)
|
|||||||
ndev->pci_slot,
|
ndev->pci_slot,
|
||||||
ndev->pci_func);
|
ndev->pci_func);
|
||||||
if (!spi_new_device(master, &netup_spi_board)) {
|
if (!spi_new_device(master, &netup_spi_board)) {
|
||||||
|
spi_unregister_master(master);
|
||||||
ndev->spi = NULL;
|
ndev->spi = NULL;
|
||||||
dev_err(&ndev->pci_dev->dev,
|
dev_err(&ndev->pci_dev->dev,
|
||||||
"%s(): unable to create SPI device\n", __func__);
|
"%s(): unable to create SPI device\n", __func__);
|
||||||
@@ -226,13 +227,13 @@ void netup_spi_release(struct netup_unidvb_dev *ndev)
|
|||||||
if (!spi)
|
if (!spi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
spi_unregister_master(spi->master);
|
||||||
spin_lock_irqsave(&spi->lock, flags);
|
spin_lock_irqsave(&spi->lock, flags);
|
||||||
reg = readw(&spi->regs->control_stat);
|
reg = readw(&spi->regs->control_stat);
|
||||||
writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat);
|
writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat);
|
||||||
reg = readw(&spi->regs->control_stat);
|
reg = readw(&spi->regs->control_stat);
|
||||||
writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat);
|
writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat);
|
||||||
spin_unlock_irqrestore(&spi->lock, flags);
|
spin_unlock_irqrestore(&spi->lock, flags);
|
||||||
spi_unregister_master(spi->master);
|
|
||||||
ndev->spi = NULL;
|
ndev->spi = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -741,8 +741,6 @@ static int cros_ec_spi_probe(struct spi_device *spi)
|
|||||||
struct cros_ec_spi *ec_spi;
|
struct cros_ec_spi *ec_spi;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
spi->bits_per_word = 8;
|
|
||||||
spi->mode = SPI_MODE_0;
|
|
||||||
spi->rt = true;
|
spi->rt = true;
|
||||||
err = spi_setup(spi);
|
err = spi_setup(spi);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
|||||||
@@ -255,6 +255,8 @@ config SPI_DW_MMIO
|
|||||||
config SPI_DW_BT1
|
config SPI_DW_BT1
|
||||||
tristate "Baikal-T1 SPI driver for DW SPI core"
|
tristate "Baikal-T1 SPI driver for DW SPI core"
|
||||||
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
|
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
|
||||||
|
select MULTIPLEXER
|
||||||
|
select MUX_MMIO
|
||||||
help
|
help
|
||||||
Baikal-T1 SoC is equipped with three DW APB SSI-based MMIO SPI
|
Baikal-T1 SoC is equipped with three DW APB SSI-based MMIO SPI
|
||||||
controllers. Two of them are pretty much normal: with IRQ, DMA,
|
controllers. Two of them are pretty much normal: with IRQ, DMA,
|
||||||
@@ -268,8 +270,6 @@ config SPI_DW_BT1
|
|||||||
config SPI_DW_BT1_DIRMAP
|
config SPI_DW_BT1_DIRMAP
|
||||||
bool "Directly mapped Baikal-T1 Boot SPI flash support"
|
bool "Directly mapped Baikal-T1 Boot SPI flash support"
|
||||||
depends on SPI_DW_BT1
|
depends on SPI_DW_BT1
|
||||||
select MULTIPLEXER
|
|
||||||
select MUX_MMIO
|
|
||||||
help
|
help
|
||||||
Directly mapped SPI flash memory is an interface specific to the
|
Directly mapped SPI flash memory is an interface specific to the
|
||||||
Baikal-T1 System Boot Controller. It is a 16MB MMIO region, which
|
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)
|
if (dummy_cycles)
|
||||||
ifr |= QSPI_IFR_NBDUM(dummy_cycles);
|
ifr |= QSPI_IFR_NBDUM(dummy_cycles);
|
||||||
|
|
||||||
/* Set data enable */
|
/* Set data enable and data transfer type. */
|
||||||
if (op->data.nbytes)
|
if (op->data.nbytes) {
|
||||||
ifr |= QSPI_IFR_DATAEN;
|
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
|
* If the QSPI controller is set in regular SPI mode, set it in
|
||||||
* Serial Memory Mode (SMM).
|
* Serial Memory Mode (SMM).
|
||||||
@@ -381,27 +385,24 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
|
|||||||
/* Clear pending interrupts */
|
/* Clear pending interrupts */
|
||||||
(void)atmel_qspi_read(aq, QSPI_SR);
|
(void)atmel_qspi_read(aq, QSPI_SR);
|
||||||
|
|
||||||
if (aq->caps->has_ricr) {
|
/* Set QSPI Instruction Frame registers. */
|
||||||
if (!op->addr.nbytes && op->data.dir == SPI_MEM_DATA_IN)
|
if (op->addr.nbytes && !op->data.nbytes)
|
||||||
ifr |= QSPI_IFR_APBTFRTYP_READ;
|
|
||||||
|
|
||||||
/* Set QSPI Instruction Frame registers */
|
|
||||||
atmel_qspi_write(iar, aq, QSPI_IAR);
|
atmel_qspi_write(iar, aq, QSPI_IAR);
|
||||||
|
|
||||||
|
if (aq->caps->has_ricr) {
|
||||||
if (op->data.dir == SPI_MEM_DATA_IN)
|
if (op->data.dir == SPI_MEM_DATA_IN)
|
||||||
atmel_qspi_write(icr, aq, QSPI_RICR);
|
atmel_qspi_write(icr, aq, QSPI_RICR);
|
||||||
else
|
else
|
||||||
atmel_qspi_write(icr, aq, QSPI_WICR);
|
atmel_qspi_write(icr, aq, QSPI_WICR);
|
||||||
atmel_qspi_write(ifr, aq, QSPI_IFR);
|
|
||||||
} else {
|
} 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;
|
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(icr, aq, QSPI_ICR);
|
||||||
atmel_qspi_write(ifr, aq, QSPI_IFR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atmel_qspi_write(ifr, aq, QSPI_IFR);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -535,7 +536,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
|||||||
struct resource *res;
|
struct resource *res;
|
||||||
int irq, err = 0;
|
int irq, err = 0;
|
||||||
|
|
||||||
ctrl = spi_alloc_master(&pdev->dev, sizeof(*aq));
|
ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*aq));
|
||||||
if (!ctrl)
|
if (!ctrl)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -557,8 +558,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
|||||||
aq->regs = devm_ioremap_resource(&pdev->dev, res);
|
aq->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(aq->regs)) {
|
if (IS_ERR(aq->regs)) {
|
||||||
dev_err(&pdev->dev, "missing registers\n");
|
dev_err(&pdev->dev, "missing registers\n");
|
||||||
err = PTR_ERR(aq->regs);
|
return PTR_ERR(aq->regs);
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Map the AHB memory */
|
/* 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);
|
aq->mem = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(aq->mem)) {
|
if (IS_ERR(aq->mem)) {
|
||||||
dev_err(&pdev->dev, "missing AHB memory\n");
|
dev_err(&pdev->dev, "missing AHB memory\n");
|
||||||
err = PTR_ERR(aq->mem);
|
return PTR_ERR(aq->mem);
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aq->mmap_size = resource_size(res);
|
aq->mmap_size = resource_size(res);
|
||||||
@@ -579,22 +578,21 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
if (IS_ERR(aq->pclk)) {
|
if (IS_ERR(aq->pclk)) {
|
||||||
dev_err(&pdev->dev, "missing peripheral clock\n");
|
dev_err(&pdev->dev, "missing peripheral clock\n");
|
||||||
err = PTR_ERR(aq->pclk);
|
return PTR_ERR(aq->pclk);
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable the peripheral clock */
|
/* Enable the peripheral clock */
|
||||||
err = clk_prepare_enable(aq->pclk);
|
err = clk_prepare_enable(aq->pclk);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "failed to enable the peripheral clock\n");
|
dev_err(&pdev->dev, "failed to enable the peripheral clock\n");
|
||||||
goto exit;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
aq->caps = of_device_get_match_data(&pdev->dev);
|
aq->caps = of_device_get_match_data(&pdev->dev);
|
||||||
if (!aq->caps) {
|
if (!aq->caps) {
|
||||||
dev_err(&pdev->dev, "Could not retrieve QSPI caps\n");
|
dev_err(&pdev->dev, "Could not retrieve QSPI caps\n");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto exit;
|
goto disable_pclk;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aq->caps->has_qspick) {
|
if (aq->caps->has_qspick) {
|
||||||
@@ -638,8 +636,6 @@ disable_qspick:
|
|||||||
clk_disable_unprepare(aq->qspick);
|
clk_disable_unprepare(aq->qspick);
|
||||||
disable_pclk:
|
disable_pclk:
|
||||||
clk_disable_unprepare(aq->pclk);
|
clk_disable_unprepare(aq->pclk);
|
||||||
exit:
|
|
||||||
spi_controller_put(ctrl);
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,7 +250,6 @@ static int amd_spi_probe(struct platform_device *pdev)
|
|||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct amd_spi *amd_spi;
|
struct amd_spi *amd_spi;
|
||||||
struct resource *res;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/* Allocate storage for spi_master and driver private data */
|
/* 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);
|
amd_spi = spi_master_get_devdata(master);
|
||||||
|
amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0);
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
amd_spi->io_remap_addr = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(amd_spi->io_remap_addr)) {
|
if (IS_ERR(amd_spi->io_remap_addr)) {
|
||||||
err = PTR_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);
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp));
|
ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||||
if (!ctlr) {
|
if (!ctlr) {
|
||||||
dev_info(&pdev->dev, "failed to allocate spi controller\n");
|
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 */
|
/* 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->clk_freq = clk_get_rate(clk);
|
||||||
sp->ctlr = ctlr;
|
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)
|
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);
|
ctlr = dev_get_drvdata(&pdev->dev);
|
||||||
sp = spi_controller_get_devdata(ctlr);
|
sp = spi_controller_get_devdata(ctlr);
|
||||||
|
|
||||||
|
spi_unregister_controller(ctlr);
|
||||||
clk_disable_unprepare(sp->clk);
|
clk_disable_unprepare(sp->clk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -512,8 +512,8 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
|||||||
|
|
||||||
master->dma_tx = dma_request_chan(dev, "tx");
|
master->dma_tx = dma_request_chan(dev, "tx");
|
||||||
if (IS_ERR(master->dma_tx)) {
|
if (IS_ERR(master->dma_tx)) {
|
||||||
err = dev_err_probe(dev, PTR_ERR(master->dma_tx),
|
err = PTR_ERR(master->dma_tx);
|
||||||
"No TX DMA channel, DMA is disabled\n");
|
dev_dbg(dev, "No TX DMA channel, DMA is disabled\n");
|
||||||
goto error_clear;
|
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
|
* No reason to check EPROBE_DEFER here since we have already
|
||||||
* requested tx channel.
|
* 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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -494,8 +494,10 @@ static int bcm63xx_hsspi_resume(struct device *dev)
|
|||||||
|
|
||||||
if (bs->pll_clk) {
|
if (bs->pll_clk) {
|
||||||
ret = clk_prepare_enable(bs->pll_clk);
|
ret = clk_prepare_enable(bs->pll_clk);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
clk_disable_unprepare(bs->clk);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_master_resume(master);
|
spi_master_resume(master);
|
||||||
|
|||||||
@@ -1040,13 +1040,13 @@ static int davinci_spi_remove(struct platform_device *pdev)
|
|||||||
spi_bitbang_stop(&dspi->bitbang);
|
spi_bitbang_stop(&dspi->bitbang);
|
||||||
|
|
||||||
clk_disable_unprepare(dspi->clk);
|
clk_disable_unprepare(dspi->clk);
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
if (dspi->dma_rx) {
|
if (dspi->dma_rx) {
|
||||||
dma_release_channel(dspi->dma_rx);
|
dma_release_channel(dspi->dma_rx);
|
||||||
dma_release_channel(dspi->dma_tx);
|
dma_release_channel(dspi->dma_tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spi_master_put(master);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ static int dw_spi_bt1_sys_init(struct platform_device *pdev,
|
|||||||
if (mem) {
|
if (mem) {
|
||||||
dwsbt1->map = devm_ioremap_resource(&pdev->dev, mem);
|
dwsbt1->map = devm_ioremap_resource(&pdev->dev, mem);
|
||||||
if (!IS_ERR(dwsbt1->map)) {
|
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_create = dw_spi_bt1_dirmap_create;
|
||||||
dws->mem_ops.dirmap_read = dw_spi_bt1_dirmap_read;
|
dws->mem_ops.dirmap_read = dw_spi_bt1_dirmap_read;
|
||||||
} else {
|
} else {
|
||||||
@@ -280,8 +280,10 @@ static int dw_spi_bt1_probe(struct platform_device *pdev)
|
|||||||
dws->bus_num = pdev->id;
|
dws->bus_num = pdev->id;
|
||||||
dws->reg_io_width = 4;
|
dws->reg_io_width = 4;
|
||||||
dws->max_freq = clk_get_rate(dwsbt1->clk);
|
dws->max_freq = clk_get_rate(dwsbt1->clk);
|
||||||
if (!dws->max_freq)
|
if (!dws->max_freq) {
|
||||||
|
ret = -EINVAL;
|
||||||
goto err_disable_clk;
|
goto err_disable_clk;
|
||||||
|
}
|
||||||
|
|
||||||
init_func = device_get_match_data(&pdev->dev);
|
init_func = device_get_match_data(&pdev->dev);
|
||||||
ret = init_func(pdev, dwsbt1);
|
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)
|
static void dw_writer(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
u32 max = tx_max(dws);
|
u32 max = tx_max(dws);
|
||||||
u16 txw = 0;
|
u32 txw = 0;
|
||||||
|
|
||||||
while (max--) {
|
while (max--) {
|
||||||
if (dws->tx) {
|
if (dws->tx) {
|
||||||
if (dws->n_bytes == 1)
|
if (dws->n_bytes == 1)
|
||||||
txw = *(u8 *)(dws->tx);
|
txw = *(u8 *)(dws->tx);
|
||||||
else
|
else if (dws->n_bytes == 2)
|
||||||
txw = *(u16 *)(dws->tx);
|
txw = *(u16 *)(dws->tx);
|
||||||
|
else
|
||||||
|
txw = *(u32 *)(dws->tx);
|
||||||
|
|
||||||
dws->tx += dws->n_bytes;
|
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)
|
static void dw_reader(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
u32 max = rx_max(dws);
|
u32 max = rx_max(dws);
|
||||||
u16 rxw;
|
u32 rxw;
|
||||||
|
|
||||||
while (max--) {
|
while (max--) {
|
||||||
rxw = dw_read_io_reg(dws, DW_SPI_DR);
|
rxw = dw_read_io_reg(dws, DW_SPI_DR);
|
||||||
if (dws->rx) {
|
if (dws->rx) {
|
||||||
if (dws->n_bytes == 1)
|
if (dws->n_bytes == 1)
|
||||||
*(u8 *)(dws->rx) = rxw;
|
*(u8 *)(dws->rx) = rxw;
|
||||||
else
|
else if (dws->n_bytes == 2)
|
||||||
*(u16 *)(dws->rx) = rxw;
|
*(u16 *)(dws->rx) = rxw;
|
||||||
|
else
|
||||||
|
*(u32 *)(dws->rx) = rxw;
|
||||||
|
|
||||||
dws->rx += dws->n_bytes;
|
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;
|
u32 speed_hz;
|
||||||
u16 clk_div;
|
u16 clk_div;
|
||||||
|
|
||||||
/* CTRLR0[ 4/3: 0] Data Frame Size */
|
/* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */
|
||||||
cr0 |= (cfg->dfs - 1);
|
cr0 |= (cfg->dfs - 1) << dws->dfs_offset;
|
||||||
|
|
||||||
if (!(dws->caps & DW_SPI_CAP_DWC_SSI))
|
if (!(dws->caps & DW_SPI_CAP_DWC_SSI))
|
||||||
/* CTRLR0[ 9:8] Transfer Mode */
|
/* 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);
|
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 */
|
/* enable HW fixup for explicit CS deselect for Amazon's alpine chip */
|
||||||
if (dws->caps & DW_SPI_CAP_CS_OVERRIDE)
|
if (dws->caps & DW_SPI_CAP_CS_OVERRIDE)
|
||||||
dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);
|
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->use_gpio_descriptors = true;
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
|
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->bus_num = dws->bus_num;
|
||||||
master->num_chipselect = dws->num_cs;
|
master->num_chipselect = dws->num_cs;
|
||||||
master->setup = dw_spi_setup;
|
master->setup = dw_spi_setup;
|
||||||
|
|||||||
@@ -222,6 +222,21 @@ static int dw_spi_keembay_init(struct platform_device *pdev,
|
|||||||
return 0;
|
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)
|
static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int (*init_func)(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 = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
|
||||||
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
|
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
|
||||||
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
|
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
|
||||||
|
{ .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
|
||||||
{ /* end of table */}
|
{ /* end of table */}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/spi/spi-mem.h>
|
#include <linux/spi/spi-mem.h>
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
|
||||||
/* Register offsets */
|
/* Register offsets */
|
||||||
#define DW_SPI_CTRLR0 0x00
|
#define DW_SPI_CTRLR0 0x00
|
||||||
@@ -41,6 +42,8 @@
|
|||||||
|
|
||||||
/* Bit fields in CTRLR0 */
|
/* Bit fields in CTRLR0 */
|
||||||
#define SPI_DFS_OFFSET 0
|
#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_OFFSET 4
|
||||||
#define SPI_FRF_SPI 0x0
|
#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_CS_OVERRIDE BIT(0)
|
||||||
#define DW_SPI_CAP_KEEMBAY_MST BIT(1)
|
#define DW_SPI_CAP_KEEMBAY_MST BIT(1)
|
||||||
#define DW_SPI_CAP_DWC_SSI BIT(2)
|
#define DW_SPI_CAP_DWC_SSI BIT(2)
|
||||||
|
#define DW_SPI_CAP_DFS32 BIT(3)
|
||||||
|
|
||||||
/* Slave spi_transfer/spi_mem_op related */
|
/* Slave spi_transfer/spi_mem_op related */
|
||||||
struct dw_spi_cfg {
|
struct dw_spi_cfg {
|
||||||
@@ -148,6 +152,7 @@ struct dw_spi {
|
|||||||
unsigned long paddr;
|
unsigned long paddr;
|
||||||
int irq;
|
int irq;
|
||||||
u32 fifo_len; /* depth of the FIFO buffer */
|
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_mem_freq; /* max mem-ops bus freq */
|
||||||
u32 max_freq; /* max bus freq supported */
|
u32 max_freq; /* max bus freq supported */
|
||||||
|
|
||||||
|
|||||||
@@ -1165,7 +1165,7 @@ static int dspi_init(struct fsl_dspi *dspi)
|
|||||||
unsigned int mcr;
|
unsigned int mcr;
|
||||||
|
|
||||||
/* Set idle states for all chip select signals to high */
|
/* 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)
|
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
|
||||||
mcr |= SPI_MCR_XSPI;
|
mcr |= SPI_MCR_XSPI;
|
||||||
@@ -1250,7 +1250,7 @@ static int dspi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
pdata = dev_get_platdata(&pdev->dev);
|
pdata = dev_get_platdata(&pdev->dev);
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
ctlr->num_chipselect = pdata->cs_num;
|
ctlr->num_chipselect = ctlr->max_native_cs = pdata->cs_num;
|
||||||
ctlr->bus_num = pdata->bus_num;
|
ctlr->bus_num = pdata->bus_num;
|
||||||
|
|
||||||
/* Only Coldfire uses platform data */
|
/* 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");
|
dev_err(&pdev->dev, "can't get spi-num-chipselects\n");
|
||||||
goto out_ctlr_put;
|
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);
|
of_property_read_u32(np, "bus-num", &bus_num);
|
||||||
ctlr->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);
|
type = fsl_spi_get_type(&ofdev->dev);
|
||||||
if (type == TYPE_FSL) {
|
if (type == TYPE_FSL) {
|
||||||
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
|
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
|
||||||
|
bool spisel_boot = false;
|
||||||
#if IS_ENABLED(CONFIG_FSL_SOC)
|
#if IS_ENABLED(CONFIG_FSL_SOC)
|
||||||
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
|
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) {
|
if (spisel_boot) {
|
||||||
pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4);
|
pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4);
|
||||||
if (!pinfo->immr_spi_cs)
|
if (!pinfo->immr_spi_cs)
|
||||||
@@ -734,10 +735,14 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
|
|||||||
* supported on the GRLIB variant.
|
* supported on the GRLIB variant.
|
||||||
*/
|
*/
|
||||||
ret = gpiod_count(dev, "cs");
|
ret = gpiod_count(dev, "cs");
|
||||||
if (ret <= 0)
|
if (ret < 0)
|
||||||
|
ret = 0;
|
||||||
|
if (ret == 0 && !spisel_boot) {
|
||||||
pdata->max_chipselect = 1;
|
pdata->max_chipselect = 1;
|
||||||
else
|
} else {
|
||||||
|
pdata->max_chipselect = ret + spisel_boot;
|
||||||
pdata->cs_control = fsl_spi_cs_control;
|
pdata->cs_control = fsl_spi_cs_control;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_address_to_resource(np, 0, &mem);
|
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))
|
if (IS_ERR(clk))
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
|
|
||||||
spi = spi_alloc_master(dev, sizeof(*mas));
|
spi = devm_spi_alloc_master(dev, sizeof(*mas));
|
||||||
if (!spi)
|
if (!spi)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -636,6 +636,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
|||||||
spi->auto_runtime_pm = true;
|
spi->auto_runtime_pm = true;
|
||||||
spi->handle_err = handle_fifo_timeout;
|
spi->handle_err = handle_fifo_timeout;
|
||||||
spi->set_cs = spi_geni_set_cs;
|
spi->set_cs = spi_geni_set_cs;
|
||||||
|
spi->use_gpio_descriptors = true;
|
||||||
|
|
||||||
init_completion(&mas->cs_done);
|
init_completion(&mas->cs_done);
|
||||||
init_completion(&mas->cancel_done);
|
init_completion(&mas->cancel_done);
|
||||||
@@ -673,7 +674,6 @@ spi_geni_probe_free_irq:
|
|||||||
free_irq(mas->irq, spi);
|
free_irq(mas->irq, spi);
|
||||||
spi_geni_probe_runtime_disable:
|
spi_geni_probe_runtime_disable:
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
spi_master_put(spi);
|
|
||||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||||
put_clkname:
|
put_clkname:
|
||||||
dev_pm_opp_put_clkname(mas->se.opp_table);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spi_gpio_put(void *data)
|
|
||||||
{
|
|
||||||
spi_master_put(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int spi_gpio_probe(struct platform_device *pdev)
|
static int spi_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
@@ -363,16 +358,10 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
|||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct spi_bitbang *bb;
|
struct spi_bitbang *bb;
|
||||||
|
|
||||||
master = spi_alloc_master(dev, sizeof(*spi_gpio));
|
master = devm_spi_alloc_master(dev, sizeof(*spi_gpio));
|
||||||
if (!master)
|
if (!master)
|
||||||
return -ENOMEM;
|
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)
|
if (pdev->dev.of_node)
|
||||||
status = spi_gpio_probe_dt(pdev, master);
|
status = spi_gpio_probe_dt(pdev, master);
|
||||||
else
|
else
|
||||||
@@ -432,7 +421,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
|||||||
if (status)
|
if (status)
|
||||||
return 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);
|
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||||
|
|||||||
@@ -731,8 +731,10 @@ static int img_spfi_resume(struct device *dev)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = pm_runtime_get_sync(dev);
|
ret = pm_runtime_get_sync(dev);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
pm_runtime_put_noidle(dev);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
spfi_reset(spfi);
|
spfi_reset(spfi);
|
||||||
pm_runtime_put(dev);
|
pm_runtime_put(dev);
|
||||||
|
|
||||||
|
|||||||
@@ -1019,33 +1019,6 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
|
|||||||
.devtype = IMX53_ECSPI,
|
.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[] = {
|
static const struct of_device_id spi_imx_dt_ids[] = {
|
||||||
{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
|
{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
|
||||||
{ .compatible = "fsl,imx21-cspi", .data = &imx21_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);
|
ret = pm_runtime_get_sync(spi_imx->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(spi_imx->dev);
|
||||||
dev_err(spi_imx->dev, "failed to enable clock\n");
|
dev_err(spi_imx->dev, "failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1580,8 +1554,7 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|||||||
struct spi_imx_data *spi_imx;
|
struct spi_imx_data *spi_imx;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret, irq, spi_drctl;
|
int ret, irq, spi_drctl;
|
||||||
const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data :
|
const struct spi_imx_devtype_data *devtype_data = of_id->data;
|
||||||
(struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
|
|
||||||
bool slave_mode;
|
bool slave_mode;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
@@ -1748,6 +1721,7 @@ static int spi_imx_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(spi_imx->dev);
|
ret = pm_runtime_get_sync(spi_imx->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(spi_imx->dev);
|
||||||
dev_err(spi_imx->dev, "failed to enable clock\n");
|
dev_err(spi_imx->dev, "failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1822,7 +1796,6 @@ static struct platform_driver spi_imx_driver = {
|
|||||||
.of_match_table = spi_imx_dt_ids,
|
.of_match_table = spi_imx_dt_ids,
|
||||||
.pm = &imx_spi_pm,
|
.pm = &imx_spi_pm,
|
||||||
},
|
},
|
||||||
.id_table = spi_imx_devtype,
|
|
||||||
.probe = spi_imx_probe,
|
.probe = spi_imx_probe,
|
||||||
.remove = spi_imx_remove,
|
.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);
|
ret = pm_runtime_get_sync(ctlr->dev.parent);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(ctlr->dev.parent);
|
||||||
dev_err(&ctlr->dev, "Failed to power device: %d\n",
|
dev_err(&ctlr->dev, "Failed to power device: %d\n",
|
||||||
ret);
|
ret);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -743,7 +744,7 @@ static int spi_mem_probe(struct spi_device *spi)
|
|||||||
mem->name = dev_name(&spi->dev);
|
mem->name = dev_name(&spi->dev);
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(mem->name))
|
if (IS_ERR_OR_NULL(mem->name))
|
||||||
return PTR_ERR(mem->name);
|
return PTR_ERR_OR_ZERO(mem->name);
|
||||||
|
|
||||||
spi_set_drvdata(spi, mem);
|
spi_set_drvdata(spi, mem);
|
||||||
|
|
||||||
|
|||||||
@@ -350,9 +350,10 @@ static int mt7621_spi_probe(struct platform_device *pdev)
|
|||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
master = spi_alloc_master(&pdev->dev, sizeof(*rs));
|
master = devm_spi_alloc_master(&pdev->dev, sizeof(*rs));
|
||||||
if (!master) {
|
if (!master) {
|
||||||
dev_info(&pdev->dev, "master allocation failed\n");
|
dev_info(&pdev->dev, "master allocation failed\n");
|
||||||
|
clk_disable_unprepare(clk);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,10 +378,15 @@ static int mt7621_spi_probe(struct platform_device *pdev)
|
|||||||
ret = device_reset(&pdev->dev);
|
ret = device_reset(&pdev->dev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "SPI reset failed!\n");
|
dev_err(&pdev->dev, "SPI reset failed!\n");
|
||||||
|
clk_disable_unprepare(clk);
|
||||||
return ret;
|
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)
|
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);
|
master = dev_get_drvdata(&pdev->dev);
|
||||||
rs = spi_controller_get_devdata(master);
|
rs = spi_controller_get_devdata(master);
|
||||||
|
|
||||||
|
spi_unregister_controller(master);
|
||||||
clk_disable_unprepare(rs->clk);
|
clk_disable_unprepare(rs->clk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ struct mtk_nor {
|
|||||||
dma_addr_t buffer_dma;
|
dma_addr_t buffer_dma;
|
||||||
struct clk *spi_clk;
|
struct clk *spi_clk;
|
||||||
struct clk *ctlr_clk;
|
struct clk *ctlr_clk;
|
||||||
|
struct clk *axi_clk;
|
||||||
unsigned int spi_freq;
|
unsigned int spi_freq;
|
||||||
bool wbuf_en;
|
bool wbuf_en;
|
||||||
bool has_irq;
|
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->spi_clk);
|
||||||
clk_disable_unprepare(sp->ctlr_clk);
|
clk_disable_unprepare(sp->ctlr_clk);
|
||||||
|
clk_disable_unprepare(sp->axi_clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mtk_nor_enable_clk(struct mtk_nor *sp)
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,7 +755,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
|
|||||||
struct spi_controller *ctlr;
|
struct spi_controller *ctlr;
|
||||||
struct mtk_nor *sp;
|
struct mtk_nor *sp;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct clk *spi_clk, *ctlr_clk;
|
struct clk *spi_clk, *ctlr_clk, *axi_clk;
|
||||||
int ret, irq;
|
int ret, irq;
|
||||||
unsigned long dma_bits;
|
unsigned long dma_bits;
|
||||||
|
|
||||||
@@ -762,13 +771,17 @@ static int mtk_nor_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(ctlr_clk))
|
if (IS_ERR(ctlr_clk))
|
||||||
return PTR_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);
|
dma_bits = (unsigned long)of_device_get_match_data(&pdev->dev);
|
||||||
if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits))) {
|
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);
|
dev_err(&pdev->dev, "failed to set dma mask(%lu)\n", dma_bits);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp));
|
ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||||
if (!ctlr) {
|
if (!ctlr) {
|
||||||
dev_err(&pdev->dev, "failed to allocate spi controller\n");
|
dev_err(&pdev->dev, "failed to allocate spi controller\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -794,6 +807,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
|
|||||||
sp->dev = &pdev->dev;
|
sp->dev = &pdev->dev;
|
||||||
sp->spi_clk = spi_clk;
|
sp->spi_clk = spi_clk;
|
||||||
sp->ctlr_clk = ctlr_clk;
|
sp->ctlr_clk = ctlr_clk;
|
||||||
|
sp->axi_clk = axi_clk;
|
||||||
sp->high_dma = (dma_bits > 32);
|
sp->high_dma = (dma_bits > 32);
|
||||||
sp->buffer = dmam_alloc_coherent(&pdev->dev,
|
sp->buffer = dmam_alloc_coherent(&pdev->dev,
|
||||||
MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
|
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;
|
struct mxic_spi *mxic;
|
||||||
int ret;
|
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)
|
if (!master)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -574,15 +574,9 @@ static int mxic_spi_probe(struct platform_device *pdev)
|
|||||||
ret = spi_register_master(master);
|
ret = spi_register_master(master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "spi_register_master failed\n");
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -607,6 +607,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(ssp->dev);
|
ret = pm_runtime_get_sync(ssp->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(ssp->dev);
|
||||||
dev_err(ssp->dev, "runtime_get_sync failed\n");
|
dev_err(ssp->dev, "runtime_get_sync failed\n");
|
||||||
goto out_pm_runtime_disable;
|
goto out_pm_runtime_disable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -677,7 +677,7 @@ static int npcm_fiu_probe(struct platform_device *pdev)
|
|||||||
struct npcm_fiu_spi *fiu;
|
struct npcm_fiu_spi *fiu;
|
||||||
void __iomem *regbase;
|
void __iomem *regbase;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int id;
|
int id, ret;
|
||||||
|
|
||||||
ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
|
ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
|
||||||
if (!ctrl)
|
if (!ctrl)
|
||||||
@@ -735,7 +735,11 @@ static int npcm_fiu_probe(struct platform_device *pdev)
|
|||||||
ctrl->num_chipselect = fiu->info->max_cs;
|
ctrl->num_chipselect = fiu->info->max_cs;
|
||||||
ctrl->dev.of_node = dev->of_node;
|
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)
|
static int npcm_fiu_remove(struct platform_device *pdev)
|
||||||
|
|||||||
@@ -839,6 +839,7 @@ static int pic32_spi_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_bailout:
|
err_bailout:
|
||||||
|
pic32_spi_dma_unprep(pic32s);
|
||||||
clk_disable_unprepare(pic32s->clk);
|
clk_disable_unprepare(pic32s->clk);
|
||||||
err_master:
|
err_master:
|
||||||
spi_master_put(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, 0x5ac2), LPSS_BXT_SSP },
|
||||||
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
|
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
|
||||||
{ PCI_VDEVICE(INTEL, 0x5ac6), 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 */
|
/* CNL-LP */
|
||||||
{ PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP },
|
{ PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP },
|
||||||
{ PCI_VDEVICE(INTEL, 0x9dab), 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)
|
if (platform_info->is_slave)
|
||||||
controller = spi_alloc_slave(dev, sizeof(struct driver_data));
|
controller = devm_spi_alloc_slave(dev, sizeof(*drv_data));
|
||||||
else
|
else
|
||||||
controller = spi_alloc_master(dev, sizeof(struct driver_data));
|
controller = devm_spi_alloc_master(dev, sizeof(*drv_data));
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
dev_err(&pdev->dev, "cannot alloc spi_controller\n");
|
dev_err(&pdev->dev, "cannot alloc spi_controller\n");
|
||||||
@@ -1911,7 +1916,6 @@ out_error_dma_irq_alloc:
|
|||||||
free_irq(ssp->irq, drv_data);
|
free_irq(ssp->irq, drv_data);
|
||||||
|
|
||||||
out_error_controller_alloc:
|
out_error_controller_alloc:
|
||||||
spi_controller_put(controller);
|
|
||||||
pxa_ssp_free(ssp);
|
pxa_ssp_free(ssp);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
dev = &pdev->dev;
|
dev = &pdev->dev;
|
||||||
|
|
||||||
master = spi_alloc_master(dev, sizeof(*ctrl));
|
master = devm_spi_alloc_master(dev, sizeof(*ctrl));
|
||||||
if (!master)
|
if (!master)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -473,54 +473,49 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
|||||||
spin_lock_init(&ctrl->lock);
|
spin_lock_init(&ctrl->lock);
|
||||||
ctrl->dev = dev;
|
ctrl->dev = dev;
|
||||||
ctrl->base = devm_platform_ioremap_resource(pdev, 0);
|
ctrl->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(ctrl->base)) {
|
if (IS_ERR(ctrl->base))
|
||||||
ret = PTR_ERR(ctrl->base);
|
return PTR_ERR(ctrl->base);
|
||||||
goto exit_probe_master_put;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl->clks = devm_kcalloc(dev, QSPI_NUM_CLKS,
|
ctrl->clks = devm_kcalloc(dev, QSPI_NUM_CLKS,
|
||||||
sizeof(*ctrl->clks), GFP_KERNEL);
|
sizeof(*ctrl->clks), GFP_KERNEL);
|
||||||
if (!ctrl->clks) {
|
if (!ctrl->clks)
|
||||||
ret = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto exit_probe_master_put;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl->clks[QSPI_CLK_CORE].id = "core";
|
ctrl->clks[QSPI_CLK_CORE].id = "core";
|
||||||
ctrl->clks[QSPI_CLK_IFACE].id = "iface";
|
ctrl->clks[QSPI_CLK_IFACE].id = "iface";
|
||||||
ret = devm_clk_bulk_get(dev, QSPI_NUM_CLKS, ctrl->clks);
|
ret = devm_clk_bulk_get(dev, QSPI_NUM_CLKS, ctrl->clks);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto exit_probe_master_put;
|
return ret;
|
||||||
|
|
||||||
ctrl->icc_path_cpu_to_qspi = devm_of_icc_get(dev, "qspi-config");
|
ctrl->icc_path_cpu_to_qspi = devm_of_icc_get(dev, "qspi-config");
|
||||||
if (IS_ERR(ctrl->icc_path_cpu_to_qspi)) {
|
if (IS_ERR(ctrl->icc_path_cpu_to_qspi))
|
||||||
ret = dev_err_probe(dev, PTR_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");
|
"Failed to get cpu path\n");
|
||||||
goto exit_probe_master_put;
|
|
||||||
}
|
|
||||||
/* Set BW vote for register access */
|
/* Set BW vote for register access */
|
||||||
ret = icc_set_bw(ctrl->icc_path_cpu_to_qspi, Bps_to_icc(1000),
|
ret = icc_set_bw(ctrl->icc_path_cpu_to_qspi, Bps_to_icc(1000),
|
||||||
Bps_to_icc(1000));
|
Bps_to_icc(1000));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(ctrl->dev, "%s: ICC BW voting failed for cpu: %d\n",
|
dev_err(ctrl->dev, "%s: ICC BW voting failed for cpu: %d\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
goto exit_probe_master_put;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = icc_disable(ctrl->icc_path_cpu_to_qspi);
|
ret = icc_disable(ctrl->icc_path_cpu_to_qspi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(ctrl->dev, "%s: ICC disable failed for cpu: %d\n",
|
dev_err(ctrl->dev, "%s: ICC disable failed for cpu: %d\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
goto exit_probe_master_put;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = platform_get_irq(pdev, 0);
|
ret = platform_get_irq(pdev, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto exit_probe_master_put;
|
return ret;
|
||||||
ret = devm_request_irq(dev, ret, qcom_qspi_irq,
|
ret = devm_request_irq(dev, ret, qcom_qspi_irq,
|
||||||
IRQF_TRIGGER_HIGH, dev_name(dev), ctrl);
|
IRQF_TRIGGER_HIGH, dev_name(dev), ctrl);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Failed to request irq %d\n", ret);
|
dev_err(dev, "Failed to request irq %d\n", ret);
|
||||||
goto exit_probe_master_put;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
master->max_speed_hz = 300000000;
|
master->max_speed_hz = 300000000;
|
||||||
@@ -537,10 +532,8 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
|||||||
master->auto_runtime_pm = true;
|
master->auto_runtime_pm = true;
|
||||||
|
|
||||||
ctrl->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core");
|
ctrl->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core");
|
||||||
if (IS_ERR(ctrl->opp_table)) {
|
if (IS_ERR(ctrl->opp_table))
|
||||||
ret = PTR_ERR(ctrl->opp_table);
|
return PTR_ERR(ctrl->opp_table);
|
||||||
goto exit_probe_master_put;
|
|
||||||
}
|
|
||||||
/* OPP table is optional */
|
/* OPP table is optional */
|
||||||
ret = dev_pm_opp_of_add_table(&pdev->dev);
|
ret = dev_pm_opp_of_add_table(&pdev->dev);
|
||||||
if (ret && ret != -ENODEV) {
|
if (ret && ret != -ENODEV) {
|
||||||
@@ -562,9 +555,6 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
|||||||
exit_probe_put_clkname:
|
exit_probe_put_clkname:
|
||||||
dev_pm_opp_put_clkname(ctrl->opp_table);
|
dev_pm_opp_put_clkname(ctrl->opp_table);
|
||||||
|
|
||||||
exit_probe_master_put:
|
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(spi_base))
|
if (IS_ERR(spi_base))
|
||||||
return PTR_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)
|
if (!master)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,8 @@
|
|||||||
#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002
|
#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002
|
||||||
#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002
|
#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002
|
||||||
|
|
||||||
|
#define ROCKCHIP_AUTOSUSPEND_TIMEOUT 2000
|
||||||
|
|
||||||
struct rockchip_spi {
|
struct rockchip_spi {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
@@ -715,6 +717,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)
|
|||||||
goto err_disable_spiclk;
|
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_set_active(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ static int rpcif_spi_probe(struct platform_device *pdev)
|
|||||||
struct rpcif *rpc;
|
struct rpcif *rpc;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
ctlr = spi_alloc_master(&pdev->dev, sizeof(*rpc));
|
ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*rpc));
|
||||||
if (!ctlr)
|
if (!ctlr)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -159,13 +159,8 @@ static int rpcif_spi_probe(struct platform_device *pdev)
|
|||||||
error = spi_register_controller(ctlr);
|
error = spi_register_controller(ctlr);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&pdev->dev, "spi_register_controller failed\n");
|
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;
|
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_platform_data *pdata = dev_get_platdata(dev);
|
||||||
struct sc18is602 *hw;
|
struct sc18is602 *hw;
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
int error;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||||
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
master = spi_alloc_master(dev, sizeof(struct sc18is602));
|
master = devm_spi_alloc_master(dev, sizeof(struct sc18is602));
|
||||||
if (!master)
|
if (!master)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@@ -298,15 +297,7 @@ static int sc18is602_probe(struct i2c_client *client,
|
|||||||
master->min_speed_hz = hw->freq / 128;
|
master->min_speed_hz = hw->freq / 128;
|
||||||
master->max_speed_hz = hw->freq / 4;
|
master->max_speed_hz = hw->freq / 4;
|
||||||
|
|
||||||
error = devm_spi_register_master(dev, master);
|
return devm_spi_register_master(dev, master);
|
||||||
if (error)
|
|
||||||
goto error_reg;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error_reg:
|
|
||||||
spi_master_put(master);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id sc18is602_id[] = {
|
static const struct i2c_device_id sc18is602_id[] = {
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ static int spi_sh_probe(struct platform_device *pdev)
|
|||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
return irq;
|
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) {
|
if (master == NULL) {
|
||||||
dev_err(&pdev->dev, "spi_alloc_master error.\n");
|
dev_err(&pdev->dev, "spi_alloc_master error.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -458,16 +458,14 @@ static int spi_sh_probe(struct platform_device *pdev)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(&pdev->dev, "No support width\n");
|
dev_err(&pdev->dev, "No support width\n");
|
||||||
ret = -ENODEV;
|
return -ENODEV;
|
||||||
goto error1;
|
|
||||||
}
|
}
|
||||||
ss->irq = irq;
|
ss->irq = irq;
|
||||||
ss->master = master;
|
ss->master = master;
|
||||||
ss->addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
ss->addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||||
if (ss->addr == NULL) {
|
if (ss->addr == NULL) {
|
||||||
dev_err(&pdev->dev, "ioremap error.\n");
|
dev_err(&pdev->dev, "ioremap error.\n");
|
||||||
ret = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto error1;
|
|
||||||
}
|
}
|
||||||
INIT_LIST_HEAD(&ss->queue);
|
INIT_LIST_HEAD(&ss->queue);
|
||||||
spin_lock_init(&ss->lock);
|
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);
|
ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "request_irq error\n");
|
dev_err(&pdev->dev, "request_irq error\n");
|
||||||
goto error1;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
master->num_chipselect = 2;
|
master->num_chipselect = 2;
|
||||||
@@ -496,9 +494,6 @@ static int spi_sh_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
error3:
|
error3:
|
||||||
free_irq(irq, ss);
|
free_irq(irq, ss);
|
||||||
error1:
|
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1010,6 +1010,7 @@ static int sprd_spi_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(ss->dev);
|
ret = pm_runtime_get_sync(ss->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(ss->dev);
|
||||||
dev_err(ss->dev, "failed to resume SPI controller\n");
|
dev_err(ss->dev, "failed to resume SPI controller\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -375,13 +375,14 @@ static int spi_st_probe(struct platform_device *pdev)
|
|||||||
ret = devm_spi_register_master(&pdev->dev, master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Failed to register master\n");
|
dev_err(&pdev->dev, "Failed to register master\n");
|
||||||
goto clk_disable;
|
goto rpm_disable;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
clk_disable:
|
rpm_disable:
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
clk_disable:
|
||||||
clk_disable_unprepare(spi_st->clk);
|
clk_disable_unprepare(spi_st->clk);
|
||||||
put_master:
|
put_master:
|
||||||
spi_master_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;
|
int ret;
|
||||||
|
|
||||||
ret = pm_runtime_get_sync(qspi->dev);
|
ret = pm_runtime_get_sync(qspi->dev);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(qspi->dev);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&qspi->lock);
|
mutex_lock(&qspi->lock);
|
||||||
ret = stm32_qspi_send(mem, op);
|
ret = stm32_qspi_send(mem, op);
|
||||||
@@ -462,8 +464,10 @@ static int stm32_qspi_setup(struct spi_device *spi)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = pm_runtime_get_sync(qspi->dev);
|
ret = pm_runtime_get_sync(qspi->dev);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(qspi->dev);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1;
|
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);
|
ret = pm_runtime_get_sync(dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(dev);
|
||||||
dev_err(dev, "Unable to power device:%d\n", ret);
|
dev_err(dev, "Unable to power device:%d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,12 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
|
#include <linux/dmaengine.h>
|
||||||
|
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
|
#define SUN6I_AUTOSUSPEND_TIMEOUT 2000
|
||||||
|
|
||||||
#define SUN6I_FIFO_DEPTH 128
|
#define SUN6I_FIFO_DEPTH 128
|
||||||
#define SUN8I_FIFO_DEPTH 64
|
#define SUN8I_FIFO_DEPTH 64
|
||||||
|
|
||||||
@@ -52,10 +55,12 @@
|
|||||||
|
|
||||||
#define SUN6I_FIFO_CTL_REG 0x18
|
#define SUN6I_FIFO_CTL_REG 0x18
|
||||||
#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK 0xff
|
#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_RDY_TRIG_LEVEL_BITS 0
|
||||||
#define SUN6I_FIFO_CTL_RF_RST BIT(15)
|
#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_MASK 0xff
|
||||||
#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS 16
|
#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_CTL_TF_RST BIT(31)
|
||||||
|
|
||||||
#define SUN6I_FIFO_STA_REG 0x1c
|
#define SUN6I_FIFO_STA_REG 0x1c
|
||||||
@@ -83,6 +88,8 @@
|
|||||||
struct sun6i_spi {
|
struct sun6i_spi {
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
void __iomem *base_addr;
|
void __iomem *base_addr;
|
||||||
|
dma_addr_t dma_addr_rx;
|
||||||
|
dma_addr_t dma_addr_tx;
|
||||||
struct clk *hclk;
|
struct clk *hclk;
|
||||||
struct clk *mclk;
|
struct clk *mclk;
|
||||||
struct reset_control *rstc;
|
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;
|
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,
|
static int sun6i_spi_transfer_one(struct spi_master *master,
|
||||||
struct spi_device *spi,
|
struct spi_device *spi,
|
||||||
struct spi_transfer *tfr)
|
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 start, end, tx_time;
|
||||||
unsigned int trig_level;
|
unsigned int trig_level;
|
||||||
unsigned int tx_len = 0, rx_len = 0;
|
unsigned int tx_len = 0, rx_len = 0;
|
||||||
|
bool use_dma;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
@@ -201,6 +271,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
|
|||||||
sspi->tx_buf = tfr->tx_buf;
|
sspi->tx_buf = tfr->tx_buf;
|
||||||
sspi->rx_buf = tfr->rx_buf;
|
sspi->rx_buf = tfr->rx_buf;
|
||||||
sspi->len = tfr->len;
|
sspi->len = tfr->len;
|
||||||
|
use_dma = master->can_dma ? master->can_dma(master, spi, tfr) : false;
|
||||||
|
|
||||||
/* Clear pending interrupts */
|
/* Clear pending interrupts */
|
||||||
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
|
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_spi_write(sspi, SUN6I_FIFO_CTL_REG,
|
||||||
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
|
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
|
||||||
|
|
||||||
/*
|
reg = 0;
|
||||||
* Setup FIFO interrupt trigger level
|
|
||||||
* Here we choose 3/4 of the full fifo depth, as it's the hardcoded
|
if (!use_dma) {
|
||||||
* value used in old generation of Allwinner SPI controller.
|
/*
|
||||||
* (See spi-sun4i.c)
|
* Setup FIFO interrupt trigger level
|
||||||
*/
|
* Here we choose 3/4 of the full fifo depth, as it's
|
||||||
trig_level = sspi->fifo_depth / 4 * 3;
|
* the hardcoded value used in old generation of Allwinner
|
||||||
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
|
* SPI controller. (See spi-sun4i.c)
|
||||||
(trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
|
*/
|
||||||
(trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
|
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,
|
* 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_XMIT_CNT_REG, tx_len);
|
||||||
sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len);
|
sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len);
|
||||||
|
|
||||||
/* Fill the TX FIFO */
|
if (!use_dma) {
|
||||||
sun6i_spi_fill_fifo(sspi);
|
/* 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 */
|
/* Enable the interrupts */
|
||||||
reg = SUN6I_INT_CTL_TC;
|
reg = SUN6I_INT_CTL_TC;
|
||||||
|
|
||||||
if (rx_len > sspi->fifo_depth)
|
if (!use_dma) {
|
||||||
reg |= SUN6I_INT_CTL_RF_RDY;
|
if (rx_len > sspi->fifo_depth)
|
||||||
if (tx_len > sspi->fifo_depth)
|
reg |= SUN6I_INT_CTL_RF_RDY;
|
||||||
reg |= SUN6I_INT_CTL_TF_ERQ;
|
if (tx_len > sspi->fifo_depth)
|
||||||
|
reg |= SUN6I_INT_CTL_TF_ERQ;
|
||||||
|
}
|
||||||
|
|
||||||
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
|
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);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,10 +528,25 @@ static int sun6i_spi_runtime_suspend(struct device *dev)
|
|||||||
return 0;
|
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)
|
static int sun6i_spi_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct sun6i_spi *sspi;
|
struct sun6i_spi *sspi;
|
||||||
|
struct resource *mem;
|
||||||
int ret = 0, irq;
|
int ret = 0, irq;
|
||||||
|
|
||||||
master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
|
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);
|
platform_set_drvdata(pdev, master);
|
||||||
sspi = spi_master_get_devdata(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)) {
|
if (IS_ERR(sspi->base_addr)) {
|
||||||
ret = PTR_ERR(sspi->base_addr);
|
ret = PTR_ERR(sspi->base_addr);
|
||||||
goto err_free_master;
|
goto err_free_master;
|
||||||
@@ -494,6 +615,33 @@ static int sun6i_spi_probe(struct platform_device *pdev)
|
|||||||
goto err_free_master;
|
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
|
* This wake-up/shutdown pattern is to be able to have the
|
||||||
* device woken up, even if runtime_pm is disabled
|
* 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);
|
ret = sun6i_spi_runtime_resume(&pdev->dev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Couldn't resume the device\n");
|
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_set_active(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
pm_runtime_idle(&pdev->dev);
|
|
||||||
|
|
||||||
ret = devm_spi_register_master(&pdev->dev, master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -519,6 +668,12 @@ static int sun6i_spi_probe(struct platform_device *pdev)
|
|||||||
err_pm_disable:
|
err_pm_disable:
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
sun6i_spi_runtime_suspend(&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:
|
err_free_master:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -526,8 +681,14 @@ err_free_master:
|
|||||||
|
|
||||||
static int sun6i_spi_remove(struct platform_device *pdev)
|
static int sun6i_spi_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct spi_master *master = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
pm_runtime_force_suspend(&pdev->dev);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -657,7 +657,8 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
if (!master->max_speed_hz) {
|
if (!master->max_speed_hz) {
|
||||||
dev_err(&pdev->dev, "missing clock source\n");
|
dev_err(&pdev->dev, "missing clock source\n");
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto disable_clk;
|
||||||
}
|
}
|
||||||
master->min_speed_hz = master->max_speed_hz / 254;
|
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);
|
rx_irq = platform_get_irq(pdev, 0);
|
||||||
if (rx_irq <= 0) {
|
if (rx_irq <= 0) {
|
||||||
ret = rx_irq;
|
ret = rx_irq;
|
||||||
goto put_spi;
|
goto disable_clk;
|
||||||
}
|
}
|
||||||
snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx",
|
snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx",
|
||||||
dev_name(&pdev->dev));
|
dev_name(&pdev->dev));
|
||||||
@@ -678,13 +679,13 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
|||||||
0, sspi->rx_irq_name, sspi);
|
0, sspi->rx_irq_name, sspi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "request rx_irq failed (%d)\n", 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);
|
tx_irq = platform_get_irq(pdev, 1);
|
||||||
if (tx_irq <= 0) {
|
if (tx_irq <= 0) {
|
||||||
ret = tx_irq;
|
ret = tx_irq;
|
||||||
goto put_spi;
|
goto disable_clk;
|
||||||
}
|
}
|
||||||
snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx",
|
snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx",
|
||||||
dev_name(&pdev->dev));
|
dev_name(&pdev->dev));
|
||||||
@@ -692,7 +693,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
|||||||
0, sspi->tx_irq_name, sspi);
|
0, sspi->tx_irq_name, sspi);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
|
dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
|
||||||
goto put_spi;
|
goto disable_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
master->dev.of_node = np;
|
master->dev.of_node = np;
|
||||||
@@ -710,7 +711,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = synquacer_spi_enable(master);
|
ret = synquacer_spi_enable(master);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail_enable;
|
goto disable_clk;
|
||||||
|
|
||||||
pm_runtime_set_active(sspi->dev);
|
pm_runtime_set_active(sspi->dev);
|
||||||
pm_runtime_enable(sspi->dev);
|
pm_runtime_enable(sspi->dev);
|
||||||
@@ -723,7 +724,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
disable_pm:
|
disable_pm:
|
||||||
pm_runtime_disable(sspi->dev);
|
pm_runtime_disable(sspi->dev);
|
||||||
fail_enable:
|
disable_clk:
|
||||||
clk_disable_unprepare(sspi->clk);
|
clk_disable_unprepare(sspi->clk);
|
||||||
put_spi:
|
put_spi:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
|
|||||||
@@ -966,6 +966,7 @@ static int tegra_spi_setup(struct spi_device *spi)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(tspi->dev);
|
ret = pm_runtime_get_sync(tspi->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(tspi->dev);
|
||||||
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
|
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
|
||||||
if (cdata)
|
if (cdata)
|
||||||
tegra_spi_cleanup(spi);
|
tegra_spi_cleanup(spi);
|
||||||
@@ -1474,6 +1475,7 @@ static int tegra_spi_resume(struct device *dev)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(dev);
|
ret = pm_runtime_get_sync(dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(dev);
|
||||||
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -552,6 +552,7 @@ static int tegra_sflash_resume(struct device *dev)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(dev);
|
ret = pm_runtime_get_sync(dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(dev);
|
||||||
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -751,6 +751,7 @@ static int tegra_slink_setup(struct spi_device *spi)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(tspi->dev);
|
ret = pm_runtime_get_sync(tspi->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(tspi->dev);
|
||||||
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
|
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1188,6 +1189,7 @@ static int tegra_slink_resume(struct device *dev)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(dev);
|
ret = pm_runtime_get_sync(dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(dev);
|
||||||
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ static int ti_qspi_setup(struct spi_device *spi)
|
|||||||
|
|
||||||
ret = pm_runtime_get_sync(qspi->dev);
|
ret = pm_runtime_get_sync(qspi->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(qspi->dev);
|
||||||
dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
|
dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
|
||||||
return ret;
|
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);
|
return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bus_type spi_bus_type = {
|
static int spi_probe(struct device *dev)
|
||||||
.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)
|
|
||||||
{
|
{
|
||||||
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
||||||
struct spi_device *spi = to_spi_device(dev);
|
struct spi_device *spi = to_spi_device(dev);
|
||||||
@@ -405,31 +396,55 @@ static int spi_drv_probe(struct device *dev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = sdrv->probe(spi);
|
if (sdrv->probe) {
|
||||||
if (ret)
|
ret = sdrv->probe(spi);
|
||||||
dev_pm_domain_detach(dev, true);
|
if (ret)
|
||||||
|
dev_pm_domain_detach(dev, true);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
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);
|
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);
|
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
|
* __spi_register_driver - register a SPI driver
|
||||||
* @owner: owner module of the driver to register
|
* @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.owner = owner;
|
||||||
sdrv->driver.bus = &spi_bus_type;
|
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);
|
return driver_register(&sdrv->driver);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__spi_register_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
|
* spi_split_transfers_maxsize - split spi transfers into multiple transfers
|
||||||
* when an individual transfer exceeds a
|
* when an individual transfer exceeds a
|
||||||
* certain size
|
* certain size
|
||||||
* @ctlr: the @spi_controller for this transfer
|
* @ctlr: the @spi_controller for this transfer
|
||||||
* @msg: the @spi_message to transform
|
* @msg: the @spi_message to transform
|
||||||
* @maxsize: the maximum when to apply this
|
* @maxsize: the maximum when to apply this
|
||||||
@@ -3369,7 +3378,8 @@ int spi_setup(struct spi_device *spi)
|
|||||||
if (status)
|
if (status)
|
||||||
return 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;
|
spi->max_speed_hz = spi->controller->max_speed_hz;
|
||||||
|
|
||||||
mutex_lock(&spi->controller->io_mutex);
|
mutex_lock(&spi->controller->io_mutex);
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ struct spi_device {
|
|||||||
#define SPI_MODE_1 (0|SPI_CPHA)
|
#define SPI_MODE_1 (0|SPI_CPHA)
|
||||||
#define SPI_MODE_2 (SPI_CPOL|0)
|
#define SPI_MODE_2 (SPI_CPOL|0)
|
||||||
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
|
#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_CS_HIGH 0x04 /* chipselect active high? */
|
||||||
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
|
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
|
||||||
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
|
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
|
||||||
|
|||||||
Reference in New Issue
Block a user