spi: Fixes for v5.15
A few small fixes for v5.15, mostly driver specific but there's one in the core which fixes a deadlock when adding devices on spi-mux that's triggered because spi-mux is a SPI device which is itself a SPI controller and so can instantiate devices when registered. We were using a global lock to protect against reusing chip selects but they're a per controller thing so moving the lock per controller resolves that. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmFpaEoACgkQJNaLcl1U h9Buawf/QpqpYKY+/ZiU3VG1iYYB3zE/KNsBVGPwDHIwLWX5NRxtGupERqoHgqaR e2Omo459vLdfShXSEuur5Co95q8nbgBxzbFYf/5/fPVmCQipWqAZ6AjJj60fpAP3 qVlXYvYrxUDfGywCkMQjLN3o+dcDxaGVG6+u1vvEnbdMt96lVbOKj2meaFpQ1jbj faY5GR/+5ZzhvzpxY3/FV6dlwvEdMRon0k6pFLis0YvxyOvQZffRdvAI4KxiFVP9 bAIPRGyn8tbppXlVJBBncRy/aSIxijauk3xGuPmRoy7CZaVZMwlfcPJ18NGixAVG B9f08ADBY7gAiEiJDCYX0u4ZaAOq+w== =U/5f -----END PGP SIGNATURE----- Merge tag 'spi-fix-v5.15-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi fixes from Mark Brown: "A few small fixes. Mostly driver specific but there's one in the core which fixes a deadlock when adding devices on spi-mux that's triggered because spi-mux is a SPI device which is itself a SPI controller and so can instantiate devices when registered. We were using a global lock to protect against reusing chip selects but they're a per controller thing so moving the lock per controller resolves that" * tag 'spi-fix-v5.15-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi-mux: Fix false-positive lockdep splats spi: Fix deadlock when adding SPI controllers on SPI buses spi: bcm-qspi: clear MSPI spifie interrupt during probe spi: spi-nxp-fspi: don't depend on a specific node name erratum workaround spi: mediatek: skip delays if they are 0 spi: atmel: Fix PDC transfer setup bug spi: spidev: Add SPI ID table spi: Use 'flash' node name instead of 'spi-flash' in example
This commit is contained in:
commit
985f6ab93f
|
@ -171,7 +171,7 @@ examples:
|
|||
cs-gpios = <&gpio0 13 0>,
|
||||
<&gpio0 14 0>;
|
||||
rx-sample-delay-ns = <3>;
|
||||
spi-flash@1 {
|
||||
flash@1 {
|
||||
compatible = "spi-nand";
|
||||
reg = <1>;
|
||||
rx-sample-delay-ns = <7>;
|
||||
|
|
|
@ -1301,7 +1301,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
|||
* DMA map early, for performance (empties dcache ASAP) and
|
||||
* better fault reporting.
|
||||
*/
|
||||
if ((!master->cur_msg_mapped)
|
||||
if ((!master->cur_msg->is_dma_mapped)
|
||||
&& as->use_pdc) {
|
||||
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
|
||||
return -ENOMEM;
|
||||
|
@ -1381,7 +1381,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
|||
}
|
||||
}
|
||||
|
||||
if (!master->cur_msg_mapped
|
||||
if (!master->cur_msg->is_dma_mapped
|
||||
&& as->use_pdc)
|
||||
atmel_spi_dma_unmap_xfer(master, xfer);
|
||||
|
||||
|
|
|
@ -1250,10 +1250,14 @@ static void bcm_qspi_hw_init(struct bcm_qspi *qspi)
|
|||
|
||||
static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
|
||||
{
|
||||
u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);
|
||||
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0);
|
||||
if (has_bspi(qspi))
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
|
||||
|
||||
/* clear interrupt */
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status & ~1);
|
||||
}
|
||||
|
||||
static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
|
||||
|
@ -1397,6 +1401,47 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
|||
if (!qspi->dev_ids)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Some SoCs integrate spi controller (e.g., its interrupt bits)
|
||||
* in specific ways
|
||||
*/
|
||||
if (soc_intc) {
|
||||
qspi->soc_intc = soc_intc;
|
||||
soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
|
||||
} else {
|
||||
qspi->soc_intc = NULL;
|
||||
}
|
||||
|
||||
if (qspi->clk) {
|
||||
ret = clk_prepare_enable(qspi->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to prepare clock\n");
|
||||
goto qspi_probe_err;
|
||||
}
|
||||
qspi->base_clk = clk_get_rate(qspi->clk);
|
||||
} else {
|
||||
qspi->base_clk = MSPI_BASE_FREQ;
|
||||
}
|
||||
|
||||
if (data->has_mspi_rev) {
|
||||
rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
|
||||
/* some older revs do not have a MSPI_REV register */
|
||||
if ((rev & 0xff) == 0xff)
|
||||
rev = 0;
|
||||
}
|
||||
|
||||
qspi->mspi_maj_rev = (rev >> 4) & 0xf;
|
||||
qspi->mspi_min_rev = rev & 0xf;
|
||||
qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;
|
||||
|
||||
qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
|
||||
|
||||
/*
|
||||
* On SW resets it is possible to have the mask still enabled
|
||||
* Need to disable the mask and clear the status while we init
|
||||
*/
|
||||
bcm_qspi_hw_uninit(qspi);
|
||||
|
||||
for (val = 0; val < num_irqs; val++) {
|
||||
irq = -1;
|
||||
name = qspi_irq_tab[val].irq_name;
|
||||
|
@ -1433,38 +1478,6 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
|||
goto qspi_probe_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some SoCs integrate spi controller (e.g., its interrupt bits)
|
||||
* in specific ways
|
||||
*/
|
||||
if (soc_intc) {
|
||||
qspi->soc_intc = soc_intc;
|
||||
soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
|
||||
} else {
|
||||
qspi->soc_intc = NULL;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(qspi->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to prepare clock\n");
|
||||
goto qspi_probe_err;
|
||||
}
|
||||
|
||||
qspi->base_clk = clk_get_rate(qspi->clk);
|
||||
|
||||
if (data->has_mspi_rev) {
|
||||
rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
|
||||
/* some older revs do not have a MSPI_REV register */
|
||||
if ((rev & 0xff) == 0xff)
|
||||
rev = 0;
|
||||
}
|
||||
|
||||
qspi->mspi_maj_rev = (rev >> 4) & 0xf;
|
||||
qspi->mspi_min_rev = rev & 0xf;
|
||||
qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;
|
||||
|
||||
qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
|
||||
|
||||
bcm_qspi_hw_init(qspi);
|
||||
init_completion(&qspi->mspi_done);
|
||||
init_completion(&qspi->bspi_done);
|
||||
|
|
|
@ -233,36 +233,44 @@ static int mtk_spi_set_hw_cs_timing(struct spi_device *spi)
|
|||
return delay;
|
||||
inactive = (delay * DIV_ROUND_UP(mdata->spi_clk_hz, 1000000)) / 1000;
|
||||
|
||||
setup = setup ? setup : 1;
|
||||
hold = hold ? hold : 1;
|
||||
inactive = inactive ? inactive : 1;
|
||||
|
||||
reg_val = readl(mdata->base + SPI_CFG0_REG);
|
||||
if (mdata->dev_comp->enhance_timing) {
|
||||
hold = min_t(u32, hold, 0x10000);
|
||||
setup = min_t(u32, setup, 0x10000);
|
||||
reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
|
||||
reg_val |= (((hold - 1) & 0xffff)
|
||||
<< SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
|
||||
reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
|
||||
reg_val |= (((setup - 1) & 0xffff)
|
||||
<< SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
|
||||
} else {
|
||||
hold = min_t(u32, hold, 0x100);
|
||||
setup = min_t(u32, setup, 0x100);
|
||||
reg_val &= ~(0xff << SPI_CFG0_CS_HOLD_OFFSET);
|
||||
reg_val |= (((hold - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
|
||||
reg_val &= ~(0xff << SPI_CFG0_CS_SETUP_OFFSET);
|
||||
reg_val |= (((setup - 1) & 0xff)
|
||||
<< SPI_CFG0_CS_SETUP_OFFSET);
|
||||
if (hold || setup) {
|
||||
reg_val = readl(mdata->base + SPI_CFG0_REG);
|
||||
if (mdata->dev_comp->enhance_timing) {
|
||||
if (hold) {
|
||||
hold = min_t(u32, hold, 0x10000);
|
||||
reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
|
||||
reg_val |= (((hold - 1) & 0xffff)
|
||||
<< SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
|
||||
}
|
||||
if (setup) {
|
||||
setup = min_t(u32, setup, 0x10000);
|
||||
reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
|
||||
reg_val |= (((setup - 1) & 0xffff)
|
||||
<< SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
|
||||
}
|
||||
} else {
|
||||
if (hold) {
|
||||
hold = min_t(u32, hold, 0x100);
|
||||
reg_val &= ~(0xff << SPI_CFG0_CS_HOLD_OFFSET);
|
||||
reg_val |= (((hold - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
|
||||
}
|
||||
if (setup) {
|
||||
setup = min_t(u32, setup, 0x100);
|
||||
reg_val &= ~(0xff << SPI_CFG0_CS_SETUP_OFFSET);
|
||||
reg_val |= (((setup - 1) & 0xff)
|
||||
<< SPI_CFG0_CS_SETUP_OFFSET);
|
||||
}
|
||||
}
|
||||
writel(reg_val, mdata->base + SPI_CFG0_REG);
|
||||
}
|
||||
writel(reg_val, mdata->base + SPI_CFG0_REG);
|
||||
|
||||
inactive = min_t(u32, inactive, 0x100);
|
||||
reg_val = readl(mdata->base + SPI_CFG1_REG);
|
||||
reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
|
||||
reg_val |= (((inactive - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
|
||||
writel(reg_val, mdata->base + SPI_CFG1_REG);
|
||||
if (inactive) {
|
||||
inactive = min_t(u32, inactive, 0x100);
|
||||
reg_val = readl(mdata->base + SPI_CFG1_REG);
|
||||
reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
|
||||
reg_val |= (((inactive - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
|
||||
writel(reg_val, mdata->base + SPI_CFG1_REG);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -137,6 +137,13 @@ static int spi_mux_probe(struct spi_device *spi)
|
|||
priv = spi_controller_get_devdata(ctlr);
|
||||
priv->spi = spi;
|
||||
|
||||
/*
|
||||
* Increase lockdep class as these lock are taken while the parent bus
|
||||
* already holds their instance's lock.
|
||||
*/
|
||||
lockdep_set_subclass(&ctlr->io_mutex, 1);
|
||||
lockdep_set_subclass(&ctlr->add_lock, 1);
|
||||
|
||||
priv->mux = devm_mux_control_get(&spi->dev, NULL);
|
||||
if (IS_ERR(priv->mux)) {
|
||||
ret = dev_err_probe(&spi->dev, PTR_ERR(priv->mux),
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -315,6 +316,7 @@
|
|||
#define NXP_FSPI_MIN_IOMAP SZ_4M
|
||||
|
||||
#define DCFG_RCWSR1 0x100
|
||||
#define SYS_PLL_RAT GENMASK(6, 2)
|
||||
|
||||
/* Access flash memory using IP bus only */
|
||||
#define FSPI_QUIRK_USE_IP_ONLY BIT(0)
|
||||
|
@ -926,9 +928,8 @@ static void erratum_err050568(struct nxp_fspi *f)
|
|||
{ .family = "QorIQ LS1028A" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
struct device_node *np;
|
||||
struct regmap *map;
|
||||
u32 val = 0, sysclk = 0;
|
||||
u32 val, sys_pll_ratio;
|
||||
int ret;
|
||||
|
||||
/* Check for LS1028A family */
|
||||
|
@ -937,7 +938,6 @@ static void erratum_err050568(struct nxp_fspi *f)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Compute system clock frequency multiplier ratio */
|
||||
map = syscon_regmap_lookup_by_compatible("fsl,ls1028a-dcfg");
|
||||
if (IS_ERR(map)) {
|
||||
dev_err(f->dev, "No syscon regmap\n");
|
||||
|
@ -948,23 +948,11 @@ static void erratum_err050568(struct nxp_fspi *f)
|
|||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
/* Strap bits 6:2 define SYS_PLL_RAT i.e frequency multiplier ratio */
|
||||
val = (val >> 2) & 0x1F;
|
||||
WARN(val == 0, "Strapping is zero: Cannot determine ratio");
|
||||
sys_pll_ratio = FIELD_GET(SYS_PLL_RAT, val);
|
||||
dev_dbg(f->dev, "val: 0x%08x, sys_pll_ratio: %d\n", val, sys_pll_ratio);
|
||||
|
||||
/* Compute system clock frequency */
|
||||
np = of_find_node_by_name(NULL, "clock-sysclk");
|
||||
if (!np)
|
||||
goto err;
|
||||
|
||||
if (of_property_read_u32(np, "clock-frequency", &sysclk))
|
||||
goto err;
|
||||
|
||||
sysclk = (sysclk * val) / 1000000; /* Convert sysclk to Mhz */
|
||||
dev_dbg(f->dev, "val: 0x%08x, sysclk: %dMhz\n", val, sysclk);
|
||||
|
||||
/* Use IP bus only if PLL is 300MHz */
|
||||
if (sysclk == 300)
|
||||
/* Use IP bus only if platform clock is 300MHz */
|
||||
if (sys_pll_ratio == 3)
|
||||
f->devtype_data->quirks |= FSPI_QUIRK_USE_IP_ONLY;
|
||||
|
||||
return;
|
||||
|
|
|
@ -1182,8 +1182,7 @@ static int tegra_slink_resume(struct device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tegra_slink_runtime_suspend(struct device *dev)
|
||||
static int __maybe_unused tegra_slink_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
||||
|
@ -1208,7 +1207,6 @@ static int tegra_slink_runtime_resume(struct device *dev)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct dev_pm_ops slink_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(tegra_slink_runtime_suspend,
|
||||
|
|
|
@ -478,12 +478,6 @@ static LIST_HEAD(spi_controller_list);
|
|||
*/
|
||||
static DEFINE_MUTEX(board_lock);
|
||||
|
||||
/*
|
||||
* Prevents addition of devices with same chip select and
|
||||
* addition of devices below an unregistering controller.
|
||||
*/
|
||||
static DEFINE_MUTEX(spi_add_lock);
|
||||
|
||||
/**
|
||||
* spi_alloc_device - Allocate a new SPI device
|
||||
* @ctlr: Controller to which device is connected
|
||||
|
@ -636,9 +630,9 @@ int spi_add_device(struct spi_device *spi)
|
|||
* chipselect **BEFORE** we call setup(), else we'll trash
|
||||
* its configuration. Lock against concurrent add() calls.
|
||||
*/
|
||||
mutex_lock(&spi_add_lock);
|
||||
mutex_lock(&ctlr->add_lock);
|
||||
status = __spi_add_device(spi);
|
||||
mutex_unlock(&spi_add_lock);
|
||||
mutex_unlock(&ctlr->add_lock);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_add_device);
|
||||
|
@ -658,7 +652,7 @@ static int spi_add_device_locked(struct spi_device *spi)
|
|||
/* Set the bus ID string */
|
||||
spi_dev_set_name(spi);
|
||||
|
||||
WARN_ON(!mutex_is_locked(&spi_add_lock));
|
||||
WARN_ON(!mutex_is_locked(&ctlr->add_lock));
|
||||
return __spi_add_device(spi);
|
||||
}
|
||||
|
||||
|
@ -2553,6 +2547,12 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
|
|||
return NULL;
|
||||
|
||||
device_initialize(&ctlr->dev);
|
||||
INIT_LIST_HEAD(&ctlr->queue);
|
||||
spin_lock_init(&ctlr->queue_lock);
|
||||
spin_lock_init(&ctlr->bus_lock_spinlock);
|
||||
mutex_init(&ctlr->bus_lock_mutex);
|
||||
mutex_init(&ctlr->io_mutex);
|
||||
mutex_init(&ctlr->add_lock);
|
||||
ctlr->bus_num = -1;
|
||||
ctlr->num_chipselect = 1;
|
||||
ctlr->slave = slave;
|
||||
|
@ -2825,11 +2825,6 @@ int spi_register_controller(struct spi_controller *ctlr)
|
|||
return id;
|
||||
ctlr->bus_num = id;
|
||||
}
|
||||
INIT_LIST_HEAD(&ctlr->queue);
|
||||
spin_lock_init(&ctlr->queue_lock);
|
||||
spin_lock_init(&ctlr->bus_lock_spinlock);
|
||||
mutex_init(&ctlr->bus_lock_mutex);
|
||||
mutex_init(&ctlr->io_mutex);
|
||||
ctlr->bus_lock_flag = 0;
|
||||
init_completion(&ctlr->xfer_completion);
|
||||
if (!ctlr->max_dma_len)
|
||||
|
@ -2966,7 +2961,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
|
|||
|
||||
/* Prevent addition of new devices, unregister existing ones */
|
||||
if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
|
||||
mutex_lock(&spi_add_lock);
|
||||
mutex_lock(&ctlr->add_lock);
|
||||
|
||||
device_for_each_child(&ctlr->dev, NULL, __unregister);
|
||||
|
||||
|
@ -2997,7 +2992,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
|
|||
mutex_unlock(&board_lock);
|
||||
|
||||
if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
|
||||
mutex_unlock(&spi_add_lock);
|
||||
mutex_unlock(&ctlr->add_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_unregister_controller);
|
||||
|
||||
|
|
|
@ -673,6 +673,19 @@ static const struct file_operations spidev_fops = {
|
|||
|
||||
static struct class *spidev_class;
|
||||
|
||||
static const struct spi_device_id spidev_spi_ids[] = {
|
||||
{ .name = "dh2228fv" },
|
||||
{ .name = "ltc2488" },
|
||||
{ .name = "sx1301" },
|
||||
{ .name = "bk4" },
|
||||
{ .name = "dhcom-board" },
|
||||
{ .name = "m53cpld" },
|
||||
{ .name = "spi-petra" },
|
||||
{ .name = "spi-authenta" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, spidev_spi_ids);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id spidev_dt_ids[] = {
|
||||
{ .compatible = "rohm,dh2228fv" },
|
||||
|
@ -818,6 +831,7 @@ static struct spi_driver spidev_spi_driver = {
|
|||
},
|
||||
.probe = spidev_probe,
|
||||
.remove = spidev_remove,
|
||||
.id_table = spidev_spi_ids,
|
||||
|
||||
/* NOTE: suspend/resume methods are not necessary here.
|
||||
* We don't do anything except pass the requests to/from
|
||||
|
|
|
@ -531,6 +531,9 @@ struct spi_controller {
|
|||
/* I/O mutex */
|
||||
struct mutex io_mutex;
|
||||
|
||||
/* Used to avoid adding the same CS twice */
|
||||
struct mutex add_lock;
|
||||
|
||||
/* lock and mutex for SPI bus locking */
|
||||
spinlock_t bus_lock_spinlock;
|
||||
struct mutex bus_lock_mutex;
|
||||
|
|
Loading…
Reference in New Issue