spi: Fixes for v4.19
Quite a few fixes for the Renesas drivers in here, plus a fix for the Tegra driver and some documentation fixes for the recently added spi-mem code. The Tegra fix is relatively large but fairly straightforward and mechanical, it runs on probe so it's been reasonably well covered in -next testing. -----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAluuOnETHGJyb29uaWVA a2VybmVsLm9yZwAKCRAk1otyXVSH0AhkB/9ahKdmxdxu0uuzzvS5qmdGD+98dTaV M+7+Bq6CJfBz0YTc9dxTiynbJot15vo5mKDZkDaJrgOoLCWWDGWa/DjRif2qS2o9 QxjWlBPzfOhKb81/HMJ+MaIHYDtAxvCu4iZExUZPxZzypX8Q9U3+9a/u0+JnRug2 guQ/4vYdxTGbR/taFsKLzf28DRqQb74KuDRAHaN44UYBxA1begy5gFOc7cEQTRu0 WACGM8jNL2eWWLXDNnQQTfb2t1v7LbbMorazyCn2e5ujamE4+DSaYWJF5axZiaQN ZcRVATw0SPiQlsQW/G014SSFJT0waybxWLOynWS9MSgjx84/GRYWvxRv =3ATM -----END PGP SIGNATURE----- Merge tag 'spi-fix-v4.19-rc5' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Mark writes: "spi: Fixes for v4.19 Quite a few fixes for the Renesas drivers in here, plus a fix for the Tegra driver and some documentation fixes for the recently added spi-mem code. The Tegra fix is relatively large but fairly straightforward and mechanical, it runs on probe so it's been reasonably well covered in -next testing." * tag 'spi-fix-v4.19-rc5' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi: spi-mem: Move the DMA-able constraint doc to the kerneldoc header spi: spi-mem: Add missing description for data.nbytes field spi: rspi: Fix interrupted DMA transfers spi: rspi: Fix invalid SPI use during system suspend spi: sh-msiof: Fix handling of write value for SISTR register spi: sh-msiof: Fix invalid SPI use during system suspend spi: gpio: Fix copy-and-paste error spi: tegra20-slink: explicitly enable/disable clock
This commit is contained in:
commit
2f19e7a7e6
|
@ -300,8 +300,8 @@ static int spi_gpio_request(struct device *dev,
|
||||||
*mflags |= SPI_MASTER_NO_RX;
|
*mflags |= SPI_MASTER_NO_RX;
|
||||||
|
|
||||||
spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
|
spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
|
||||||
if (IS_ERR(spi_gpio->mosi))
|
if (IS_ERR(spi_gpio->sck))
|
||||||
return PTR_ERR(spi_gpio->mosi);
|
return PTR_ERR(spi_gpio->sck);
|
||||||
|
|
||||||
for (i = 0; i < num_chipselects; i++) {
|
for (i = 0; i < num_chipselects; i++) {
|
||||||
spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs",
|
spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs",
|
||||||
|
|
|
@ -598,11 +598,13 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
|
||||||
|
|
||||||
ret = wait_event_interruptible_timeout(rspi->wait,
|
ret = wait_event_interruptible_timeout(rspi->wait,
|
||||||
rspi->dma_callbacked, HZ);
|
rspi->dma_callbacked, HZ);
|
||||||
if (ret > 0 && rspi->dma_callbacked)
|
if (ret > 0 && rspi->dma_callbacked) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
else if (!ret) {
|
} else {
|
||||||
dev_err(&rspi->master->dev, "DMA timeout\n");
|
if (!ret) {
|
||||||
ret = -ETIMEDOUT;
|
dev_err(&rspi->master->dev, "DMA timeout\n");
|
||||||
|
ret = -ETIMEDOUT;
|
||||||
|
}
|
||||||
if (tx)
|
if (tx)
|
||||||
dmaengine_terminate_all(rspi->master->dma_tx);
|
dmaengine_terminate_all(rspi->master->dma_tx);
|
||||||
if (rx)
|
if (rx)
|
||||||
|
@ -1350,12 +1352,36 @@ static const struct platform_device_id spi_driver_ids[] = {
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
|
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int rspi_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct rspi_data *rspi = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
return spi_master_suspend(rspi->master);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rspi_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct rspi_data *rspi = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
return spi_master_resume(rspi->master);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume);
|
||||||
|
#define DEV_PM_OPS &rspi_pm_ops
|
||||||
|
#else
|
||||||
|
#define DEV_PM_OPS NULL
|
||||||
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
static struct platform_driver rspi_driver = {
|
static struct platform_driver rspi_driver = {
|
||||||
.probe = rspi_probe,
|
.probe = rspi_probe,
|
||||||
.remove = rspi_remove,
|
.remove = rspi_remove,
|
||||||
.id_table = spi_driver_ids,
|
.id_table = spi_driver_ids,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "renesas_spi",
|
.name = "renesas_spi",
|
||||||
|
.pm = DEV_PM_OPS,
|
||||||
.of_match_table = of_match_ptr(rspi_of_match),
|
.of_match_table = of_match_ptr(rspi_of_match),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -397,7 +397,8 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
|
||||||
|
|
||||||
static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p)
|
static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p)
|
||||||
{
|
{
|
||||||
sh_msiof_write(p, STR, sh_msiof_read(p, STR));
|
sh_msiof_write(p, STR,
|
||||||
|
sh_msiof_read(p, STR) & ~(STR_TDREQ | STR_RDREQ));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p,
|
static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p,
|
||||||
|
@ -1426,12 +1427,37 @@ static const struct platform_device_id spi_driver_ids[] = {
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
|
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int sh_msiof_spi_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
return spi_master_suspend(p->master);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sh_msiof_spi_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
return spi_master_resume(p->master);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend,
|
||||||
|
sh_msiof_spi_resume);
|
||||||
|
#define DEV_PM_OPS &sh_msiof_spi_pm_ops
|
||||||
|
#else
|
||||||
|
#define DEV_PM_OPS NULL
|
||||||
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
static struct platform_driver sh_msiof_spi_drv = {
|
static struct platform_driver sh_msiof_spi_drv = {
|
||||||
.probe = sh_msiof_spi_probe,
|
.probe = sh_msiof_spi_probe,
|
||||||
.remove = sh_msiof_spi_remove,
|
.remove = sh_msiof_spi_remove,
|
||||||
.id_table = spi_driver_ids,
|
.id_table = spi_driver_ids,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "spi_sh_msiof",
|
.name = "spi_sh_msiof",
|
||||||
|
.pm = DEV_PM_OPS,
|
||||||
.of_match_table = of_match_ptr(sh_msiof_match),
|
.of_match_table = of_match_ptr(sh_msiof_match),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1063,6 +1063,24 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
||||||
goto exit_free_master;
|
goto exit_free_master;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* disabled clock may cause interrupt storm upon request */
|
||||||
|
tspi->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(tspi->clk)) {
|
||||||
|
ret = PTR_ERR(tspi->clk);
|
||||||
|
dev_err(&pdev->dev, "Can not get clock %d\n", ret);
|
||||||
|
goto exit_free_master;
|
||||||
|
}
|
||||||
|
ret = clk_prepare(tspi->clk);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "Clock prepare failed %d\n", ret);
|
||||||
|
goto exit_free_master;
|
||||||
|
}
|
||||||
|
ret = clk_enable(tspi->clk);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "Clock enable failed %d\n", ret);
|
||||||
|
goto exit_free_master;
|
||||||
|
}
|
||||||
|
|
||||||
spi_irq = platform_get_irq(pdev, 0);
|
spi_irq = platform_get_irq(pdev, 0);
|
||||||
tspi->irq = spi_irq;
|
tspi->irq = spi_irq;
|
||||||
ret = request_threaded_irq(tspi->irq, tegra_slink_isr,
|
ret = request_threaded_irq(tspi->irq, tegra_slink_isr,
|
||||||
|
@ -1071,14 +1089,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
|
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
|
||||||
tspi->irq);
|
tspi->irq);
|
||||||
goto exit_free_master;
|
goto exit_clk_disable;
|
||||||
}
|
|
||||||
|
|
||||||
tspi->clk = devm_clk_get(&pdev->dev, NULL);
|
|
||||||
if (IS_ERR(tspi->clk)) {
|
|
||||||
dev_err(&pdev->dev, "can not get clock\n");
|
|
||||||
ret = PTR_ERR(tspi->clk);
|
|
||||||
goto exit_free_irq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi");
|
tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi");
|
||||||
|
@ -1138,6 +1149,8 @@ exit_rx_dma_free:
|
||||||
tegra_slink_deinit_dma_param(tspi, true);
|
tegra_slink_deinit_dma_param(tspi, true);
|
||||||
exit_free_irq:
|
exit_free_irq:
|
||||||
free_irq(spi_irq, tspi);
|
free_irq(spi_irq, tspi);
|
||||||
|
exit_clk_disable:
|
||||||
|
clk_disable(tspi->clk);
|
||||||
exit_free_master:
|
exit_free_master:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1150,6 +1163,8 @@ static int tegra_slink_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
free_irq(tspi->irq, tspi);
|
free_irq(tspi->irq, tspi);
|
||||||
|
|
||||||
|
clk_disable(tspi->clk);
|
||||||
|
|
||||||
if (tspi->tx_dma_chan)
|
if (tspi->tx_dma_chan)
|
||||||
tegra_slink_deinit_dma_param(tspi, false);
|
tegra_slink_deinit_dma_param(tspi, false);
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,10 @@ enum spi_mem_data_dir {
|
||||||
* @dummy.buswidth: number of IO lanes used to transmit the dummy bytes
|
* @dummy.buswidth: number of IO lanes used to transmit the dummy bytes
|
||||||
* @data.buswidth: number of IO lanes used to send/receive the data
|
* @data.buswidth: number of IO lanes used to send/receive the data
|
||||||
* @data.dir: direction of the transfer
|
* @data.dir: direction of the transfer
|
||||||
* @data.buf.in: input buffer
|
* @data.nbytes: number of data bytes to send/receive. Can be zero if the
|
||||||
* @data.buf.out: output buffer
|
* operation does not involve transferring data
|
||||||
|
* @data.buf.in: input buffer (must be DMA-able)
|
||||||
|
* @data.buf.out: output buffer (must be DMA-able)
|
||||||
*/
|
*/
|
||||||
struct spi_mem_op {
|
struct spi_mem_op {
|
||||||
struct {
|
struct {
|
||||||
|
@ -105,7 +107,6 @@ struct spi_mem_op {
|
||||||
u8 buswidth;
|
u8 buswidth;
|
||||||
enum spi_mem_data_dir dir;
|
enum spi_mem_data_dir dir;
|
||||||
unsigned int nbytes;
|
unsigned int nbytes;
|
||||||
/* buf.{in,out} must be DMA-able. */
|
|
||||||
union {
|
union {
|
||||||
void *in;
|
void *in;
|
||||||
const void *out;
|
const void *out;
|
||||||
|
|
Loading…
Reference in New Issue