spi: Fixes for v5.6
A selection of small fixes, mostly for drivers, that have arrived since the merge window. None of them are earth shattering in themselves but all useful for affected systems. -----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl5iiroTHGJyb29uaWVA a2VybmVsLm9yZwAKCRAk1otyXVSH0ALxB/0TAEys4X1IxDku7N4E9vivlTQP+Yy5 LmJ7Oc+z1aCWX3LrpMa3M9JInnY44iahjariaZgcQ9GXXTO4rEoOSTVL99fXzj0h wRS23p+h8GNFQ0s6Bzni8HSITz+vzCUJjYQe4i8iJIpQBRIErFSrqzB4uRGd7SPI PIgYeTSA3rFuVvdAgijRg3hPTW2rpn328G/k35JpUNo9OdZ/v6NDQl1Sbg/FedFu iY0feUaQ1FafHGkja/+OYN43bCraDo7Fo4COyF9cHGIJ8nBzMZJumhjgei26nviM OQ15zRewFpnLGlK8ffPykrnynOhqo3GF7JbFWvI5pga/G5XzzLY8mi19 =bFsu -----END PGP SIGNATURE----- Merge tag 'spi-fix-v5.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi fixes from Mark Brown: "A selection of small fixes, mostly for drivers, that have arrived since the merge window. None of them are earth shattering in themselves but all useful for affected systems" * tag 'spi-fix-v5.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi: spi_register_controller(): free bus id on error paths spi: bcm63xx-hsspi: Really keep pll clk enabled spi: atmel-quadspi: fix possible MMIO window size overrun spi/zynqmp: remove entry that causes a cs glitch spi: pxa2xx: Add CS control clock quirk spi: spidev: Fix CS polarity if GPIO descriptors are used spi: qup: call spi_qup_pm_resume_runtime before suspending spi: spi-omap2-mcspi: Support probe deferral for DMA channels spi: spi-omap2-mcspi: Handle DMA size restriction on AM65x
This commit is contained in:
Коммит
ae24a21bbd
|
@ -149,6 +149,7 @@ struct atmel_qspi {
|
|||
struct clk *qspick;
|
||||
struct platform_device *pdev;
|
||||
const struct atmel_qspi_caps *caps;
|
||||
resource_size_t mmap_size;
|
||||
u32 pending;
|
||||
u32 mr;
|
||||
u32 scr;
|
||||
|
@ -329,6 +330,14 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
|||
u32 sr, offset;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Check if the address exceeds the MMIO window size. An improvement
|
||||
* would be to add support for regular SPI mode and fall back to it
|
||||
* when the flash memories overrun the controller's memory space.
|
||||
*/
|
||||
if (op->addr.val + op->data.nbytes > aq->mmap_size)
|
||||
return -ENOTSUPP;
|
||||
|
||||
err = atmel_qspi_set_cfg(aq, op, &offset);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -480,6 +489,8 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
aq->mmap_size = resource_size(res);
|
||||
|
||||
/* Get the peripheral clock */
|
||||
aq->pclk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(aq->pclk))
|
||||
|
|
|
@ -366,7 +366,6 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
|
|||
goto out_disable_clk;
|
||||
|
||||
rate = clk_get_rate(pll_clk);
|
||||
clk_disable_unprepare(pll_clk);
|
||||
if (!rate) {
|
||||
ret = -EINVAL;
|
||||
goto out_disable_pll_clk;
|
||||
|
|
|
@ -130,6 +130,7 @@ struct omap2_mcspi {
|
|||
int fifo_depth;
|
||||
bool slave_aborted;
|
||||
unsigned int pin_dir:1;
|
||||
size_t max_xfer_len;
|
||||
};
|
||||
|
||||
struct omap2_mcspi_cs {
|
||||
|
@ -974,20 +975,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
|
|||
* Note that we currently allow DMA only if we get a channel
|
||||
* for both rx and tx. Otherwise we'll do PIO for both rx and tx.
|
||||
*/
|
||||
static int omap2_mcspi_request_dma(struct spi_device *spi)
|
||||
static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi,
|
||||
struct omap2_mcspi_dma *mcspi_dma)
|
||||
{
|
||||
struct spi_master *master = spi->master;
|
||||
struct omap2_mcspi *mcspi;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
int ret = 0;
|
||||
|
||||
mcspi = spi_master_get_devdata(master);
|
||||
mcspi_dma = mcspi->dma_channels + spi->chip_select;
|
||||
|
||||
init_completion(&mcspi_dma->dma_rx_completion);
|
||||
init_completion(&mcspi_dma->dma_tx_completion);
|
||||
|
||||
mcspi_dma->dma_rx = dma_request_chan(&master->dev,
|
||||
mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
|
||||
mcspi_dma->dma_rx_ch_name);
|
||||
if (IS_ERR(mcspi_dma->dma_rx)) {
|
||||
ret = PTR_ERR(mcspi_dma->dma_rx);
|
||||
|
@ -995,7 +988,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
|
|||
goto no_dma;
|
||||
}
|
||||
|
||||
mcspi_dma->dma_tx = dma_request_chan(&master->dev,
|
||||
mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,
|
||||
mcspi_dma->dma_tx_ch_name);
|
||||
if (IS_ERR(mcspi_dma->dma_tx)) {
|
||||
ret = PTR_ERR(mcspi_dma->dma_tx);
|
||||
|
@ -1004,20 +997,40 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
|
|||
mcspi_dma->dma_rx = NULL;
|
||||
}
|
||||
|
||||
init_completion(&mcspi_dma->dma_rx_completion);
|
||||
init_completion(&mcspi_dma->dma_tx_completion);
|
||||
|
||||
no_dma:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void omap2_mcspi_release_dma(struct spi_master *master)
|
||||
{
|
||||
struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < master->num_chipselect; i++) {
|
||||
mcspi_dma = &mcspi->dma_channels[i];
|
||||
|
||||
if (mcspi_dma->dma_rx) {
|
||||
dma_release_channel(mcspi_dma->dma_rx);
|
||||
mcspi_dma->dma_rx = NULL;
|
||||
}
|
||||
if (mcspi_dma->dma_tx) {
|
||||
dma_release_channel(mcspi_dma->dma_tx);
|
||||
mcspi_dma->dma_tx = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int omap2_mcspi_setup(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
|
||||
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
|
||||
if (!cs) {
|
||||
cs = kzalloc(sizeof *cs, GFP_KERNEL);
|
||||
if (!cs)
|
||||
|
@ -1042,13 +1055,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
|
|||
}
|
||||
}
|
||||
|
||||
if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
|
||||
ret = omap2_mcspi_request_dma(spi);
|
||||
if (ret)
|
||||
dev_warn(&spi->dev, "not using DMA for McSPI (%d)\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
ret = pm_runtime_get_sync(mcspi->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(mcspi->dev);
|
||||
|
@ -1065,12 +1071,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)
|
|||
|
||||
static void omap2_mcspi_cleanup(struct spi_device *spi)
|
||||
{
|
||||
struct omap2_mcspi *mcspi;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
struct omap2_mcspi_cs *cs;
|
||||
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
|
||||
if (spi->controller_state) {
|
||||
/* Unlink controller state from context save list */
|
||||
cs = spi->controller_state;
|
||||
|
@ -1079,19 +1081,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
|
|||
kfree(cs);
|
||||
}
|
||||
|
||||
if (spi->chip_select < spi->master->num_chipselect) {
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
|
||||
if (mcspi_dma->dma_rx) {
|
||||
dma_release_channel(mcspi_dma->dma_rx);
|
||||
mcspi_dma->dma_rx = NULL;
|
||||
}
|
||||
if (mcspi_dma->dma_tx) {
|
||||
dma_release_channel(mcspi_dma->dma_tx);
|
||||
mcspi_dma->dma_tx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (gpio_is_valid(spi->cs_gpio))
|
||||
gpio_free(spi->cs_gpio);
|
||||
}
|
||||
|
@ -1302,9 +1291,24 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,
|
|||
if (spi_controller_is_slave(master))
|
||||
return true;
|
||||
|
||||
master->dma_rx = mcspi_dma->dma_rx;
|
||||
master->dma_tx = mcspi_dma->dma_tx;
|
||||
|
||||
return (xfer->len >= DMA_MIN_BYTES);
|
||||
}
|
||||
|
||||
static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
|
||||
{
|
||||
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
|
||||
struct omap2_mcspi_dma *mcspi_dma =
|
||||
&mcspi->dma_channels[spi->chip_select];
|
||||
|
||||
if (mcspi->max_xfer_len && mcspi_dma->dma_rx)
|
||||
return mcspi->max_xfer_len;
|
||||
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
|
||||
{
|
||||
struct spi_master *master = mcspi->master;
|
||||
|
@ -1373,6 +1377,11 @@ static struct omap2_mcspi_platform_config omap4_pdata = {
|
|||
.regs_offset = OMAP4_MCSPI_REG_OFFSET,
|
||||
};
|
||||
|
||||
static struct omap2_mcspi_platform_config am654_pdata = {
|
||||
.regs_offset = OMAP4_MCSPI_REG_OFFSET,
|
||||
.max_xfer_len = SZ_4K - 1,
|
||||
};
|
||||
|
||||
static const struct of_device_id omap_mcspi_of_match[] = {
|
||||
{
|
||||
.compatible = "ti,omap2-mcspi",
|
||||
|
@ -1382,6 +1391,10 @@ static const struct of_device_id omap_mcspi_of_match[] = {
|
|||
.compatible = "ti,omap4-mcspi",
|
||||
.data = &omap4_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,am654-mcspi",
|
||||
.data = &am654_pdata,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
|
||||
|
@ -1439,6 +1452,10 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
|||
mcspi->pin_dir = pdata->pin_dir;
|
||||
}
|
||||
regs_offset = pdata->regs_offset;
|
||||
if (pdata->max_xfer_len) {
|
||||
mcspi->max_xfer_len = pdata->max_xfer_len;
|
||||
master->max_transfer_size = omap2_mcspi_max_xfer_size;
|
||||
}
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mcspi->base = devm_ioremap_resource(&pdev->dev, r);
|
||||
|
@ -1464,6 +1481,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
|||
for (i = 0; i < master->num_chipselect; i++) {
|
||||
sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
|
||||
sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
|
||||
|
||||
status = omap2_mcspi_request_dma(mcspi,
|
||||
&mcspi->dma_channels[i]);
|
||||
if (status == -EPROBE_DEFER)
|
||||
goto free_master;
|
||||
}
|
||||
|
||||
status = platform_get_irq(pdev, 0);
|
||||
|
@ -1501,6 +1523,7 @@ disable_pm:
|
|||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
free_master:
|
||||
omap2_mcspi_release_dma(master);
|
||||
spi_master_put(master);
|
||||
return status;
|
||||
}
|
||||
|
@ -1510,6 +1533,8 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
|
|||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
|
||||
|
||||
omap2_mcspi_release_dma(master);
|
||||
|
||||
pm_runtime_dont_use_autosuspend(mcspi->dev);
|
||||
pm_runtime_put_sync(mcspi->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
|
|
@ -70,6 +70,10 @@ MODULE_ALIAS("platform:pxa2xx-spi");
|
|||
#define LPSS_CAPS_CS_EN_SHIFT 9
|
||||
#define LPSS_CAPS_CS_EN_MASK (0xf << LPSS_CAPS_CS_EN_SHIFT)
|
||||
|
||||
#define LPSS_PRIV_CLOCK_GATE 0x38
|
||||
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3
|
||||
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3
|
||||
|
||||
struct lpss_config {
|
||||
/* LPSS offset from drv_data->ioaddr */
|
||||
unsigned offset;
|
||||
|
@ -86,6 +90,8 @@ struct lpss_config {
|
|||
unsigned cs_sel_shift;
|
||||
unsigned cs_sel_mask;
|
||||
unsigned cs_num;
|
||||
/* Quirks */
|
||||
unsigned cs_clk_stays_gated : 1;
|
||||
};
|
||||
|
||||
/* Keep these sorted with enum pxa_ssp_type */
|
||||
|
@ -156,6 +162,7 @@ static const struct lpss_config lpss_platforms[] = {
|
|||
.tx_threshold_hi = 56,
|
||||
.cs_sel_shift = 8,
|
||||
.cs_sel_mask = 3 << 8,
|
||||
.cs_clk_stays_gated = true,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -383,6 +390,22 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
|
|||
else
|
||||
value |= LPSS_CS_CONTROL_CS_HIGH;
|
||||
__lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
|
||||
if (config->cs_clk_stays_gated) {
|
||||
u32 clkgate;
|
||||
|
||||
/*
|
||||
* Changing CS alone when dynamic clock gating is on won't
|
||||
* actually flip CS at that time. This ruins SPI transfers
|
||||
* that specify delays, or have no data. Toggle the clock mode
|
||||
* to force on briefly to poke the CS pin to move.
|
||||
*/
|
||||
clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE);
|
||||
value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) |
|
||||
LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON;
|
||||
|
||||
__lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value);
|
||||
__lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate);
|
||||
}
|
||||
}
|
||||
|
||||
static void cs_assert(struct spi_device *spi)
|
||||
|
|
|
@ -1217,6 +1217,11 @@ static int spi_qup_suspend(struct device *device)
|
|||
struct spi_qup *controller = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
if (pm_runtime_suspended(device)) {
|
||||
ret = spi_qup_pm_resume_runtime(device);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = spi_master_suspend(master);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1225,10 +1230,8 @@ static int spi_qup_suspend(struct device *device)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!pm_runtime_suspended(device)) {
|
||||
clk_disable_unprepare(controller->cclk);
|
||||
clk_disable_unprepare(controller->iclk);
|
||||
}
|
||||
clk_disable_unprepare(controller->cclk);
|
||||
clk_disable_unprepare(controller->iclk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -401,9 +401,6 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
|
|||
|
||||
zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry);
|
||||
|
||||
/* Dummy generic FIFO entry */
|
||||
zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0);
|
||||
|
||||
/* Manually start the generic FIFO command */
|
||||
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
|
||||
zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
|
||||
|
|
|
@ -2639,7 +2639,7 @@ int spi_register_controller(struct spi_controller *ctlr)
|
|||
if (ctlr->use_gpio_descriptors) {
|
||||
status = spi_get_gpio_descs(ctlr);
|
||||
if (status)
|
||||
return status;
|
||||
goto free_bus_id;
|
||||
/*
|
||||
* A controller using GPIO descriptors always
|
||||
* supports SPI_CS_HIGH if need be.
|
||||
|
@ -2649,7 +2649,7 @@ int spi_register_controller(struct spi_controller *ctlr)
|
|||
/* Legacy code path for GPIOs from DT */
|
||||
status = of_spi_get_gpio_numbers(ctlr);
|
||||
if (status)
|
||||
return status;
|
||||
goto free_bus_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2657,17 +2657,14 @@ int spi_register_controller(struct spi_controller *ctlr)
|
|||
* Even if it's just one always-selected device, there must
|
||||
* be at least one chipselect.
|
||||
*/
|
||||
if (!ctlr->num_chipselect)
|
||||
return -EINVAL;
|
||||
if (!ctlr->num_chipselect) {
|
||||
status = -EINVAL;
|
||||
goto free_bus_id;
|
||||
}
|
||||
|
||||
status = device_add(&ctlr->dev);
|
||||
if (status < 0) {
|
||||
/* free bus id */
|
||||
mutex_lock(&board_lock);
|
||||
idr_remove(&spi_master_idr, ctlr->bus_num);
|
||||
mutex_unlock(&board_lock);
|
||||
goto done;
|
||||
}
|
||||
if (status < 0)
|
||||
goto free_bus_id;
|
||||
dev_dbg(dev, "registered %s %s\n",
|
||||
spi_controller_is_slave(ctlr) ? "slave" : "master",
|
||||
dev_name(&ctlr->dev));
|
||||
|
@ -2683,11 +2680,7 @@ int spi_register_controller(struct spi_controller *ctlr)
|
|||
status = spi_controller_initialize_queue(ctlr);
|
||||
if (status) {
|
||||
device_del(&ctlr->dev);
|
||||
/* free bus id */
|
||||
mutex_lock(&board_lock);
|
||||
idr_remove(&spi_master_idr, ctlr->bus_num);
|
||||
mutex_unlock(&board_lock);
|
||||
goto done;
|
||||
goto free_bus_id;
|
||||
}
|
||||
}
|
||||
/* add statistics */
|
||||
|
@ -2702,7 +2695,12 @@ int spi_register_controller(struct spi_controller *ctlr)
|
|||
/* Register devices from the device tree and ACPI */
|
||||
of_register_spi_devices(ctlr);
|
||||
acpi_register_spi_devices(ctlr);
|
||||
done:
|
||||
return status;
|
||||
|
||||
free_bus_id:
|
||||
mutex_lock(&board_lock);
|
||||
idr_remove(&spi_master_idr, ctlr->bus_num);
|
||||
mutex_unlock(&board_lock);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_register_controller);
|
||||
|
|
|
@ -396,6 +396,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
else
|
||||
retval = get_user(tmp, (u32 __user *)arg);
|
||||
if (retval == 0) {
|
||||
struct spi_controller *ctlr = spi->controller;
|
||||
u32 save = spi->mode;
|
||||
|
||||
if (tmp & ~SPI_MODE_MASK) {
|
||||
|
@ -403,6 +404,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
break;
|
||||
}
|
||||
|
||||
if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
|
||||
ctlr->cs_gpiods[spi->chip_select])
|
||||
tmp |= SPI_CS_HIGH;
|
||||
|
||||
tmp |= spi->mode & ~SPI_MODE_MASK;
|
||||
spi->mode = (u16)tmp;
|
||||
retval = spi_setup(spi);
|
||||
|
|
|
@ -11,6 +11,7 @@ struct omap2_mcspi_platform_config {
|
|||
unsigned short num_cs;
|
||||
unsigned int regs_offset;
|
||||
unsigned int pin_dir:1;
|
||||
size_t max_xfer_len;
|
||||
};
|
||||
|
||||
struct omap2_mcspi_device_config {
|
||||
|
|
Загрузка…
Ссылка в новой задаче