mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
spi: Fixes for v6.11
A small collection of fixes here, all driver specific and none of them too serious. For whatever reason runtime PM seems to have been causing a bunch of issues recently. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmbIYJUACgkQJNaLcl1U h9CPEAf+N0cSK3htQClbeFoKDqVna5FioME1vx9QVJM2q3aTd+WN6moHovbSEWUd dAB/2Ubo2gCntjdA7IB2DRhexe7V+woeRGI/50WxnIGg2jMQJINLrKXWmEjvIlfN dtqJMNtUDNY0deuJaIhJ/rJbICCg9foL0AluWe4scy2+Kz2lCD6iaEKSh5pc6ipB +DlBZT0rCNfcwPcJmjBv2YaOCYyKh7/pJA5qtFop23DzbubtD5YSgfX32BeDEc88 1TLJgaUI+AgKdKpM482ZnHs8BPDAY28UnnipRQSDEFCZERXUjHNixd0fnY64cDl6 SWMOf56ZpPH8cJ9KACHjkliBZwDy4g== =CyNt -----END PGP SIGNATURE----- Merge tag 'spi-fix-v6.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi fixes from Mark Brown: "A small collection of fixes here, all driver specific and none of them too serious. For whatever reason runtime PM seems to have been causing a bunch of issues recently" * tag 'spi-fix-v6.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi: pxa2xx: Move PM runtime handling to the glue drivers spi: pxa2xx: Do not override dev->platform_data on probe spi: spi-fsl-lpspi: limit PRESCALE bit in TCR register spi: spi-cadence-quadspi: Fix OSPI NOR failures during system resume spi: zynqmp-gqspi: Scale timeout by data size
This commit is contained in:
commit
c2a905a6d6
|
|
@ -2000,13 +2000,25 @@ static int cqspi_runtime_resume(struct device *dev)
|
|||
static int cqspi_suspend(struct device *dev)
|
||||
{
|
||||
struct cqspi_st *cqspi = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
return spi_controller_suspend(cqspi->host);
|
||||
ret = spi_controller_suspend(cqspi->host);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return pm_runtime_force_suspend(dev);
|
||||
}
|
||||
|
||||
static int cqspi_resume(struct device *dev)
|
||||
{
|
||||
struct cqspi_st *cqspi = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "pm_runtime_force_resume failed on resume\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return spi_controller_resume(cqspi->host);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@
|
|||
#define TCR_RXMSK BIT(19)
|
||||
#define TCR_TXMSK BIT(18)
|
||||
|
||||
struct fsl_lpspi_devtype_data {
|
||||
u8 prescale_max;
|
||||
};
|
||||
|
||||
struct lpspi_config {
|
||||
u8 bpw;
|
||||
u8 chip_select;
|
||||
|
|
@ -119,10 +123,25 @@ struct fsl_lpspi_data {
|
|||
bool usedma;
|
||||
struct completion dma_rx_completion;
|
||||
struct completion dma_tx_completion;
|
||||
|
||||
const struct fsl_lpspi_devtype_data *devtype_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* ERR051608 fixed or not:
|
||||
* https://www.nxp.com/docs/en/errata/i.MX93_1P87f.pdf
|
||||
*/
|
||||
static struct fsl_lpspi_devtype_data imx93_lpspi_devtype_data = {
|
||||
.prescale_max = 1,
|
||||
};
|
||||
|
||||
static struct fsl_lpspi_devtype_data imx7ulp_lpspi_devtype_data = {
|
||||
.prescale_max = 8,
|
||||
};
|
||||
|
||||
static const struct of_device_id fsl_lpspi_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx7ulp-spi", },
|
||||
{ .compatible = "fsl,imx7ulp-spi", .data = &imx7ulp_lpspi_devtype_data,},
|
||||
{ .compatible = "fsl,imx93-spi", .data = &imx93_lpspi_devtype_data,},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fsl_lpspi_dt_ids);
|
||||
|
|
@ -297,9 +316,11 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
|
|||
{
|
||||
struct lpspi_config config = fsl_lpspi->config;
|
||||
unsigned int perclk_rate, scldiv, div;
|
||||
u8 prescale_max;
|
||||
u8 prescale;
|
||||
|
||||
perclk_rate = clk_get_rate(fsl_lpspi->clk_per);
|
||||
prescale_max = fsl_lpspi->devtype_data->prescale_max;
|
||||
|
||||
if (!config.speed_hz) {
|
||||
dev_err(fsl_lpspi->dev,
|
||||
|
|
@ -315,7 +336,7 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
|
|||
|
||||
div = DIV_ROUND_UP(perclk_rate, config.speed_hz);
|
||||
|
||||
for (prescale = 0; prescale < 8; prescale++) {
|
||||
for (prescale = 0; prescale < prescale_max; prescale++) {
|
||||
scldiv = div / (1 << prescale) - 2;
|
||||
if (scldiv < 256) {
|
||||
fsl_lpspi->config.prescale = prescale;
|
||||
|
|
@ -822,6 +843,7 @@ static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi)
|
|||
|
||||
static int fsl_lpspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct fsl_lpspi_devtype_data *devtype_data;
|
||||
struct fsl_lpspi_data *fsl_lpspi;
|
||||
struct spi_controller *controller;
|
||||
struct resource *res;
|
||||
|
|
@ -830,6 +852,10 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
|
|||
u32 temp;
|
||||
bool is_target;
|
||||
|
||||
devtype_data = of_device_get_match_data(&pdev->dev);
|
||||
if (!devtype_data)
|
||||
return -ENODEV;
|
||||
|
||||
is_target = of_property_read_bool((&pdev->dev)->of_node, "spi-slave");
|
||||
if (is_target)
|
||||
controller = devm_spi_alloc_target(&pdev->dev,
|
||||
|
|
@ -848,6 +874,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
|
|||
fsl_lpspi->is_target = is_target;
|
||||
fsl_lpspi->is_only_cs1 = of_property_read_bool((&pdev->dev)->of_node,
|
||||
"fsl,spi-only-use-cs1-sel");
|
||||
fsl_lpspi->devtype_data = devtype_data;
|
||||
|
||||
init_completion(&fsl_lpspi->xfer_done);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sprintf.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
|
@ -297,11 +298,23 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
|
|||
return ret;
|
||||
ssp->irq = pci_irq_vector(dev, 0);
|
||||
|
||||
return pxa2xx_spi_probe(&dev->dev, ssp);
|
||||
ret = pxa2xx_spi_probe(&dev->dev, ssp, pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&dev->dev, 50);
|
||||
pm_runtime_use_autosuspend(&dev->dev);
|
||||
pm_runtime_put_autosuspend(&dev->dev);
|
||||
pm_runtime_allow(&dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
|
||||
{
|
||||
pm_runtime_forbid(&dev->dev);
|
||||
pm_runtime_get_noresume(&dev->dev);
|
||||
|
||||
pxa2xx_spi_remove(&dev->dev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
|
@ -63,7 +64,7 @@ static struct ssp_device *pxa2xx_spi_ssp_request(struct platform_device *pdev)
|
|||
|
||||
ssp = pxa_ssp_request(pdev->id, pdev->name);
|
||||
if (!ssp)
|
||||
return ssp;
|
||||
return NULL;
|
||||
|
||||
status = devm_add_action_or_reset(&pdev->dev, pxa2xx_spi_ssp_release, ssp);
|
||||
if (status)
|
||||
|
|
@ -142,14 +143,13 @@ static int pxa2xx_spi_platform_probe(struct platform_device *pdev)
|
|||
struct pxa2xx_spi_controller *platform_info;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ssp_device *ssp;
|
||||
int ret;
|
||||
|
||||
platform_info = dev_get_platdata(dev);
|
||||
if (!platform_info) {
|
||||
platform_info = pxa2xx_spi_init_pdata(pdev);
|
||||
if (IS_ERR(platform_info))
|
||||
return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n");
|
||||
|
||||
dev->platform_data = platform_info;
|
||||
}
|
||||
|
||||
ssp = pxa2xx_spi_ssp_request(pdev);
|
||||
|
|
@ -158,12 +158,28 @@ static int pxa2xx_spi_platform_probe(struct platform_device *pdev)
|
|||
if (!ssp)
|
||||
ssp = &platform_info->ssp;
|
||||
|
||||
return pxa2xx_spi_probe(dev, ssp);
|
||||
pm_runtime_set_autosuspend_delay(dev, 50);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = pxa2xx_spi_probe(dev, ssp, platform_info);
|
||||
if (ret)
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
pxa2xx_spi_remove(&pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
pxa2xx_spi_remove(dev);
|
||||
|
||||
pm_runtime_put_noidle(dev);
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
|
||||
|
|
|
|||
|
|
@ -1277,16 +1277,15 @@ static size_t pxa2xx_spi_max_dma_transfer_size(struct spi_device *spi)
|
|||
return MAX_DMA_LEN;
|
||||
}
|
||||
|
||||
int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp)
|
||||
int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
|
||||
struct pxa2xx_spi_controller *platform_info)
|
||||
{
|
||||
struct pxa2xx_spi_controller *platform_info;
|
||||
struct spi_controller *controller;
|
||||
struct driver_data *drv_data;
|
||||
const struct lpss_config *config;
|
||||
int status;
|
||||
u32 tmp;
|
||||
|
||||
platform_info = dev_get_platdata(dev);
|
||||
if (platform_info->is_target)
|
||||
controller = devm_spi_alloc_target(dev, sizeof(*drv_data));
|
||||
else
|
||||
|
|
@ -1450,24 +1449,16 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp)
|
|||
}
|
||||
}
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, 50);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
/* Register with the SPI framework */
|
||||
dev_set_drvdata(dev, drv_data);
|
||||
status = spi_register_controller(controller);
|
||||
if (status) {
|
||||
dev_err_probe(dev, status, "problem registering SPI controller\n");
|
||||
goto out_error_pm_runtime_enabled;
|
||||
goto out_error_clock_enabled;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
out_error_pm_runtime_enabled:
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
out_error_clock_enabled:
|
||||
clk_disable_unprepare(ssp->clk);
|
||||
|
||||
|
|
@ -1484,8 +1475,6 @@ void pxa2xx_spi_remove(struct device *dev)
|
|||
struct driver_data *drv_data = dev_get_drvdata(dev);
|
||||
struct ssp_device *ssp = drv_data->ssp;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
spi_unregister_controller(drv_data->controller);
|
||||
|
||||
/* Disable the SSP at the peripheral and SOC level */
|
||||
|
|
@ -1496,9 +1485,6 @@ void pxa2xx_spi_remove(struct device *dev)
|
|||
if (drv_data->controller_info->enable_dma)
|
||||
pxa2xx_spi_dma_release(drv_data);
|
||||
|
||||
pm_runtime_put_noidle(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
/* Release IRQ */
|
||||
free_irq(ssp->irq, drv_data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data);
|
|||
extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data);
|
||||
extern void pxa2xx_spi_dma_release(struct driver_data *drv_data);
|
||||
|
||||
int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp);
|
||||
int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
|
||||
struct pxa2xx_spi_controller *platform_info);
|
||||
void pxa2xx_spi_remove(struct device *dev);
|
||||
|
||||
extern const struct dev_pm_ops pxa2xx_spi_pm_ops;
|
||||
|
|
|
|||
|
|
@ -1033,6 +1033,18 @@ static int __maybe_unused zynqmp_runtime_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long zynqmp_qspi_timeout(struct zynqmp_qspi *xqspi, u8 bits,
|
||||
unsigned long bytes)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
/* Assume we are at most 2x slower than the nominal bus speed */
|
||||
timeout = mult_frac(bytes, 2 * 8 * MSEC_PER_SEC,
|
||||
bits * xqspi->speed_hz);
|
||||
/* And add 100 ms for scheduling delays */
|
||||
return msecs_to_jiffies(timeout + 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_qspi_exec_op() - Initiates the QSPI transfer
|
||||
* @mem: The SPI memory
|
||||
|
|
@ -1049,6 +1061,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
|
|||
{
|
||||
struct zynqmp_qspi *xqspi = spi_controller_get_devdata
|
||||
(mem->spi->controller);
|
||||
unsigned long timeout;
|
||||
int err = 0, i;
|
||||
u32 genfifoentry = 0;
|
||||
u16 opcode = op->cmd.opcode;
|
||||
|
|
@ -1077,8 +1090,10 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
|
|||
zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
|
||||
GQSPI_IER_GENFIFOEMPTY_MASK |
|
||||
GQSPI_IER_TXNOT_FULL_MASK);
|
||||
if (!wait_for_completion_timeout
|
||||
(&xqspi->data_completion, msecs_to_jiffies(1000))) {
|
||||
timeout = zynqmp_qspi_timeout(xqspi, op->cmd.buswidth,
|
||||
op->cmd.nbytes);
|
||||
if (!wait_for_completion_timeout(&xqspi->data_completion,
|
||||
timeout)) {
|
||||
err = -ETIMEDOUT;
|
||||
goto return_err;
|
||||
}
|
||||
|
|
@ -1104,8 +1119,10 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
|
|||
GQSPI_IER_TXEMPTY_MASK |
|
||||
GQSPI_IER_GENFIFOEMPTY_MASK |
|
||||
GQSPI_IER_TXNOT_FULL_MASK);
|
||||
if (!wait_for_completion_timeout
|
||||
(&xqspi->data_completion, msecs_to_jiffies(1000))) {
|
||||
timeout = zynqmp_qspi_timeout(xqspi, op->addr.buswidth,
|
||||
op->addr.nbytes);
|
||||
if (!wait_for_completion_timeout(&xqspi->data_completion,
|
||||
timeout)) {
|
||||
err = -ETIMEDOUT;
|
||||
goto return_err;
|
||||
}
|
||||
|
|
@ -1173,8 +1190,9 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
|
|||
GQSPI_IER_RXEMPTY_MASK);
|
||||
}
|
||||
}
|
||||
if (!wait_for_completion_timeout
|
||||
(&xqspi->data_completion, msecs_to_jiffies(1000)))
|
||||
timeout = zynqmp_qspi_timeout(xqspi, op->data.buswidth,
|
||||
op->data.nbytes);
|
||||
if (!wait_for_completion_timeout(&xqspi->data_completion, timeout))
|
||||
err = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user