spi: Updates for v3.13
As well as the usual driver updates and cleanups there's a few improvements to the core here: - The start of some improvements to factor out more of the SPI message loop into the core. Right now this is just simplifying the code a bit but hopefully next time around we'll also have managed to roll out some noticable performance improvements which drivers can take advantage of. - Support for loading modules for ACPI enumerated SPI devices. - Managed registration for SPI controllers. - Helper for another common I/O pattern. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.15 (GNU/Linux) iQIcBAABAgAGBQJSd9ZZAAoJELSic+t+oim9/UkP/1sxozJ0bpnSLRTrI5B5b8Xt x13r/Hb9WaAxhZW4C/lgWUS1J/S1k4uuJHYFfS3+a3lqF5ulww+vkSuNuF8V0fCJ egFuO5iQJwA6Npw8IqSf+29geNX8mMXu881g42Znur+SLlkno5sw5Fl7izJ/gfzN SGNNp9sSi8j59XcUvSZZbOYYjji2n78RCmWD+gdaS7HilDXDYO2Jnh6N7BJ24/6/ lin+SzVRhSTHHH8Gz8UBfgKwDPDFB38Z/DIUSfz1bJP6EnkLKCpq1NqRJE/a4Wqs vWhWO6f7WFJID8qs/q6UNnBzGs8tIXpMMQtRgB4NcJYdG6V7Vl1qYYgEyKwdQE3L M7nTLNLppfqhUh4xg0O957ifpW7WYiA7grL5skF+yZNUMCeBkIsCLh847i+w113t qwqxw6sQHeZbIzDq3BXU7zKUXJ+XEERTFNBHC8lWqcIm/cD8xjhwuhMtebkc75GU PFCMeIIFd6BWbUPghXZnyTsHEITxFAyDJbEMj+KqtiscMKaubmrQ1qENMoIzpJof lBPjT78vFIY4A31v21l1FwD/E6BeI/+epZn6UHGfuoepeCaZjGfuGKBxSyY7KF/n okGwLKrRn84w6zN98XuoHcbPRtl35cHdom1VHHELs/7gPq6wW7/mn0bsOXkK5WDp txUO/nlCkAcXPo+hfVAM =emSz -----END PGP SIGNATURE----- Merge tag 'spi-v3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi updates from Mark Brown: "As well as the usual driver updates and cleanups there's a few improvements to the core here: - The start of some improvements to factor out more of the SPI message loop into the core. Right now this is just simplifying the code a bit but hopefully next time around we'll also have managed to roll out some noticable performance improvements which drivers can take advantage of. - Support for loading modules for ACPI enumerated SPI devices. - Managed registration for SPI controllers. - Helper for another common I/O pattern" * tag 'spi-v3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (116 commits) spi/hspi: add device tree support spi: atmel: fix return value check in atmel_spi_probe() spi: spi-imx: only enable the clocks when we start to transfer a message spi/s3c64xx: Fix doubled clock disable on suspend spi/s3c64xx: Do not ignore return value of spi_master_resume/suspend spi: spi-mxs: Use u32 instead of uint32_t spi: spi-mxs: Don't set clock for each xfer spi: spi-mxs: Clean up setup_transfer function spi: spi-mxs: Remove check of spi mode bits spi: spi-mxs: Fix race in setup method spi: spi-mxs: Remove bogus setting of ssp clk rate field spi: spi-mxs: Remove full duplex check, spi core already does it spi: spi-mxs: Fix chip select control bits in DMA mode spi: spi-mxs: Fix extra CS pulses and read mode in multi-transfer messages spi: spi-mxs: Change flag arguments in txrx functions to bit flags spi: spi-mxs: Always clear INGORE_CRC, to keep CS asserted spi: spi-mxs: Remove mxs_spi_enable and mxs_spi_disable spi: spi-mxs: Always set LOCK_CS spi/s3c64xx: Add missing pm_runtime_put on setup fail spi/s3c64xx: Add missing pm_runtime_set_active() call in probe() ...
This commit is contained in:
commit
f095ca6b31
7
Documentation/devicetree/bindings/spi/sh-hspi.txt
Normal file
7
Documentation/devicetree/bindings/spi/sh-hspi.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Renesas HSPI.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : "renesas,hspi"
|
||||||
|
- reg : Offset and length of the register set for the device
|
||||||
|
- interrupts : interrupt line used by HSPI
|
||||||
|
|
@ -303,3 +303,6 @@ PHY
|
|||||||
|
|
||||||
SLAVE DMA ENGINE
|
SLAVE DMA ENGINE
|
||||||
devm_acpi_dma_controller_register()
|
devm_acpi_dma_controller_register()
|
||||||
|
|
||||||
|
SPI
|
||||||
|
devm_spi_register_master()
|
||||||
|
@ -42,13 +42,8 @@ static const u8 adt7310_reg_table[] = {
|
|||||||
static int adt7310_spi_read_word(struct device *dev, u8 reg)
|
static int adt7310_spi_read_word(struct device *dev, u8 reg)
|
||||||
{
|
{
|
||||||
struct spi_device *spi = to_spi_device(dev);
|
struct spi_device *spi = to_spi_device(dev);
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = spi_w8r16(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
|
return spi_w8r16be(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return be16_to_cpu((__force __be16)ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
|
static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
|
||||||
|
@ -264,6 +264,7 @@ config SPI_FSL_SPI
|
|||||||
config SPI_FSL_DSPI
|
config SPI_FSL_DSPI
|
||||||
tristate "Freescale DSPI controller"
|
tristate "Freescale DSPI controller"
|
||||||
select SPI_BITBANG
|
select SPI_BITBANG
|
||||||
|
depends on SOC_VF610 || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This enables support for the Freescale DSPI controller in master
|
This enables support for the Freescale DSPI controller in master
|
||||||
mode. VF610 platform uses the controller.
|
mode. VF610 platform uses the controller.
|
||||||
@ -369,7 +370,7 @@ config SPI_PXA2XX_PCI
|
|||||||
|
|
||||||
config SPI_RSPI
|
config SPI_RSPI
|
||||||
tristate "Renesas RSPI controller"
|
tristate "Renesas RSPI controller"
|
||||||
depends on SUPERH && SH_DMAE_BASE
|
depends on (SUPERH || ARCH_SHMOBILE) && SH_DMAE_BASE
|
||||||
help
|
help
|
||||||
SPI driver for Renesas RSPI blocks.
|
SPI driver for Renesas RSPI blocks.
|
||||||
|
|
||||||
@ -393,7 +394,7 @@ config SPI_S3C24XX_FIQ
|
|||||||
|
|
||||||
config SPI_S3C64XX
|
config SPI_S3C64XX
|
||||||
tristate "Samsung S3C64XX series type SPI"
|
tristate "Samsung S3C64XX series type SPI"
|
||||||
depends on (ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS)
|
depends on PLAT_SAMSUNG
|
||||||
select S3C64XX_DMA if ARCH_S3C64XX
|
select S3C64XX_DMA if ARCH_S3C64XX
|
||||||
help
|
help
|
||||||
SPI driver for Samsung S3C64XX and newer SoCs.
|
SPI driver for Samsung S3C64XX and newer SoCs.
|
||||||
|
@ -219,7 +219,7 @@ static int altera_spi_probe(struct platform_device *pdev)
|
|||||||
platform_set_drvdata(pdev, hw);
|
platform_set_drvdata(pdev, hw);
|
||||||
|
|
||||||
/* setup the state for the bitbang driver */
|
/* setup the state for the bitbang driver */
|
||||||
hw->bitbang.master = spi_master_get(master);
|
hw->bitbang.master = master;
|
||||||
if (!hw->bitbang.master)
|
if (!hw->bitbang.master)
|
||||||
return err;
|
return err;
|
||||||
hw->bitbang.chipselect = altera_spi_chipsel;
|
hw->bitbang.chipselect = altera_spi_chipsel;
|
||||||
|
@ -231,7 +231,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
|
|||||||
master->num_chipselect = pdata->num_chipselect;
|
master->num_chipselect = pdata->num_chipselect;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp->bitbang.master = spi_master_get(master);
|
sp->bitbang.master = master;
|
||||||
sp->bitbang.chipselect = ath79_spi_chipselect;
|
sp->bitbang.chipselect = ath79_spi_chipselect;
|
||||||
sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
|
sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
|
||||||
sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
|
sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
|
||||||
|
@ -170,18 +170,18 @@
|
|||||||
/* Bit manipulation macros */
|
/* Bit manipulation macros */
|
||||||
#define SPI_BIT(name) \
|
#define SPI_BIT(name) \
|
||||||
(1 << SPI_##name##_OFFSET)
|
(1 << SPI_##name##_OFFSET)
|
||||||
#define SPI_BF(name,value) \
|
#define SPI_BF(name, value) \
|
||||||
(((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET)
|
(((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET)
|
||||||
#define SPI_BFEXT(name,value) \
|
#define SPI_BFEXT(name, value) \
|
||||||
(((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1))
|
(((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1))
|
||||||
#define SPI_BFINS(name,value,old) \
|
#define SPI_BFINS(name, value, old) \
|
||||||
( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \
|
(((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \
|
||||||
| SPI_BF(name,value))
|
| SPI_BF(name, value))
|
||||||
|
|
||||||
/* Register access macros */
|
/* Register access macros */
|
||||||
#define spi_readl(port,reg) \
|
#define spi_readl(port, reg) \
|
||||||
__raw_readl((port)->regs + SPI_##reg)
|
__raw_readl((port)->regs + SPI_##reg)
|
||||||
#define spi_writel(port,reg,value) \
|
#define spi_writel(port, reg, value) \
|
||||||
__raw_writel((value), (port)->regs + SPI_##reg)
|
__raw_writel((value), (port)->regs + SPI_##reg)
|
||||||
|
|
||||||
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
|
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
|
||||||
@ -1401,8 +1401,8 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
|
|||||||
asd = spi->controller_state;
|
asd = spi->controller_state;
|
||||||
bits = (asd->csr >> 4) & 0xf;
|
bits = (asd->csr >> 4) & 0xf;
|
||||||
if (bits != xfer->bits_per_word - 8) {
|
if (bits != xfer->bits_per_word - 8) {
|
||||||
dev_dbg(&spi->dev, "you can't yet change "
|
dev_dbg(&spi->dev,
|
||||||
"bits_per_word in transfers\n");
|
"you can't yet change bits_per_word in transfers\n");
|
||||||
return -ENOPROTOOPT;
|
return -ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1516,7 +1516,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* setup spi core then atmel-specific driver state */
|
/* setup spi core then atmel-specific driver state */
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
master = spi_alloc_master(&pdev->dev, sizeof *as);
|
master = spi_alloc_master(&pdev->dev, sizeof(*as));
|
||||||
if (!master)
|
if (!master)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
@ -1546,9 +1546,11 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
|||||||
INIT_LIST_HEAD(&as->queue);
|
INIT_LIST_HEAD(&as->queue);
|
||||||
|
|
||||||
as->pdev = pdev;
|
as->pdev = pdev;
|
||||||
as->regs = ioremap(regs->start, resource_size(regs));
|
as->regs = devm_ioremap_resource(&pdev->dev, regs);
|
||||||
if (!as->regs)
|
if (IS_ERR(as->regs)) {
|
||||||
|
ret = PTR_ERR(as->regs);
|
||||||
goto out_free_buffer;
|
goto out_free_buffer;
|
||||||
|
}
|
||||||
as->phybase = regs->start;
|
as->phybase = regs->start;
|
||||||
as->irq = irq;
|
as->irq = irq;
|
||||||
as->clk = clk;
|
as->clk = clk;
|
||||||
@ -1617,7 +1619,6 @@ out_free_dma:
|
|||||||
out_free_irq:
|
out_free_irq:
|
||||||
free_irq(irq, master);
|
free_irq(irq, master);
|
||||||
out_unmap_regs:
|
out_unmap_regs:
|
||||||
iounmap(as->regs);
|
|
||||||
out_free_buffer:
|
out_free_buffer:
|
||||||
if (!as->use_pdc)
|
if (!as->use_pdc)
|
||||||
tasklet_kill(&as->tasklet);
|
tasklet_kill(&as->tasklet);
|
||||||
@ -1669,36 +1670,36 @@ static int atmel_spi_remove(struct platform_device *pdev)
|
|||||||
clk_disable_unprepare(as->clk);
|
clk_disable_unprepare(as->clk);
|
||||||
clk_put(as->clk);
|
clk_put(as->clk);
|
||||||
free_irq(as->irq, master);
|
free_irq(as->irq, master);
|
||||||
iounmap(as->regs);
|
|
||||||
|
|
||||||
spi_unregister_master(master);
|
spi_unregister_master(master);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int atmel_spi_suspend(struct device *dev)
|
||||||
static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|
||||||
{
|
{
|
||||||
struct spi_master *master = platform_get_drvdata(pdev);
|
struct spi_master *master = dev_get_drvdata(dev);
|
||||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||||
|
|
||||||
clk_disable_unprepare(as->clk);
|
clk_disable_unprepare(as->clk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int atmel_spi_resume(struct platform_device *pdev)
|
static int atmel_spi_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct spi_master *master = platform_get_drvdata(pdev);
|
struct spi_master *master = dev_get_drvdata(dev);
|
||||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||||
|
|
||||||
return clk_prepare_enable(as->clk);
|
clk_prepare_enable(as->clk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(atmel_spi_pm_ops, atmel_spi_suspend, atmel_spi_resume);
|
||||||
|
|
||||||
|
#define ATMEL_SPI_PM_OPS (&atmel_spi_pm_ops)
|
||||||
#else
|
#else
|
||||||
#define atmel_spi_suspend NULL
|
#define ATMEL_SPI_PM_OPS NULL
|
||||||
#define atmel_spi_resume NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_OF)
|
#if defined(CONFIG_OF)
|
||||||
@ -1714,10 +1715,9 @@ static struct platform_driver atmel_spi_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = "atmel_spi",
|
.name = "atmel_spi",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.pm = ATMEL_SPI_PM_OPS,
|
||||||
.of_match_table = of_match_ptr(atmel_spi_dt_ids),
|
.of_match_table = of_match_ptr(atmel_spi_dt_ids),
|
||||||
},
|
},
|
||||||
.suspend = atmel_spi_suspend,
|
|
||||||
.resume = atmel_spi_resume,
|
|
||||||
.probe = atmel_spi_probe,
|
.probe = atmel_spi_probe,
|
||||||
.remove = atmel_spi_remove,
|
.remove = atmel_spi_remove,
|
||||||
};
|
};
|
||||||
|
@ -775,7 +775,7 @@ static int au1550_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
hw = spi_master_get_devdata(master);
|
hw = spi_master_get_devdata(master);
|
||||||
|
|
||||||
hw->master = spi_master_get(master);
|
hw->master = master;
|
||||||
hw->pdata = dev_get_platdata(&pdev->dev);
|
hw->pdata = dev_get_platdata(&pdev->dev);
|
||||||
hw->dev = &pdev->dev;
|
hw->dev = &pdev->dev;
|
||||||
|
|
||||||
@ -985,6 +985,7 @@ static int au1550_spi_remove(struct platform_device *pdev)
|
|||||||
MODULE_ALIAS("platform:au1550-spi");
|
MODULE_ALIAS("platform:au1550-spi");
|
||||||
|
|
||||||
static struct platform_driver au1550_spi_drv = {
|
static struct platform_driver au1550_spi_drv = {
|
||||||
|
.probe = au1550_spi_probe,
|
||||||
.remove = au1550_spi_remove,
|
.remove = au1550_spi_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "au1550-spi",
|
.name = "au1550-spi",
|
||||||
@ -1004,7 +1005,7 @@ static int __init au1550_spi_init(void)
|
|||||||
printk(KERN_ERR "au1550-spi: cannot add memory"
|
printk(KERN_ERR "au1550-spi: cannot add memory"
|
||||||
"dbdma device\n");
|
"dbdma device\n");
|
||||||
}
|
}
|
||||||
return platform_driver_probe(&au1550_spi_drv, au1550_spi_probe);
|
return platform_driver_register(&au1550_spi_drv);
|
||||||
}
|
}
|
||||||
module_init(au1550_spi_init);
|
module_init(au1550_spi_init);
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
|
|||||||
bcm2835_wr(bs, BCM2835_SPI_CS,
|
bcm2835_wr(bs, BCM2835_SPI_CS,
|
||||||
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
|
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
|
||||||
|
|
||||||
err = spi_register_master(master);
|
err = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
|
dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
|
||||||
goto out_free_irq;
|
goto out_free_irq;
|
||||||
@ -381,14 +381,12 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
|
|||||||
struct bcm2835_spi *bs = spi_master_get_devdata(master);
|
struct bcm2835_spi *bs = spi_master_get_devdata(master);
|
||||||
|
|
||||||
free_irq(bs->irq, master);
|
free_irq(bs->irq, master);
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
/* Clear FIFOs, and disable the HW block */
|
/* Clear FIFOs, and disable the HW block */
|
||||||
bcm2835_wr(bs, BCM2835_SPI_CS,
|
bcm2835_wr(bs, BCM2835_SPI_CS,
|
||||||
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
|
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
|
||||||
|
|
||||||
clk_disable_unprepare(bs->clk);
|
clk_disable_unprepare(bs->clk);
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -412,7 +412,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
|||||||
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
|
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
|
||||||
|
|
||||||
/* register and we are done */
|
/* register and we are done */
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(dev, master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "spi register failed\n");
|
dev_err(dev, "spi register failed\n");
|
||||||
goto out_clk_disable;
|
goto out_clk_disable;
|
||||||
@ -438,8 +438,6 @@ static int bcm63xx_spi_remove(struct platform_device *pdev)
|
|||||||
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
|
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
|
||||||
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
|
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
/* reset spi block */
|
/* reset spi block */
|
||||||
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
|
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
|
||||||
|
|
||||||
@ -447,8 +445,6 @@ static int bcm63xx_spi_remove(struct platform_device *pdev)
|
|||||||
clk_disable_unprepare(bs->clk);
|
clk_disable_unprepare(bs->clk);
|
||||||
clk_put(bs->clk);
|
clk_put(bs->clk);
|
||||||
|
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,7 +592,7 @@ bfin_sport_spi_setup(struct spi_device *spi)
|
|||||||
*/
|
*/
|
||||||
if (chip_info->ctl_reg || chip_info->enable_dma) {
|
if (chip_info->ctl_reg || chip_info->enable_dma) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
dev_err(&spi->dev, "don't set ctl_reg/enable_dma fields");
|
dev_err(&spi->dev, "don't set ctl_reg/enable_dma fields\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
chip->cs_chg_udelay = chip_info->cs_chg_udelay;
|
chip->cs_chg_udelay = chip_info->cs_chg_udelay;
|
||||||
@ -879,11 +879,10 @@ static int bfin_sport_spi_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM_SLEEP
|
||||||
static int
|
static int bfin_sport_spi_suspend(struct device *dev)
|
||||||
bfin_sport_spi_suspend(struct platform_device *pdev, pm_message_t state)
|
|
||||||
{
|
{
|
||||||
struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev);
|
struct bfin_sport_spi_master_data *drv_data = dev_get_drvdata(dev);
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = bfin_sport_spi_stop_queue(drv_data);
|
status = bfin_sport_spi_stop_queue(drv_data);
|
||||||
@ -896,10 +895,9 @@ bfin_sport_spi_suspend(struct platform_device *pdev, pm_message_t state)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int bfin_sport_spi_resume(struct device *dev)
|
||||||
bfin_sport_spi_resume(struct platform_device *pdev)
|
|
||||||
{
|
{
|
||||||
struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev);
|
struct bfin_sport_spi_master_data *drv_data = dev_get_drvdata(dev);
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* Enable the SPI interface */
|
/* Enable the SPI interface */
|
||||||
@ -912,19 +910,22 @@ bfin_sport_spi_resume(struct platform_device *pdev)
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(bfin_sport_spi_pm_ops, bfin_sport_spi_suspend,
|
||||||
|
bfin_sport_spi_resume);
|
||||||
|
|
||||||
|
#define BFIN_SPORT_SPI_PM_OPS (&bfin_sport_spi_pm_ops)
|
||||||
#else
|
#else
|
||||||
# define bfin_sport_spi_suspend NULL
|
#define BFIN_SPORT_SPI_PM_OPS NULL
|
||||||
# define bfin_sport_spi_resume NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct platform_driver bfin_sport_spi_driver = {
|
static struct platform_driver bfin_sport_spi_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = DRV_NAME,
|
.name = DRV_NAME,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.pm = BFIN_SPORT_SPI_PM_OPS,
|
||||||
},
|
},
|
||||||
.probe = bfin_sport_spi_probe,
|
.probe = bfin_sport_spi_probe,
|
||||||
.remove = bfin_sport_spi_remove,
|
.remove = bfin_sport_spi_remove,
|
||||||
.suspend = bfin_sport_spi_suspend,
|
|
||||||
.resume = bfin_sport_spi_resume,
|
|
||||||
};
|
};
|
||||||
module_platform_driver(bfin_sport_spi_driver);
|
module_platform_driver(bfin_sport_spi_driver);
|
||||||
|
@ -867,7 +867,7 @@ static int bfin_spi_probe(struct platform_device *pdev)
|
|||||||
tasklet_init(&drv_data->pump_transfers,
|
tasklet_init(&drv_data->pump_transfers,
|
||||||
bfin_spi_pump_transfers, (unsigned long)drv_data);
|
bfin_spi_pump_transfers, (unsigned long)drv_data);
|
||||||
/* register with the SPI framework */
|
/* register with the SPI framework */
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(dev, master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "can not register spi master\n");
|
dev_err(dev, "can not register spi master\n");
|
||||||
goto err_free_peripheral;
|
goto err_free_peripheral;
|
||||||
@ -898,7 +898,6 @@ static int bfin_spi_remove(struct platform_device *pdev)
|
|||||||
free_dma(drv_data->rx_dma);
|
free_dma(drv_data->rx_dma);
|
||||||
free_dma(drv_data->tx_dma);
|
free_dma(drv_data->tx_dma);
|
||||||
|
|
||||||
spi_unregister_master(drv_data->master);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,7 +524,7 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
|
|||||||
timeout = jiffies + HZ;
|
timeout = jiffies + HZ;
|
||||||
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF))
|
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF))
|
||||||
if (!time_before(jiffies, timeout)) {
|
if (!time_before(jiffies, timeout)) {
|
||||||
dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF");
|
dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF\n");
|
||||||
break;
|
break;
|
||||||
} else
|
} else
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
@ -913,8 +913,9 @@ static void bfin_spi_pump_messages(struct work_struct *work)
|
|||||||
drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
|
drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
|
||||||
struct spi_transfer, transfer_list);
|
struct spi_transfer, transfer_list);
|
||||||
|
|
||||||
dev_dbg(&drv_data->pdev->dev, "got a message to pump, "
|
dev_dbg(&drv_data->pdev->dev,
|
||||||
"state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
|
"got a message to pump, state is set to: baud "
|
||||||
|
"%d, flag 0x%x, ctl 0x%x\n",
|
||||||
drv_data->cur_chip->baud, drv_data->cur_chip->flag,
|
drv_data->cur_chip->baud, drv_data->cur_chip->flag,
|
||||||
drv_data->cur_chip->ctl_reg);
|
drv_data->cur_chip->ctl_reg);
|
||||||
|
|
||||||
@ -1013,8 +1014,8 @@ static int bfin_spi_setup(struct spi_device *spi)
|
|||||||
* but let's assume (for now) they do.
|
* but let's assume (for now) they do.
|
||||||
*/
|
*/
|
||||||
if (chip_info->ctl_reg & ~bfin_ctl_reg) {
|
if (chip_info->ctl_reg & ~bfin_ctl_reg) {
|
||||||
dev_err(&spi->dev, "do not set bits in ctl_reg "
|
dev_err(&spi->dev,
|
||||||
"that the SPI framework manages\n");
|
"do not set bits in ctl_reg that the SPI framework manages\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
chip->enable_dma = chip_info->enable_dma != 0
|
chip->enable_dma = chip_info->enable_dma != 0
|
||||||
@ -1050,17 +1051,17 @@ static int bfin_spi_setup(struct spi_device *spi)
|
|||||||
chip->chip_select_num = spi->chip_select;
|
chip->chip_select_num = spi->chip_select;
|
||||||
if (chip->chip_select_num < MAX_CTRL_CS) {
|
if (chip->chip_select_num < MAX_CTRL_CS) {
|
||||||
if (!(spi->mode & SPI_CPHA))
|
if (!(spi->mode & SPI_CPHA))
|
||||||
dev_warn(&spi->dev, "Warning: SPI CPHA not set:"
|
dev_warn(&spi->dev,
|
||||||
" Slave Select not under software control!\n"
|
"Warning: SPI CPHA not set: Slave Select not under software control!\n"
|
||||||
" See Documentation/blackfin/bfin-spi-notes.txt");
|
"See Documentation/blackfin/bfin-spi-notes.txt\n");
|
||||||
|
|
||||||
chip->flag = (1 << spi->chip_select) << 8;
|
chip->flag = (1 << spi->chip_select) << 8;
|
||||||
} else
|
} else
|
||||||
chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS;
|
chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS;
|
||||||
|
|
||||||
if (chip->enable_dma && chip->pio_interrupt) {
|
if (chip->enable_dma && chip->pio_interrupt) {
|
||||||
dev_err(&spi->dev, "enable_dma is set, "
|
dev_err(&spi->dev,
|
||||||
"do not set pio_interrupt\n");
|
"enable_dma is set, do not set pio_interrupt\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -1410,10 +1411,10 @@ static int bfin_spi_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM_SLEEP
|
||||||
static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state)
|
static int bfin_spi_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
|
struct bfin_spi_master_data *drv_data = dev_get_drvdata(dev);
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
status = bfin_spi_stop_queue(drv_data);
|
status = bfin_spi_stop_queue(drv_data);
|
||||||
@ -1432,9 +1433,9 @@ static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bfin_spi_resume(struct platform_device *pdev)
|
static int bfin_spi_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
|
struct bfin_spi_master_data *drv_data = dev_get_drvdata(dev);
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
bfin_write(&drv_data->regs->ctl, drv_data->ctrl_reg);
|
bfin_write(&drv_data->regs->ctl, drv_data->ctrl_reg);
|
||||||
@ -1443,31 +1444,34 @@ static int bfin_spi_resume(struct platform_device *pdev)
|
|||||||
/* Start the queue running */
|
/* Start the queue running */
|
||||||
status = bfin_spi_start_queue(drv_data);
|
status = bfin_spi_start_queue(drv_data);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
|
dev_err(dev, "problem starting queue (%d)\n", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(bfin_spi_pm_ops, bfin_spi_suspend, bfin_spi_resume);
|
||||||
|
|
||||||
|
#define BFIN_SPI_PM_OPS (&bfin_spi_pm_ops)
|
||||||
#else
|
#else
|
||||||
#define bfin_spi_suspend NULL
|
#define BFIN_SPI_PM_OPS NULL
|
||||||
#define bfin_spi_resume NULL
|
#endif
|
||||||
#endif /* CONFIG_PM */
|
|
||||||
|
|
||||||
MODULE_ALIAS("platform:bfin-spi");
|
MODULE_ALIAS("platform:bfin-spi");
|
||||||
static struct platform_driver bfin_spi_driver = {
|
static struct platform_driver bfin_spi_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = DRV_NAME,
|
.name = DRV_NAME,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.pm = BFIN_SPI_PM_OPS,
|
||||||
},
|
},
|
||||||
.suspend = bfin_spi_suspend,
|
.probe = bfin_spi_probe,
|
||||||
.resume = bfin_spi_resume,
|
|
||||||
.remove = bfin_spi_remove,
|
.remove = bfin_spi_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init bfin_spi_init(void)
|
static int __init bfin_spi_init(void)
|
||||||
{
|
{
|
||||||
return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe);
|
return platform_driver_register(&bfin_spi_driver);
|
||||||
}
|
}
|
||||||
subsys_initcall(bfin_spi_init);
|
subsys_initcall(bfin_spi_init);
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ int spi_bitbang_setup(struct spi_device *spi)
|
|||||||
bitbang = spi_master_get_devdata(spi->master);
|
bitbang = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
if (!cs) {
|
if (!cs) {
|
||||||
cs = kzalloc(sizeof *cs, GFP_KERNEL);
|
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
|
||||||
if (!cs)
|
if (!cs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
spi->controller_state = cs;
|
spi->controller_state = cs;
|
||||||
@ -258,7 +258,7 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
|
|||||||
|
|
||||||
static int spi_bitbang_prepare_hardware(struct spi_master *spi)
|
static int spi_bitbang_prepare_hardware(struct spi_master *spi)
|
||||||
{
|
{
|
||||||
struct spi_bitbang *bitbang;
|
struct spi_bitbang *bitbang;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
bitbang = spi_master_get_devdata(spi);
|
bitbang = spi_master_get_devdata(spi);
|
||||||
@ -273,7 +273,7 @@ static int spi_bitbang_prepare_hardware(struct spi_master *spi)
|
|||||||
static int spi_bitbang_transfer_one(struct spi_master *master,
|
static int spi_bitbang_transfer_one(struct spi_master *master,
|
||||||
struct spi_message *m)
|
struct spi_message *m)
|
||||||
{
|
{
|
||||||
struct spi_bitbang *bitbang;
|
struct spi_bitbang *bitbang;
|
||||||
unsigned nsecs;
|
unsigned nsecs;
|
||||||
struct spi_transfer *t = NULL;
|
struct spi_transfer *t = NULL;
|
||||||
unsigned cs_change;
|
unsigned cs_change;
|
||||||
@ -292,7 +292,7 @@ static int spi_bitbang_transfer_one(struct spi_master *master,
|
|||||||
cs_change = 1;
|
cs_change = 1;
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
list_for_each_entry (t, &m->transfers, transfer_list) {
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
|
|
||||||
/* override speed or wordsize? */
|
/* override speed or wordsize? */
|
||||||
if (t->speed_hz || t->bits_per_word)
|
if (t->speed_hz || t->bits_per_word)
|
||||||
@ -349,7 +349,8 @@ static int spi_bitbang_transfer_one(struct spi_master *master,
|
|||||||
if (t->delay_usecs)
|
if (t->delay_usecs)
|
||||||
udelay(t->delay_usecs);
|
udelay(t->delay_usecs);
|
||||||
|
|
||||||
if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
|
if (cs_change &&
|
||||||
|
!list_is_last(&t->transfer_list, &m->transfers)) {
|
||||||
/* sometimes a short mid-message deselect of the chip
|
/* sometimes a short mid-message deselect of the chip
|
||||||
* may be needed to terminate a mode or command
|
* may be needed to terminate a mode or command
|
||||||
*/
|
*/
|
||||||
@ -378,7 +379,7 @@ static int spi_bitbang_transfer_one(struct spi_master *master,
|
|||||||
|
|
||||||
static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
|
static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
|
||||||
{
|
{
|
||||||
struct spi_bitbang *bitbang;
|
struct spi_bitbang *bitbang;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
bitbang = spi_master_get_devdata(spi);
|
bitbang = spi_master_get_devdata(spi);
|
||||||
@ -414,10 +415,16 @@ static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
|
|||||||
* This routine registers the spi_master, which will process requests in a
|
* This routine registers the spi_master, which will process requests in a
|
||||||
* dedicated task, keeping IRQs unblocked most of the time. To stop
|
* dedicated task, keeping IRQs unblocked most of the time. To stop
|
||||||
* processing those requests, call spi_bitbang_stop().
|
* processing those requests, call spi_bitbang_stop().
|
||||||
|
*
|
||||||
|
* On success, this routine will take a reference to master. The caller is
|
||||||
|
* responsible for calling spi_bitbang_stop() to decrement the reference and
|
||||||
|
* spi_master_put() as counterpart of spi_alloc_master() to prevent a memory
|
||||||
|
* leak.
|
||||||
*/
|
*/
|
||||||
int spi_bitbang_start(struct spi_bitbang *bitbang)
|
int spi_bitbang_start(struct spi_bitbang *bitbang)
|
||||||
{
|
{
|
||||||
struct spi_master *master = bitbang->master;
|
struct spi_master *master = bitbang->master;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!master || !bitbang->chipselect)
|
if (!master || !bitbang->chipselect)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -449,7 +456,11 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
|
|||||||
/* driver may get busy before register() returns, especially
|
/* driver may get busy before register() returns, especially
|
||||||
* if someone registered boardinfo for devices
|
* if someone registered boardinfo for devices
|
||||||
*/
|
*/
|
||||||
return spi_register_master(master);
|
ret = spi_register_master(spi_master_get(master));
|
||||||
|
if (ret)
|
||||||
|
spi_master_put(master);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_bitbang_start);
|
EXPORT_SYMBOL_GPL(spi_bitbang_start);
|
||||||
|
|
||||||
|
@ -147,8 +147,8 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
|
|||||||
|
|
||||||
/* we only needed to implement one mode here, and choose SPI_MODE_0 */
|
/* we only needed to implement one mode here, and choose SPI_MODE_0 */
|
||||||
|
|
||||||
#define spidelay(X) do{}while(0)
|
#define spidelay(X) do { } while (0)
|
||||||
//#define spidelay ndelay
|
/* #define spidelay ndelay */
|
||||||
|
|
||||||
#include "spi-bitbang-txrx.h"
|
#include "spi-bitbang-txrx.h"
|
||||||
|
|
||||||
@ -171,15 +171,15 @@ static struct mtd_partition partitions[] = { {
|
|||||||
/* sector 0 = 8 pages * 264 bytes/page (1 block)
|
/* sector 0 = 8 pages * 264 bytes/page (1 block)
|
||||||
* sector 1 = 248 pages * 264 bytes/page
|
* sector 1 = 248 pages * 264 bytes/page
|
||||||
*/
|
*/
|
||||||
.name = "bookkeeping", // 66 KB
|
.name = "bookkeeping", /* 66 KB */
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = (8 + 248) * 264,
|
.size = (8 + 248) * 264,
|
||||||
// .mask_flags = MTD_WRITEABLE,
|
/* .mask_flags = MTD_WRITEABLE, */
|
||||||
}, {
|
}, {
|
||||||
/* sector 2 = 256 pages * 264 bytes/page
|
/* sector 2 = 256 pages * 264 bytes/page
|
||||||
* sectors 3-5 = 512 pages * 264 bytes/page
|
* sectors 3-5 = 512 pages * 264 bytes/page
|
||||||
*/
|
*/
|
||||||
.name = "filesystem", // 462 KB
|
.name = "filesystem", /* 462 KB */
|
||||||
.offset = MTDPART_OFS_APPEND,
|
.offset = MTDPART_OFS_APPEND,
|
||||||
.size = MTDPART_SIZ_FULL,
|
.size = MTDPART_SIZ_FULL,
|
||||||
} };
|
} };
|
||||||
@ -209,7 +209,7 @@ static void butterfly_attach(struct parport *p)
|
|||||||
* and no way to be selective about what it binds to.
|
* and no way to be selective about what it binds to.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
master = spi_alloc_master(dev, sizeof *pp);
|
master = spi_alloc_master(dev, sizeof(*pp));
|
||||||
if (!master) {
|
if (!master) {
|
||||||
status = -ENOMEM;
|
status = -ENOMEM;
|
||||||
goto done;
|
goto done;
|
||||||
@ -225,7 +225,7 @@ static void butterfly_attach(struct parport *p)
|
|||||||
master->bus_num = 42;
|
master->bus_num = 42;
|
||||||
master->num_chipselect = 2;
|
master->num_chipselect = 2;
|
||||||
|
|
||||||
pp->bitbang.master = spi_master_get(master);
|
pp->bitbang.master = master;
|
||||||
pp->bitbang.chipselect = butterfly_chipselect;
|
pp->bitbang.chipselect = butterfly_chipselect;
|
||||||
pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
|
pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
|
||||||
|
|
||||||
@ -289,7 +289,6 @@ static void butterfly_attach(struct parport *p)
|
|||||||
pr_debug("%s: dataflash at %s\n", p->name,
|
pr_debug("%s: dataflash at %s\n", p->name,
|
||||||
dev_name(&pp->dataflash->dev));
|
dev_name(&pp->dataflash->dev));
|
||||||
|
|
||||||
// dev_info(_what?_, ...)
|
|
||||||
pr_info("%s: AVR Butterfly\n", p->name);
|
pr_info("%s: AVR Butterfly\n", p->name);
|
||||||
butterfly = pp;
|
butterfly = pp;
|
||||||
return;
|
return;
|
||||||
|
@ -226,10 +226,10 @@ static int spi_clps711x_probe(struct platform_device *pdev)
|
|||||||
dev_name(&pdev->dev), hw);
|
dev_name(&pdev->dev), hw);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Can't request IRQ\n");
|
dev_err(&pdev->dev, "Can't request IRQ\n");
|
||||||
goto clk_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
dev_info(&pdev->dev,
|
dev_info(&pdev->dev,
|
||||||
"SPI bus driver initialized. Master clock %u Hz\n",
|
"SPI bus driver initialized. Master clock %u Hz\n",
|
||||||
@ -239,7 +239,6 @@ static int spi_clps711x_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
dev_err(&pdev->dev, "Failed to register master\n");
|
dev_err(&pdev->dev, "Failed to register master\n");
|
||||||
|
|
||||||
clk_out:
|
|
||||||
err_out:
|
err_out:
|
||||||
while (--i >= 0)
|
while (--i >= 0)
|
||||||
if (gpio_is_valid(hw->chipselect[i]))
|
if (gpio_is_valid(hw->chipselect[i]))
|
||||||
@ -260,8 +259,6 @@ static int spi_clps711x_remove(struct platform_device *pdev)
|
|||||||
if (gpio_is_valid(hw->chipselect[i]))
|
if (gpio_is_valid(hw->chipselect[i]))
|
||||||
gpio_free(hw->chipselect[i]);
|
gpio_free(hw->chipselect[i]);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +279,8 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
|
|||||||
struct davinci_spi *dspi;
|
struct davinci_spi *dspi;
|
||||||
struct davinci_spi_config *spicfg;
|
struct davinci_spi_config *spicfg;
|
||||||
u8 bits_per_word = 0;
|
u8 bits_per_word = 0;
|
||||||
u32 hz = 0, spifmt = 0, prescale = 0;
|
u32 hz = 0, spifmt = 0;
|
||||||
|
int prescale;
|
||||||
|
|
||||||
dspi = spi_master_get_devdata(spi->master);
|
dspi = spi_master_get_devdata(spi->master);
|
||||||
spicfg = (struct davinci_spi_config *)spi->controller_data;
|
spicfg = (struct davinci_spi_config *)spi->controller_data;
|
||||||
@ -916,7 +917,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto unmap_io;
|
goto unmap_io;
|
||||||
|
|
||||||
dspi->bitbang.master = spi_master_get(master);
|
dspi->bitbang.master = master;
|
||||||
if (dspi->bitbang.master == NULL) {
|
if (dspi->bitbang.master == NULL) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto irq_free;
|
goto irq_free;
|
||||||
@ -925,7 +926,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
|||||||
dspi->clk = clk_get(&pdev->dev, NULL);
|
dspi->clk = clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(dspi->clk)) {
|
if (IS_ERR(dspi->clk)) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto put_master;
|
goto irq_free;
|
||||||
}
|
}
|
||||||
clk_prepare_enable(dspi->clk);
|
clk_prepare_enable(dspi->clk);
|
||||||
|
|
||||||
@ -1015,8 +1016,6 @@ free_dma:
|
|||||||
free_clk:
|
free_clk:
|
||||||
clk_disable_unprepare(dspi->clk);
|
clk_disable_unprepare(dspi->clk);
|
||||||
clk_put(dspi->clk);
|
clk_put(dspi->clk);
|
||||||
put_master:
|
|
||||||
spi_master_put(master);
|
|
||||||
irq_free:
|
irq_free:
|
||||||
free_irq(dspi->irq, dspi);
|
free_irq(dspi->irq, dspi);
|
||||||
unmap_io:
|
unmap_io:
|
||||||
@ -1024,7 +1023,7 @@ unmap_io:
|
|||||||
release_region:
|
release_region:
|
||||||
release_mem_region(dspi->pbase, resource_size(r));
|
release_mem_region(dspi->pbase, resource_size(r));
|
||||||
free_master:
|
free_master:
|
||||||
kfree(master);
|
spi_master_put(master);
|
||||||
err:
|
err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1051,11 +1050,11 @@ static int davinci_spi_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
clk_disable_unprepare(dspi->clk);
|
clk_disable_unprepare(dspi->clk);
|
||||||
clk_put(dspi->clk);
|
clk_put(dspi->clk);
|
||||||
spi_master_put(master);
|
|
||||||
free_irq(dspi->irq, dspi);
|
free_irq(dspi->irq, dspi);
|
||||||
iounmap(dspi->base);
|
iounmap(dspi->base);
|
||||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
release_mem_region(dspi->pbase, resource_size(r));
|
release_mem_region(dspi->pbase, resource_size(r));
|
||||||
|
spi_master_put(master);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
|
|||||||
dwsmmio->clk = clk_get(&pdev->dev, NULL);
|
dwsmmio->clk = clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(dwsmmio->clk)) {
|
if (IS_ERR(dwsmmio->clk)) {
|
||||||
ret = PTR_ERR(dwsmmio->clk);
|
ret = PTR_ERR(dwsmmio->clk);
|
||||||
goto err_irq;
|
goto err_unmap;
|
||||||
}
|
}
|
||||||
clk_enable(dwsmmio->clk);
|
clk_enable(dwsmmio->clk);
|
||||||
|
|
||||||
@ -94,8 +94,6 @@ err_clk:
|
|||||||
clk_disable(dwsmmio->clk);
|
clk_disable(dwsmmio->clk);
|
||||||
clk_put(dwsmmio->clk);
|
clk_put(dwsmmio->clk);
|
||||||
dwsmmio->clk = NULL;
|
dwsmmio->clk = NULL;
|
||||||
err_irq:
|
|
||||||
free_irq(dws->irq, dws);
|
|
||||||
err_unmap:
|
err_unmap:
|
||||||
iounmap(dws->regs);
|
iounmap(dws->regs);
|
||||||
err_release_reg:
|
err_release_reg:
|
||||||
@ -115,7 +113,6 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
|
|||||||
clk_put(dwsmmio->clk);
|
clk_put(dwsmmio->clk);
|
||||||
dwsmmio->clk = NULL;
|
dwsmmio->clk = NULL;
|
||||||
|
|
||||||
free_irq(dwsmmio->dws.irq, &dwsmmio->dws);
|
|
||||||
dw_spi_remove_host(&dwsmmio->dws);
|
dw_spi_remove_host(&dwsmmio->dws);
|
||||||
iounmap(dwsmmio->dws.regs);
|
iounmap(dwsmmio->dws.regs);
|
||||||
kfree(dwsmmio);
|
kfree(dwsmmio);
|
||||||
|
@ -40,7 +40,7 @@ static int spi_pci_probe(struct pci_dev *pdev,
|
|||||||
int pci_bar = 0;
|
int pci_bar = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
printk(KERN_INFO "DW: found PCI SPI controller(ID: %04x:%04x)\n",
|
dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
|
||||||
pdev->vendor, pdev->device);
|
pdev->vendor, pdev->device);
|
||||||
|
|
||||||
ret = pci_enable_device(pdev);
|
ret = pci_enable_device(pdev);
|
||||||
@ -109,7 +109,6 @@ static void spi_pci_remove(struct pci_dev *pdev)
|
|||||||
{
|
{
|
||||||
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
|
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
|
||||||
|
|
||||||
pci_set_drvdata(pdev, NULL);
|
|
||||||
dw_spi_remove_host(&dwpci->dws);
|
dw_spi_remove_host(&dwpci->dws);
|
||||||
iounmap(dwpci->dws.regs);
|
iounmap(dwpci->dws.regs);
|
||||||
pci_release_region(pdev, 0);
|
pci_release_region(pdev, 0);
|
||||||
|
@ -870,8 +870,8 @@ void dw_spi_remove_host(struct dw_spi *dws)
|
|||||||
/* Remove the queue */
|
/* Remove the queue */
|
||||||
status = destroy_queue(dws);
|
status = destroy_queue(dws);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
|
dev_err(&dws->master->dev,
|
||||||
"complete, message memory not freed\n");
|
"dw_spi_remove: workqueue will not complete, message memory not freed\n");
|
||||||
|
|
||||||
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
||||||
dws->dma_ops->dma_exit(dws);
|
dws->dma_ops->dma_exit(dws);
|
||||||
|
@ -280,10 +280,6 @@ static irqreturn_t efm32_spi_txirq(int irq, void *data)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct efm32_spi_pdata efm32_spi_pdata_default = {
|
|
||||||
.location = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
|
static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
|
||||||
{
|
{
|
||||||
u32 reg = efm32_spi_read32(ddata, REG_ROUTE);
|
u32 reg = efm32_spi_read32(ddata, REG_ROUTE);
|
||||||
@ -347,7 +343,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
ddata = spi_master_get_devdata(master);
|
ddata = spi_master_get_devdata(master);
|
||||||
|
|
||||||
ddata->bitbang.master = spi_master_get(master);
|
ddata->bitbang.master = master;
|
||||||
ddata->bitbang.chipselect = efm32_spi_chipselect;
|
ddata->bitbang.chipselect = efm32_spi_chipselect;
|
||||||
ddata->bitbang.setup_transfer = efm32_spi_setup_transfer;
|
ddata->bitbang.setup_transfer = efm32_spi_setup_transfer;
|
||||||
ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
|
ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
|
||||||
@ -387,7 +383,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource_size(res) < 60) {
|
if (resource_size(res) < 0x60) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
dev_err(&pdev->dev, "memory resource too small\n");
|
dev_err(&pdev->dev, "memory resource too small\n");
|
||||||
goto err;
|
goto err;
|
||||||
@ -467,7 +463,6 @@ err_disable_clk:
|
|||||||
clk_disable_unprepare(ddata->clk);
|
clk_disable_unprepare(ddata->clk);
|
||||||
err:
|
err:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
kfree(master);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -478,13 +473,14 @@ static int efm32_spi_remove(struct platform_device *pdev)
|
|||||||
struct spi_master *master = platform_get_drvdata(pdev);
|
struct spi_master *master = platform_get_drvdata(pdev);
|
||||||
struct efm32_spi_ddata *ddata = spi_master_get_devdata(master);
|
struct efm32_spi_ddata *ddata = spi_master_get_devdata(master);
|
||||||
|
|
||||||
|
spi_bitbang_stop(&ddata->bitbang);
|
||||||
|
|
||||||
efm32_spi_write32(ddata, 0, REG_IEN);
|
efm32_spi_write32(ddata, 0, REG_IEN);
|
||||||
|
|
||||||
free_irq(ddata->txirq, ddata);
|
free_irq(ddata->txirq, ddata);
|
||||||
free_irq(ddata->rxirq, ddata);
|
free_irq(ddata->rxirq, ddata);
|
||||||
clk_disable_unprepare(ddata->clk);
|
clk_disable_unprepare(ddata->clk);
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
kfree(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -330,7 +330,7 @@ static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
|
|||||||
|
|
||||||
dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
|
dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
|
||||||
chip->spi->mode, div_cpsr, div_scr, dss);
|
chip->spi->mode, div_cpsr, div_scr, dss);
|
||||||
dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
|
dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0);
|
||||||
|
|
||||||
ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr);
|
ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr);
|
||||||
ep93xx_spi_write_u16(espi, SSPCR0, cr0);
|
ep93xx_spi_write_u16(espi, SSPCR0, cr0);
|
||||||
@ -509,7 +509,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (WARN_ON(len)) {
|
if (WARN_ON(len)) {
|
||||||
dev_warn(&espi->pdev->dev, "len = %zu expected 0!", len);
|
dev_warn(&espi->pdev->dev, "len = %zu expected 0!\n", len);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -942,7 +942,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
|
|||||||
/* make sure that the hardware is disabled */
|
/* make sure that the hardware is disabled */
|
||||||
ep93xx_spi_write_u8(espi, SSPCR1, 0);
|
ep93xx_spi_write_u8(espi, SSPCR1, 0);
|
||||||
|
|
||||||
error = spi_register_master(master);
|
error = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&pdev->dev, "failed to register SPI master\n");
|
dev_err(&pdev->dev, "failed to register SPI master\n");
|
||||||
goto fail_free_dma;
|
goto fail_free_dma;
|
||||||
@ -968,7 +968,6 @@ static int ep93xx_spi_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
ep93xx_spi_release_dma(espi);
|
ep93xx_spi_release_dma(espi);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
|
|||||||
|
|
||||||
switch (mspi->subblock) {
|
switch (mspi->subblock) {
|
||||||
default:
|
default:
|
||||||
dev_warn(dev, "cell-index unspecified, assuming SPI1");
|
dev_warn(dev, "cell-index unspecified, assuming SPI1\n");
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 0:
|
case 0:
|
||||||
mspi->subblock = QE_CR_SUBBLOCK_SPI1;
|
mspi->subblock = QE_CR_SUBBLOCK_SPI1;
|
||||||
|
@ -108,7 +108,7 @@ struct fsl_dspi {
|
|||||||
struct spi_bitbang bitbang;
|
struct spi_bitbang bitbang;
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
|
||||||
void *base;
|
void __iomem *base;
|
||||||
int irq;
|
int irq;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_warn("Can not find valid buad rate,speed_hz is %d,clkrate is %ld\
|
pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld\
|
||||||
,we use the max prescaler value.\n", speed_hz, clkrate);
|
,we use the max prescaler value.\n", speed_hz, clkrate);
|
||||||
*pbr = ARRAY_SIZE(pbr_tbl) - 1;
|
*pbr = ARRAY_SIZE(pbr_tbl) - 1;
|
||||||
*br = ARRAY_SIZE(brs) - 1;
|
*br = ARRAY_SIZE(brs) - 1;
|
||||||
@ -450,7 +450,7 @@ static int dspi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
dspi = spi_master_get_devdata(master);
|
dspi = spi_master_get_devdata(master);
|
||||||
dspi->pdev = pdev;
|
dspi->pdev = pdev;
|
||||||
dspi->bitbang.master = spi_master_get(master);
|
dspi->bitbang.master = master;
|
||||||
dspi->bitbang.chipselect = dspi_chipselect;
|
dspi->bitbang.chipselect = dspi_chipselect;
|
||||||
dspi->bitbang.setup_transfer = dspi_setup_transfer;
|
dspi->bitbang.setup_transfer = dspi_setup_transfer;
|
||||||
dspi->bitbang.txrx_bufs = dspi_txrx_transfer;
|
dspi->bitbang.txrx_bufs = dspi_txrx_transfer;
|
||||||
@ -520,7 +520,6 @@ out_clk_put:
|
|||||||
clk_disable_unprepare(dspi->clk);
|
clk_disable_unprepare(dspi->clk);
|
||||||
out_master_put:
|
out_master_put:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -531,6 +530,7 @@ static int dspi_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* Disconnect from the SPI framework */
|
/* Disconnect from the SPI framework */
|
||||||
spi_bitbang_stop(&dspi->bitbang);
|
spi_bitbang_stop(&dspi->bitbang);
|
||||||
|
clk_disable_unprepare(dspi->clk);
|
||||||
spi_master_put(dspi->bitbang.master);
|
spi_master_put(dspi->bitbang.master);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -547,5 +547,5 @@ static struct platform_driver fsl_dspi_driver = {
|
|||||||
module_platform_driver(fsl_dspi_driver);
|
module_platform_driver(fsl_dspi_driver);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Freescale DSPI Controller Driver");
|
MODULE_DESCRIPTION("Freescale DSPI Controller Driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||||
|
@ -289,8 +289,8 @@ static void fsl_espi_do_trans(struct spi_message *m,
|
|||||||
if ((first->bits_per_word != t->bits_per_word) ||
|
if ((first->bits_per_word != t->bits_per_word) ||
|
||||||
(first->speed_hz != t->speed_hz)) {
|
(first->speed_hz != t->speed_hz)) {
|
||||||
espi_trans->status = -EINVAL;
|
espi_trans->status = -EINVAL;
|
||||||
dev_err(mspi->dev, "bits_per_word/speed_hz should be"
|
dev_err(mspi->dev,
|
||||||
" same for the same SPI transfer\n");
|
"bits_per_word/speed_hz should be same for the same SPI transfer\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
|
|
||||||
@ -467,7 +468,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
spi_gpio->bitbang.master = spi_master_get(master);
|
spi_gpio->bitbang.master = master;
|
||||||
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
|
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
|
||||||
|
|
||||||
if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
|
if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
|
||||||
@ -486,7 +487,6 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
status = spi_bitbang_start(&spi_gpio->bitbang);
|
status = spi_bitbang_start(&spi_gpio->bitbang);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
spi_master_put(spi_gpio->bitbang.master);
|
|
||||||
gpio_free:
|
gpio_free:
|
||||||
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
|
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
|
||||||
gpio_free(SPI_MISO_GPIO);
|
gpio_free(SPI_MISO_GPIO);
|
||||||
@ -510,13 +510,13 @@ static int spi_gpio_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* stop() unregisters child devices too */
|
/* stop() unregisters child devices too */
|
||||||
status = spi_bitbang_stop(&spi_gpio->bitbang);
|
status = spi_bitbang_stop(&spi_gpio->bitbang);
|
||||||
spi_master_put(spi_gpio->bitbang.master);
|
|
||||||
|
|
||||||
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
|
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
|
||||||
gpio_free(SPI_MISO_GPIO);
|
gpio_free(SPI_MISO_GPIO);
|
||||||
if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
|
if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
|
||||||
gpio_free(SPI_MOSI_GPIO);
|
gpio_free(SPI_MOSI_GPIO);
|
||||||
gpio_free(SPI_SCK_GPIO);
|
gpio_free(SPI_SCK_GPIO);
|
||||||
|
spi_master_put(spi_gpio->bitbang.master);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -749,6 +749,35 @@ static void spi_imx_cleanup(struct spi_device *spi)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg)
|
||||||
|
{
|
||||||
|
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = clk_enable(spi_imx->clk_per);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_enable(spi_imx->clk_ipg);
|
||||||
|
if (ret) {
|
||||||
|
clk_disable(spi_imx->clk_per);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg)
|
||||||
|
{
|
||||||
|
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
|
||||||
|
|
||||||
|
clk_disable(spi_imx->clk_ipg);
|
||||||
|
clk_disable(spi_imx->clk_per);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int spi_imx_probe(struct platform_device *pdev)
|
static int spi_imx_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
@ -786,7 +815,7 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|||||||
master->num_chipselect = num_cs;
|
master->num_chipselect = num_cs;
|
||||||
|
|
||||||
spi_imx = spi_master_get_devdata(master);
|
spi_imx = spi_master_get_devdata(master);
|
||||||
spi_imx->bitbang.master = spi_master_get(master);
|
spi_imx->bitbang.master = master;
|
||||||
|
|
||||||
for (i = 0; i < master->num_chipselect; i++) {
|
for (i = 0; i < master->num_chipselect; i++) {
|
||||||
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
|
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
|
||||||
@ -810,6 +839,8 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|||||||
spi_imx->bitbang.txrx_bufs = spi_imx_transfer;
|
spi_imx->bitbang.txrx_bufs = spi_imx_transfer;
|
||||||
spi_imx->bitbang.master->setup = spi_imx_setup;
|
spi_imx->bitbang.master->setup = spi_imx_setup;
|
||||||
spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
|
spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
|
||||||
|
spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
|
||||||
|
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
|
||||||
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||||
|
|
||||||
init_completion(&spi_imx->xfer_done);
|
init_completion(&spi_imx->xfer_done);
|
||||||
@ -872,6 +903,8 @@ static int spi_imx_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
dev_info(&pdev->dev, "probed\n");
|
dev_info(&pdev->dev, "probed\n");
|
||||||
|
|
||||||
|
clk_disable(spi_imx->clk_ipg);
|
||||||
|
clk_disable(spi_imx->clk_per);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
out_clk_put:
|
out_clk_put:
|
||||||
|
@ -222,7 +222,7 @@ static void spi_lm70llp_attach(struct parport *p)
|
|||||||
/*
|
/*
|
||||||
* SPI and bitbang hookup.
|
* SPI and bitbang hookup.
|
||||||
*/
|
*/
|
||||||
pp->bitbang.master = spi_master_get(master);
|
pp->bitbang.master = master;
|
||||||
pp->bitbang.chipselect = lm70_chipselect;
|
pp->bitbang.chipselect = lm70_chipselect;
|
||||||
pp->bitbang.txrx_word[SPI_MODE_0] = lm70_txrx;
|
pp->bitbang.txrx_word[SPI_MODE_0] = lm70_txrx;
|
||||||
pp->bitbang.flags = SPI_3WIRE;
|
pp->bitbang.flags = SPI_3WIRE;
|
||||||
|
@ -536,7 +536,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto free_clock;
|
goto free_clock;
|
||||||
|
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(dev, master);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto free_clock;
|
goto free_clock;
|
||||||
|
|
||||||
@ -559,12 +559,10 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
|
|||||||
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
||||||
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
|
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
clk_disable_unprepare(mps->clk_mclk);
|
clk_disable_unprepare(mps->clk_mclk);
|
||||||
free_irq(mps->irq, mps);
|
free_irq(mps->irq, mps);
|
||||||
if (mps->psc)
|
if (mps->psc)
|
||||||
iounmap(mps->psc);
|
iounmap(mps->psc);
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -383,8 +383,8 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
|||||||
|
|
||||||
mps->irq = irq;
|
mps->irq = irq;
|
||||||
if (pdata == NULL) {
|
if (pdata == NULL) {
|
||||||
dev_warn(dev, "probe called without platform data, no "
|
dev_warn(dev,
|
||||||
"cs_control function will be called\n");
|
"probe called without platform data, no cs_control function will be called\n");
|
||||||
mps->cs_control = NULL;
|
mps->cs_control = NULL;
|
||||||
mps->sysclk = 0;
|
mps->sysclk = 0;
|
||||||
master->bus_num = bus_num;
|
master->bus_num = bus_num;
|
||||||
|
@ -57,34 +57,53 @@
|
|||||||
|
|
||||||
#define SG_MAXLEN 0xff00
|
#define SG_MAXLEN 0xff00
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags for txrx functions. More efficient that using an argument register for
|
||||||
|
* each one.
|
||||||
|
*/
|
||||||
|
#define TXRX_WRITE (1<<0) /* This is a write */
|
||||||
|
#define TXRX_DEASSERT_CS (1<<1) /* De-assert CS at end of txrx */
|
||||||
|
|
||||||
struct mxs_spi {
|
struct mxs_spi {
|
||||||
struct mxs_ssp ssp;
|
struct mxs_ssp ssp;
|
||||||
struct completion c;
|
struct completion c;
|
||||||
|
unsigned int sck; /* Rate requested (vs actual) */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mxs_spi_setup_transfer(struct spi_device *dev,
|
static int mxs_spi_setup_transfer(struct spi_device *dev,
|
||||||
struct spi_transfer *t)
|
const struct spi_transfer *t)
|
||||||
{
|
{
|
||||||
struct mxs_spi *spi = spi_master_get_devdata(dev->master);
|
struct mxs_spi *spi = spi_master_get_devdata(dev->master);
|
||||||
struct mxs_ssp *ssp = &spi->ssp;
|
struct mxs_ssp *ssp = &spi->ssp;
|
||||||
uint32_t hz = 0;
|
const unsigned int hz = min(dev->max_speed_hz, t->speed_hz);
|
||||||
|
|
||||||
hz = dev->max_speed_hz;
|
|
||||||
if (t && t->speed_hz)
|
|
||||||
hz = min(hz, t->speed_hz);
|
|
||||||
if (hz == 0) {
|
if (hz == 0) {
|
||||||
dev_err(&dev->dev, "Cannot continue with zero clock\n");
|
dev_err(&dev->dev, "SPI clock rate of zero not allowed\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mxs_ssp_set_clk_rate(ssp, hz);
|
if (hz != spi->sck) {
|
||||||
|
mxs_ssp_set_clk_rate(ssp, hz);
|
||||||
|
/*
|
||||||
|
* Save requested rate, hz, rather than the actual rate,
|
||||||
|
* ssp->clk_rate. Otherwise we would set the rate every trasfer
|
||||||
|
* when the actual rate is not quite the same as requested rate.
|
||||||
|
*/
|
||||||
|
spi->sck = hz;
|
||||||
|
/*
|
||||||
|
* Perhaps we should return an error if the actual clock is
|
||||||
|
* nowhere close to what was requested?
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(BM_SSP_CTRL0_LOCK_CS,
|
||||||
|
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
||||||
|
|
||||||
writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) |
|
writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) |
|
||||||
BF_SSP_CTRL1_WORD_LENGTH
|
BF_SSP_CTRL1_WORD_LENGTH(BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) |
|
||||||
(BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) |
|
((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
|
||||||
((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
|
((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0),
|
||||||
((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0),
|
ssp->base + HW_SSP_CTRL1(ssp));
|
||||||
ssp->base + HW_SSP_CTRL1(ssp));
|
|
||||||
|
|
||||||
writel(0x0, ssp->base + HW_SSP_CMD0);
|
writel(0x0, ssp->base + HW_SSP_CMD0);
|
||||||
writel(0x0, ssp->base + HW_SSP_CMD1);
|
writel(0x0, ssp->base + HW_SSP_CMD1);
|
||||||
@ -94,26 +113,15 @@ static int mxs_spi_setup_transfer(struct spi_device *dev,
|
|||||||
|
|
||||||
static int mxs_spi_setup(struct spi_device *dev)
|
static int mxs_spi_setup(struct spi_device *dev)
|
||||||
{
|
{
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!dev->bits_per_word)
|
if (!dev->bits_per_word)
|
||||||
dev->bits_per_word = 8;
|
dev->bits_per_word = 8;
|
||||||
|
|
||||||
if (dev->mode & ~(SPI_CPOL | SPI_CPHA))
|
return 0;
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
err = mxs_spi_setup_transfer(dev, NULL);
|
|
||||||
if (err) {
|
|
||||||
dev_err(&dev->dev,
|
|
||||||
"Failed to setup transfer, error = %d\n", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t mxs_spi_cs_to_reg(unsigned cs)
|
static u32 mxs_spi_cs_to_reg(unsigned cs)
|
||||||
{
|
{
|
||||||
uint32_t select = 0;
|
u32 select = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* i.MX28 Datasheet: 17.10.1: HW_SSP_CTRL0
|
* i.MX28 Datasheet: 17.10.1: HW_SSP_CTRL0
|
||||||
@ -131,43 +139,11 @@ static uint32_t mxs_spi_cs_to_reg(unsigned cs)
|
|||||||
return select;
|
return select;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mxs_spi_set_cs(struct mxs_spi *spi, unsigned cs)
|
|
||||||
{
|
|
||||||
const uint32_t mask =
|
|
||||||
BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ;
|
|
||||||
uint32_t select;
|
|
||||||
struct mxs_ssp *ssp = &spi->ssp;
|
|
||||||
|
|
||||||
writel(mask, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
|
||||||
select = mxs_spi_cs_to_reg(cs);
|
|
||||||
writel(select, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mxs_spi_enable(struct mxs_spi *spi)
|
|
||||||
{
|
|
||||||
struct mxs_ssp *ssp = &spi->ssp;
|
|
||||||
|
|
||||||
writel(BM_SSP_CTRL0_LOCK_CS,
|
|
||||||
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
|
||||||
writel(BM_SSP_CTRL0_IGNORE_CRC,
|
|
||||||
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mxs_spi_disable(struct mxs_spi *spi)
|
|
||||||
{
|
|
||||||
struct mxs_ssp *ssp = &spi->ssp;
|
|
||||||
|
|
||||||
writel(BM_SSP_CTRL0_LOCK_CS,
|
|
||||||
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
|
||||||
writel(BM_SSP_CTRL0_IGNORE_CRC,
|
|
||||||
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set)
|
static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set)
|
||||||
{
|
{
|
||||||
const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT);
|
const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT);
|
||||||
struct mxs_ssp *ssp = &spi->ssp;
|
struct mxs_ssp *ssp = &spi->ssp;
|
||||||
uint32_t reg;
|
u32 reg;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
reg = readl_relaxed(ssp->base + offset);
|
reg = readl_relaxed(ssp->base + offset);
|
||||||
@ -200,9 +176,9 @@ static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
|
static int mxs_spi_txrx_dma(struct mxs_spi *spi,
|
||||||
unsigned char *buf, int len,
|
unsigned char *buf, int len,
|
||||||
int *first, int *last, int write)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct mxs_ssp *ssp = &spi->ssp;
|
struct mxs_ssp *ssp = &spi->ssp;
|
||||||
struct dma_async_tx_descriptor *desc = NULL;
|
struct dma_async_tx_descriptor *desc = NULL;
|
||||||
@ -211,11 +187,11 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
|
|||||||
const int sgs = DIV_ROUND_UP(len, desc_len);
|
const int sgs = DIV_ROUND_UP(len, desc_len);
|
||||||
int sg_count;
|
int sg_count;
|
||||||
int min, ret;
|
int min, ret;
|
||||||
uint32_t ctrl0;
|
u32 ctrl0;
|
||||||
struct page *vm_page;
|
struct page *vm_page;
|
||||||
void *sg_buf;
|
void *sg_buf;
|
||||||
struct {
|
struct {
|
||||||
uint32_t pio[4];
|
u32 pio[4];
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
} *dma_xfer;
|
} *dma_xfer;
|
||||||
|
|
||||||
@ -228,21 +204,25 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
|
|||||||
|
|
||||||
INIT_COMPLETION(spi->c);
|
INIT_COMPLETION(spi->c);
|
||||||
|
|
||||||
|
/* Chip select was already programmed into CTRL0 */
|
||||||
ctrl0 = readl(ssp->base + HW_SSP_CTRL0);
|
ctrl0 = readl(ssp->base + HW_SSP_CTRL0);
|
||||||
ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT;
|
ctrl0 &= ~(BM_SSP_CTRL0_XFER_COUNT | BM_SSP_CTRL0_IGNORE_CRC |
|
||||||
ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs);
|
BM_SSP_CTRL0_READ);
|
||||||
|
ctrl0 |= BM_SSP_CTRL0_DATA_XFER;
|
||||||
|
|
||||||
if (*first)
|
if (!(flags & TXRX_WRITE))
|
||||||
ctrl0 |= BM_SSP_CTRL0_LOCK_CS;
|
|
||||||
if (!write)
|
|
||||||
ctrl0 |= BM_SSP_CTRL0_READ;
|
ctrl0 |= BM_SSP_CTRL0_READ;
|
||||||
|
|
||||||
/* Queue the DMA data transfer. */
|
/* Queue the DMA data transfer. */
|
||||||
for (sg_count = 0; sg_count < sgs; sg_count++) {
|
for (sg_count = 0; sg_count < sgs; sg_count++) {
|
||||||
|
/* Prepare the transfer descriptor. */
|
||||||
min = min(len, desc_len);
|
min = min(len, desc_len);
|
||||||
|
|
||||||
/* Prepare the transfer descriptor. */
|
/*
|
||||||
if ((sg_count + 1 == sgs) && *last)
|
* De-assert CS on last segment if flag is set (i.e., no more
|
||||||
|
* transfers will follow)
|
||||||
|
*/
|
||||||
|
if ((sg_count + 1 == sgs) && (flags & TXRX_DEASSERT_CS))
|
||||||
ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC;
|
ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC;
|
||||||
|
|
||||||
if (ssp->devid == IMX23_SSP) {
|
if (ssp->devid == IMX23_SSP) {
|
||||||
@ -267,7 +247,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
|
|||||||
|
|
||||||
sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min);
|
sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min);
|
||||||
ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
|
ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
|
||||||
write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
(flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||||
|
|
||||||
len -= min;
|
len -= min;
|
||||||
buf += min;
|
buf += min;
|
||||||
@ -287,7 +267,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
|
|||||||
|
|
||||||
desc = dmaengine_prep_slave_sg(ssp->dmach,
|
desc = dmaengine_prep_slave_sg(ssp->dmach,
|
||||||
&dma_xfer[sg_count].sg, 1,
|
&dma_xfer[sg_count].sg, 1,
|
||||||
write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
|
(flags & TXRX_WRITE) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
|
||||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
|
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
@ -324,7 +304,7 @@ err_vmalloc:
|
|||||||
while (--sg_count >= 0) {
|
while (--sg_count >= 0) {
|
||||||
err_mapped:
|
err_mapped:
|
||||||
dma_unmap_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
|
dma_unmap_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
|
||||||
write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
(flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(dma_xfer);
|
kfree(dma_xfer);
|
||||||
@ -332,20 +312,19 @@ err_mapped:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs,
|
static int mxs_spi_txrx_pio(struct mxs_spi *spi,
|
||||||
unsigned char *buf, int len,
|
unsigned char *buf, int len,
|
||||||
int *first, int *last, int write)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct mxs_ssp *ssp = &spi->ssp;
|
struct mxs_ssp *ssp = &spi->ssp;
|
||||||
|
|
||||||
if (*first)
|
writel(BM_SSP_CTRL0_IGNORE_CRC,
|
||||||
mxs_spi_enable(spi);
|
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
||||||
|
|
||||||
mxs_spi_set_cs(spi, cs);
|
|
||||||
|
|
||||||
while (len--) {
|
while (len--) {
|
||||||
if (*last && len == 0)
|
if (len == 0 && (flags & TXRX_DEASSERT_CS))
|
||||||
mxs_spi_disable(spi);
|
writel(BM_SSP_CTRL0_IGNORE_CRC,
|
||||||
|
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
||||||
|
|
||||||
if (ssp->devid == IMX23_SSP) {
|
if (ssp->devid == IMX23_SSP) {
|
||||||
writel(BM_SSP_CTRL0_XFER_COUNT,
|
writel(BM_SSP_CTRL0_XFER_COUNT,
|
||||||
@ -356,7 +335,7 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs,
|
|||||||
writel(1, ssp->base + HW_SSP_XFER_SIZE);
|
writel(1, ssp->base + HW_SSP_XFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write)
|
if (flags & TXRX_WRITE)
|
||||||
writel(BM_SSP_CTRL0_READ,
|
writel(BM_SSP_CTRL0_READ,
|
||||||
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
||||||
else
|
else
|
||||||
@ -369,13 +348,13 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs,
|
|||||||
if (mxs_ssp_wait(spi, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN, 1))
|
if (mxs_ssp_wait(spi, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN, 1))
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
if (write)
|
if (flags & TXRX_WRITE)
|
||||||
writel(*buf, ssp->base + HW_SSP_DATA(ssp));
|
writel(*buf, ssp->base + HW_SSP_DATA(ssp));
|
||||||
|
|
||||||
writel(BM_SSP_CTRL0_DATA_XFER,
|
writel(BM_SSP_CTRL0_DATA_XFER,
|
||||||
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
||||||
|
|
||||||
if (!write) {
|
if (!(flags & TXRX_WRITE)) {
|
||||||
if (mxs_ssp_wait(spi, HW_SSP_STATUS(ssp),
|
if (mxs_ssp_wait(spi, HW_SSP_STATUS(ssp),
|
||||||
BM_SSP_STATUS_FIFO_EMPTY, 0))
|
BM_SSP_STATUS_FIFO_EMPTY, 0))
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
@ -400,14 +379,15 @@ static int mxs_spi_transfer_one(struct spi_master *master,
|
|||||||
{
|
{
|
||||||
struct mxs_spi *spi = spi_master_get_devdata(master);
|
struct mxs_spi *spi = spi_master_get_devdata(master);
|
||||||
struct mxs_ssp *ssp = &spi->ssp;
|
struct mxs_ssp *ssp = &spi->ssp;
|
||||||
int first, last;
|
|
||||||
struct spi_transfer *t, *tmp_t;
|
struct spi_transfer *t, *tmp_t;
|
||||||
|
unsigned int flag;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
int cs;
|
|
||||||
|
|
||||||
first = last = 0;
|
/* Program CS register bits here, it will be used for all transfers. */
|
||||||
|
writel(BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ,
|
||||||
cs = m->spi->chip_select;
|
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
||||||
|
writel(mxs_spi_cs_to_reg(m->spi->chip_select),
|
||||||
|
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
||||||
|
|
||||||
list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
|
list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
|
||||||
|
|
||||||
@ -415,16 +395,9 @@ static int mxs_spi_transfer_one(struct spi_master *master,
|
|||||||
if (status)
|
if (status)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (&t->transfer_list == m->transfers.next)
|
/* De-assert on last transfer, inverted by cs_change flag */
|
||||||
first = 1;
|
flag = (&t->transfer_list == m->transfers.prev) ^ t->cs_change ?
|
||||||
if (&t->transfer_list == m->transfers.prev)
|
TXRX_DEASSERT_CS : 0;
|
||||||
last = 1;
|
|
||||||
if ((t->rx_buf && t->tx_buf) || (t->rx_dma && t->tx_dma)) {
|
|
||||||
dev_err(ssp->dev,
|
|
||||||
"Cannot send and receive simultaneously\n");
|
|
||||||
status = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Small blocks can be transfered via PIO.
|
* Small blocks can be transfered via PIO.
|
||||||
@ -441,26 +414,26 @@ static int mxs_spi_transfer_one(struct spi_master *master,
|
|||||||
STMP_OFFSET_REG_CLR);
|
STMP_OFFSET_REG_CLR);
|
||||||
|
|
||||||
if (t->tx_buf)
|
if (t->tx_buf)
|
||||||
status = mxs_spi_txrx_pio(spi, cs,
|
status = mxs_spi_txrx_pio(spi,
|
||||||
(void *)t->tx_buf,
|
(void *)t->tx_buf,
|
||||||
t->len, &first, &last, 1);
|
t->len, flag | TXRX_WRITE);
|
||||||
if (t->rx_buf)
|
if (t->rx_buf)
|
||||||
status = mxs_spi_txrx_pio(spi, cs,
|
status = mxs_spi_txrx_pio(spi,
|
||||||
t->rx_buf, t->len,
|
t->rx_buf, t->len,
|
||||||
&first, &last, 0);
|
flag);
|
||||||
} else {
|
} else {
|
||||||
writel(BM_SSP_CTRL1_DMA_ENABLE,
|
writel(BM_SSP_CTRL1_DMA_ENABLE,
|
||||||
ssp->base + HW_SSP_CTRL1(ssp) +
|
ssp->base + HW_SSP_CTRL1(ssp) +
|
||||||
STMP_OFFSET_REG_SET);
|
STMP_OFFSET_REG_SET);
|
||||||
|
|
||||||
if (t->tx_buf)
|
if (t->tx_buf)
|
||||||
status = mxs_spi_txrx_dma(spi, cs,
|
status = mxs_spi_txrx_dma(spi,
|
||||||
(void *)t->tx_buf, t->len,
|
(void *)t->tx_buf, t->len,
|
||||||
&first, &last, 1);
|
flag | TXRX_WRITE);
|
||||||
if (t->rx_buf)
|
if (t->rx_buf)
|
||||||
status = mxs_spi_txrx_dma(spi, cs,
|
status = mxs_spi_txrx_dma(spi,
|
||||||
t->rx_buf, t->len,
|
t->rx_buf, t->len,
|
||||||
&first, &last, 0);
|
flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
@ -469,7 +442,6 @@ static int mxs_spi_transfer_one(struct spi_master *master,
|
|||||||
}
|
}
|
||||||
|
|
||||||
m->actual_length += t->len;
|
m->actual_length += t->len;
|
||||||
first = last = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m->status = status;
|
m->status = status;
|
||||||
@ -563,7 +535,6 @@ static int mxs_spi_probe(struct platform_device *pdev)
|
|||||||
goto out_dma_release;
|
goto out_dma_release;
|
||||||
|
|
||||||
clk_set_rate(ssp->clk, clk_freq);
|
clk_set_rate(ssp->clk, clk_freq);
|
||||||
ssp->clk_rate = clk_get_rate(ssp->clk) / 1000;
|
|
||||||
|
|
||||||
ret = stmp_reset_block(ssp->base);
|
ret = stmp_reset_block(ssp->base);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -571,7 +542,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
platform_set_drvdata(pdev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
|
dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
|
||||||
goto out_disable_clk;
|
goto out_disable_clk;
|
||||||
@ -598,10 +569,8 @@ static int mxs_spi_remove(struct platform_device *pdev)
|
|||||||
spi = spi_master_get_devdata(master);
|
spi = spi_master_get_devdata(master);
|
||||||
ssp = &spi->ssp;
|
ssp = &spi->ssp;
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
clk_disable_unprepare(ssp->clk);
|
clk_disable_unprepare(ssp->clk);
|
||||||
dma_release_channel(ssp->dmach);
|
dma_release_channel(ssp->dmach);
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ static int nuc900_spi_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
hw = spi_master_get_devdata(master);
|
hw = spi_master_get_devdata(master);
|
||||||
hw->master = spi_master_get(master);
|
hw->master = master;
|
||||||
hw->pdata = dev_get_platdata(&pdev->dev);
|
hw->pdata = dev_get_platdata(&pdev->dev);
|
||||||
hw->dev = &pdev->dev;
|
hw->dev = &pdev->dev;
|
||||||
|
|
||||||
@ -435,7 +435,6 @@ err_iomap:
|
|||||||
kfree(hw->ioarea);
|
kfree(hw->ioarea);
|
||||||
err_pdata:
|
err_pdata:
|
||||||
spi_master_put(hw->master);
|
spi_master_put(hw->master);
|
||||||
|
|
||||||
err_nomem:
|
err_nomem:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,7 @@ static int tiny_spi_probe(struct platform_device *pdev)
|
|||||||
platform_set_drvdata(pdev, hw);
|
platform_set_drvdata(pdev, hw);
|
||||||
|
|
||||||
/* setup the state for the bitbang driver */
|
/* setup the state for the bitbang driver */
|
||||||
hw->bitbang.master = spi_master_get(master);
|
hw->bitbang.master = master;
|
||||||
if (!hw->bitbang.master)
|
if (!hw->bitbang.master)
|
||||||
return err;
|
return err;
|
||||||
hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
|
hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
|
||||||
|
@ -272,7 +272,7 @@ static int octeon_spi_probe(struct platform_device *pdev)
|
|||||||
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||||
|
|
||||||
master->dev.of_node = pdev->dev.of_node;
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
err = spi_register_master(master);
|
err = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "register master failed: %d\n", err);
|
dev_err(&pdev->dev, "register master failed: %d\n", err);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -292,8 +292,6 @@ static int octeon_spi_remove(struct platform_device *pdev)
|
|||||||
struct octeon_spi *p = spi_master_get_devdata(master);
|
struct octeon_spi *p = spi_master_get_devdata(master);
|
||||||
u64 register_base = p->register_base;
|
u64 register_base = p->register_base;
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
/* Clear the CSENA* and put everything in a known state. */
|
/* Clear the CSENA* and put everything in a known state. */
|
||||||
cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0);
|
cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0);
|
||||||
|
|
||||||
|
@ -457,7 +457,7 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = spi_register_master(master);
|
status = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -485,8 +485,6 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +557,8 @@ static struct platform_driver uwire_driver = {
|
|||||||
.name = "omap_uwire",
|
.name = "omap_uwire",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
},
|
},
|
||||||
.remove = uwire_remove,
|
.probe = uwire_probe,
|
||||||
|
.remove = uwire_remove,
|
||||||
// suspend ... unuse ck
|
// suspend ... unuse ck
|
||||||
// resume ... use ck
|
// resume ... use ck
|
||||||
};
|
};
|
||||||
@ -579,7 +580,7 @@ static int __init omap_uwire_init(void)
|
|||||||
omap_writel(val | 0x00AAA000, OMAP7XX_IO_CONF_9);
|
omap_writel(val | 0x00AAA000, OMAP7XX_IO_CONF_9);
|
||||||
}
|
}
|
||||||
|
|
||||||
return platform_driver_probe(&uwire_driver, uwire_probe);
|
return platform_driver_register(&uwire_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit omap_uwire_exit(void)
|
static void __exit omap_uwire_exit(void)
|
||||||
|
@ -276,7 +276,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
|
|||||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||||
struct omap2_mcspi *mcspi;
|
struct omap2_mcspi *mcspi;
|
||||||
unsigned int wcnt;
|
unsigned int wcnt;
|
||||||
int fifo_depth, bytes_per_word;
|
int max_fifo_depth, fifo_depth, bytes_per_word;
|
||||||
u32 chconf, xferlevel;
|
u32 chconf, xferlevel;
|
||||||
|
|
||||||
mcspi = spi_master_get_devdata(master);
|
mcspi = spi_master_get_devdata(master);
|
||||||
@ -287,7 +287,12 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
|
|||||||
if (t->len % bytes_per_word != 0)
|
if (t->len % bytes_per_word != 0)
|
||||||
goto disable_fifo;
|
goto disable_fifo;
|
||||||
|
|
||||||
fifo_depth = gcd(t->len, OMAP2_MCSPI_MAX_FIFODEPTH);
|
if (t->rx_buf != NULL && t->tx_buf != NULL)
|
||||||
|
max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2;
|
||||||
|
else
|
||||||
|
max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH;
|
||||||
|
|
||||||
|
fifo_depth = gcd(t->len, max_fifo_depth);
|
||||||
if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0)
|
if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0)
|
||||||
goto disable_fifo;
|
goto disable_fifo;
|
||||||
|
|
||||||
@ -299,7 +304,8 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
|
|||||||
if (t->rx_buf != NULL) {
|
if (t->rx_buf != NULL) {
|
||||||
chconf |= OMAP2_MCSPI_CHCONF_FFER;
|
chconf |= OMAP2_MCSPI_CHCONF_FFER;
|
||||||
xferlevel |= (fifo_depth - 1) << 8;
|
xferlevel |= (fifo_depth - 1) << 8;
|
||||||
} else {
|
}
|
||||||
|
if (t->tx_buf != NULL) {
|
||||||
chconf |= OMAP2_MCSPI_CHCONF_FFET;
|
chconf |= OMAP2_MCSPI_CHCONF_FFET;
|
||||||
xferlevel |= fifo_depth - 1;
|
xferlevel |= fifo_depth - 1;
|
||||||
}
|
}
|
||||||
@ -498,7 +504,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
|||||||
((u32 *)xfer->rx_buf)[elements++] = w;
|
((u32 *)xfer->rx_buf)[elements++] = w;
|
||||||
} else {
|
} else {
|
||||||
int bytes_per_word = mcspi_bytes_per_word(word_len);
|
int bytes_per_word = mcspi_bytes_per_word(word_len);
|
||||||
dev_err(&spi->dev, "DMA RX penultimate word empty");
|
dev_err(&spi->dev, "DMA RX penultimate word empty\n");
|
||||||
count -= (bytes_per_word << 1);
|
count -= (bytes_per_word << 1);
|
||||||
omap2_mcspi_set_enable(spi, 1);
|
omap2_mcspi_set_enable(spi, 1);
|
||||||
return count;
|
return count;
|
||||||
@ -516,7 +522,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
|||||||
else /* word_len <= 32 */
|
else /* word_len <= 32 */
|
||||||
((u32 *)xfer->rx_buf)[elements] = w;
|
((u32 *)xfer->rx_buf)[elements] = w;
|
||||||
} else {
|
} else {
|
||||||
dev_err(&spi->dev, "DMA RX last word empty");
|
dev_err(&spi->dev, "DMA RX last word empty\n");
|
||||||
count -= mcspi_bytes_per_word(word_len);
|
count -= mcspi_bytes_per_word(word_len);
|
||||||
}
|
}
|
||||||
omap2_mcspi_set_enable(spi, 1);
|
omap2_mcspi_set_enable(spi, 1);
|
||||||
@ -1407,7 +1413,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
|||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto disable_pm;
|
goto disable_pm;
|
||||||
|
|
||||||
status = spi_register_master(master);
|
status = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto disable_pm;
|
goto disable_pm;
|
||||||
|
|
||||||
@ -1435,7 +1441,6 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
|
|||||||
pm_runtime_put_sync(mcspi->dev);
|
pm_runtime_put_sync(mcspi->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
kfree(dma_channels);
|
kfree(dma_channels);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -84,8 +84,8 @@ static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size)
|
|||||||
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
|
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
|
||||||
ORION_SPI_IF_8_16_BIT_MODE);
|
ORION_SPI_IF_8_16_BIT_MODE);
|
||||||
} else {
|
} else {
|
||||||
pr_debug("Bad bits per word value %d (only 8 or 16 are "
|
pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n",
|
||||||
"allowed).\n", size);
|
size);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +407,7 @@ static int orion_spi_probe(struct platform_device *pdev)
|
|||||||
const u32 *iprop;
|
const u32 *iprop;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
master = spi_alloc_master(&pdev->dev, sizeof *spi);
|
master = spi_alloc_master(&pdev->dev, sizeof(*spi));
|
||||||
if (master == NULL) {
|
if (master == NULL) {
|
||||||
dev_dbg(&pdev->dev, "master allocation failed\n");
|
dev_dbg(&pdev->dev, "master allocation failed\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -457,7 +457,7 @@ static int orion_spi_probe(struct platform_device *pdev)
|
|||||||
goto out_rel_clk;
|
goto out_rel_clk;
|
||||||
|
|
||||||
master->dev.of_node = pdev->dev.of_node;
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
status = spi_register_master(master);
|
status = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto out_rel_clk;
|
goto out_rel_clk;
|
||||||
|
|
||||||
@ -483,8 +483,6 @@ static int orion_spi_remove(struct platform_device *pdev)
|
|||||||
clk_disable_unprepare(spi->clk);
|
clk_disable_unprepare(spi->clk);
|
||||||
clk_put(spi->clk);
|
clk_put(spi->clk);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1619,7 +1619,6 @@ static int verify_controller_parameters(struct pl022 *pl022,
|
|||||||
dev_err(&pl022->adev->dev,
|
dev_err(&pl022->adev->dev,
|
||||||
"RX FIFO Trigger Level is configured incorrectly\n");
|
"RX FIFO Trigger Level is configured incorrectly\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
switch (chip_info->tx_lev_trig) {
|
switch (chip_info->tx_lev_trig) {
|
||||||
case SSP_TX_1_OR_MORE_EMPTY_LOC:
|
case SSP_TX_1_OR_MORE_EMPTY_LOC:
|
||||||
@ -1645,7 +1644,6 @@ static int verify_controller_parameters(struct pl022 *pl022,
|
|||||||
dev_err(&pl022->adev->dev,
|
dev_err(&pl022->adev->dev,
|
||||||
"TX FIFO Trigger Level is configured incorrectly\n");
|
"TX FIFO Trigger Level is configured incorrectly\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
|
if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
|
||||||
if ((chip_info->ctrl_len < SSP_BITS_4)
|
if ((chip_info->ctrl_len < SSP_BITS_4)
|
||||||
@ -2175,8 +2173,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
status = -ENOMEM;
|
status = -ENOMEM;
|
||||||
goto err_no_ioremap;
|
goto err_no_ioremap;
|
||||||
}
|
}
|
||||||
printk(KERN_INFO "pl022: mapped registers from %pa to %p\n",
|
dev_info(&adev->dev, "mapped registers from %pa to %p\n",
|
||||||
&adev->res.start, pl022->virtbase);
|
&adev->res.start, pl022->virtbase);
|
||||||
|
|
||||||
pl022->clk = devm_clk_get(&adev->dev, NULL);
|
pl022->clk = devm_clk_get(&adev->dev, NULL);
|
||||||
if (IS_ERR(pl022->clk)) {
|
if (IS_ERR(pl022->clk)) {
|
||||||
@ -2227,7 +2225,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
|
|
||||||
/* Register with the SPI framework */
|
/* Register with the SPI framework */
|
||||||
amba_set_drvdata(adev, pl022);
|
amba_set_drvdata(adev, pl022);
|
||||||
status = spi_register_master(master);
|
status = devm_spi_register_master(&adev->dev, master);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
dev_err(&adev->dev,
|
dev_err(&adev->dev,
|
||||||
"probe - problem registering spi master\n");
|
"probe - problem registering spi master\n");
|
||||||
@ -2287,8 +2285,6 @@ pl022_remove(struct amba_device *adev)
|
|||||||
clk_unprepare(pl022->clk);
|
clk_unprepare(pl022->clk);
|
||||||
amba_release_regions(adev);
|
amba_release_regions(adev);
|
||||||
tasklet_disable(&pl022->pump_transfers);
|
tasklet_disable(&pl022->pump_transfers);
|
||||||
spi_unregister_master(pl022->master);
|
|
||||||
amba_set_drvdata(adev, NULL);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +396,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
|
|||||||
master->dev.of_node = np;
|
master->dev.of_node = np;
|
||||||
platform_set_drvdata(op, master);
|
platform_set_drvdata(op, master);
|
||||||
hw = spi_master_get_devdata(master);
|
hw = spi_master_get_devdata(master);
|
||||||
hw->master = spi_master_get(master);
|
hw->master = master;
|
||||||
hw->dev = dev;
|
hw->dev = dev;
|
||||||
|
|
||||||
init_completion(&hw->done);
|
init_completion(&hw->done);
|
||||||
@ -558,6 +558,7 @@ static int spi_ppc4xx_of_remove(struct platform_device *op)
|
|||||||
free_irq(hw->irqnum, hw);
|
free_irq(hw->irqnum, hw);
|
||||||
iounmap(hw->regs);
|
iounmap(hw->regs);
|
||||||
free_gpios(hw);
|
free_gpios(hw);
|
||||||
|
spi_master_put(master);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,8 +573,8 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
|
|||||||
write_SSTO(0, reg);
|
write_SSTO(0, reg);
|
||||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||||
|
|
||||||
dev_err(&drv_data->pdev->dev, "bad message state "
|
dev_err(&drv_data->pdev->dev,
|
||||||
"in interrupt handler\n");
|
"bad message state in interrupt handler\n");
|
||||||
|
|
||||||
/* Never fail */
|
/* Never fail */
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
@ -651,8 +651,8 @@ static void pump_transfers(unsigned long data)
|
|||||||
if (message->is_dma_mapped
|
if (message->is_dma_mapped
|
||||||
|| transfer->rx_dma || transfer->tx_dma) {
|
|| transfer->rx_dma || transfer->tx_dma) {
|
||||||
dev_err(&drv_data->pdev->dev,
|
dev_err(&drv_data->pdev->dev,
|
||||||
"pump_transfers: mapped transfer length "
|
"pump_transfers: mapped transfer length of "
|
||||||
"of %u is greater than %d\n",
|
"%u is greater than %d\n",
|
||||||
transfer->len, MAX_DMA_LEN);
|
transfer->len, MAX_DMA_LEN);
|
||||||
message->status = -EINVAL;
|
message->status = -EINVAL;
|
||||||
giveback(drv_data);
|
giveback(drv_data);
|
||||||
@ -660,11 +660,10 @@ static void pump_transfers(unsigned long data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* warn ... we force this to PIO mode */
|
/* warn ... we force this to PIO mode */
|
||||||
if (printk_ratelimit())
|
dev_warn_ratelimited(&message->spi->dev,
|
||||||
dev_warn(&message->spi->dev, "pump_transfers: "
|
"pump_transfers: DMA disabled for transfer length %ld "
|
||||||
"DMA disabled for transfer length %ld "
|
"greater than %d\n",
|
||||||
"greater than %d\n",
|
(long)drv_data->len, MAX_DMA_LEN);
|
||||||
(long)drv_data->len, MAX_DMA_LEN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup the transfer state based on the type of transfer */
|
/* Setup the transfer state based on the type of transfer */
|
||||||
@ -726,11 +725,8 @@ static void pump_transfers(unsigned long data)
|
|||||||
message->spi,
|
message->spi,
|
||||||
bits, &dma_burst,
|
bits, &dma_burst,
|
||||||
&dma_thresh))
|
&dma_thresh))
|
||||||
if (printk_ratelimit())
|
dev_warn_ratelimited(&message->spi->dev,
|
||||||
dev_warn(&message->spi->dev,
|
"pump_transfers: DMA burst size reduced to match bits_per_word\n");
|
||||||
"pump_transfers: "
|
|
||||||
"DMA burst size reduced to "
|
|
||||||
"match bits_per_word\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cr0 = clk_div
|
cr0 = clk_div
|
||||||
@ -854,8 +850,8 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
|
|||||||
if (gpio_is_valid(chip_info->gpio_cs)) {
|
if (gpio_is_valid(chip_info->gpio_cs)) {
|
||||||
err = gpio_request(chip_info->gpio_cs, "SPI_CS");
|
err = gpio_request(chip_info->gpio_cs, "SPI_CS");
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&spi->dev, "failed to request chip select "
|
dev_err(&spi->dev, "failed to request chip select GPIO%d\n",
|
||||||
"GPIO%d\n", chip_info->gpio_cs);
|
chip_info->gpio_cs);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -899,8 +895,8 @@ static int setup(struct spi_device *spi)
|
|||||||
|
|
||||||
if (drv_data->ssp_type == CE4100_SSP) {
|
if (drv_data->ssp_type == CE4100_SSP) {
|
||||||
if (spi->chip_select > 4) {
|
if (spi->chip_select > 4) {
|
||||||
dev_err(&spi->dev, "failed setup: "
|
dev_err(&spi->dev,
|
||||||
"cs number must not be > 4.\n");
|
"failed setup: cs number must not be > 4.\n");
|
||||||
kfree(chip);
|
kfree(chip);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -956,8 +952,8 @@ static int setup(struct spi_device *spi)
|
|||||||
spi->bits_per_word,
|
spi->bits_per_word,
|
||||||
&chip->dma_burst_size,
|
&chip->dma_burst_size,
|
||||||
&chip->dma_threshold)) {
|
&chip->dma_threshold)) {
|
||||||
dev_warn(&spi->dev, "in setup: DMA burst size reduced "
|
dev_warn(&spi->dev,
|
||||||
"to match bits_per_word\n");
|
"in setup: DMA burst size reduced to match bits_per_word\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1205,7 +1201,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* Register with the SPI framework */
|
/* Register with the SPI framework */
|
||||||
platform_set_drvdata(pdev, drv_data);
|
platform_set_drvdata(pdev, drv_data);
|
||||||
status = spi_register_master(master);
|
status = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
dev_err(&pdev->dev, "problem registering spi master\n");
|
dev_err(&pdev->dev, "problem registering spi master\n");
|
||||||
goto out_error_clock_enabled;
|
goto out_error_clock_enabled;
|
||||||
@ -1257,9 +1253,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
|
|||||||
/* Release SSP */
|
/* Release SSP */
|
||||||
pxa_ssp_free(ssp);
|
pxa_ssp_free(ssp);
|
||||||
|
|
||||||
/* Disconnect from the SPI framework */
|
|
||||||
spi_unregister_master(drv_data->master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,14 @@
|
|||||||
#define RSPI_SPCMD6 0x1c
|
#define RSPI_SPCMD6 0x1c
|
||||||
#define RSPI_SPCMD7 0x1e
|
#define RSPI_SPCMD7 0x1e
|
||||||
|
|
||||||
|
/*qspi only */
|
||||||
|
#define QSPI_SPBFCR 0x18
|
||||||
|
#define QSPI_SPBDCR 0x1a
|
||||||
|
#define QSPI_SPBMUL0 0x1c
|
||||||
|
#define QSPI_SPBMUL1 0x20
|
||||||
|
#define QSPI_SPBMUL2 0x24
|
||||||
|
#define QSPI_SPBMUL3 0x28
|
||||||
|
|
||||||
/* SPCR */
|
/* SPCR */
|
||||||
#define SPCR_SPRIE 0x80
|
#define SPCR_SPRIE 0x80
|
||||||
#define SPCR_SPE 0x40
|
#define SPCR_SPE 0x40
|
||||||
@ -126,6 +134,8 @@
|
|||||||
#define SPCMD_LSBF 0x1000
|
#define SPCMD_LSBF 0x1000
|
||||||
#define SPCMD_SPB_MASK 0x0f00
|
#define SPCMD_SPB_MASK 0x0f00
|
||||||
#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
|
#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
|
||||||
|
#define SPCMD_SPB_8BIT 0x0000 /* qspi only */
|
||||||
|
#define SPCMD_SPB_16BIT 0x0100
|
||||||
#define SPCMD_SPB_20BIT 0x0000
|
#define SPCMD_SPB_20BIT 0x0000
|
||||||
#define SPCMD_SPB_24BIT 0x0100
|
#define SPCMD_SPB_24BIT 0x0100
|
||||||
#define SPCMD_SPB_32BIT 0x0200
|
#define SPCMD_SPB_32BIT 0x0200
|
||||||
@ -135,6 +145,10 @@
|
|||||||
#define SPCMD_CPOL 0x0002
|
#define SPCMD_CPOL 0x0002
|
||||||
#define SPCMD_CPHA 0x0001
|
#define SPCMD_CPHA 0x0001
|
||||||
|
|
||||||
|
/* SPBFCR */
|
||||||
|
#define SPBFCR_TXRST 0x80 /* qspi only */
|
||||||
|
#define SPBFCR_RXRST 0x40 /* qspi only */
|
||||||
|
|
||||||
struct rspi_data {
|
struct rspi_data {
|
||||||
void __iomem *addr;
|
void __iomem *addr;
|
||||||
u32 max_speed_hz;
|
u32 max_speed_hz;
|
||||||
@ -145,6 +159,7 @@ struct rspi_data {
|
|||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
unsigned char spsr;
|
unsigned char spsr;
|
||||||
|
const struct spi_ops *ops;
|
||||||
|
|
||||||
/* for dmaengine */
|
/* for dmaengine */
|
||||||
struct dma_chan *chan_tx;
|
struct dma_chan *chan_tx;
|
||||||
@ -165,6 +180,11 @@ static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset)
|
|||||||
iowrite16(data, rspi->addr + offset);
|
iowrite16(data, rspi->addr + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rspi_write32(struct rspi_data *rspi, u32 data, u16 offset)
|
||||||
|
{
|
||||||
|
iowrite32(data, rspi->addr + offset);
|
||||||
|
}
|
||||||
|
|
||||||
static u8 rspi_read8(struct rspi_data *rspi, u16 offset)
|
static u8 rspi_read8(struct rspi_data *rspi, u16 offset)
|
||||||
{
|
{
|
||||||
return ioread8(rspi->addr + offset);
|
return ioread8(rspi->addr + offset);
|
||||||
@ -175,17 +195,103 @@ static u16 rspi_read16(struct rspi_data *rspi, u16 offset)
|
|||||||
return ioread16(rspi->addr + offset);
|
return ioread16(rspi->addr + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char rspi_calc_spbr(struct rspi_data *rspi)
|
/* optional functions */
|
||||||
|
struct spi_ops {
|
||||||
|
int (*set_config_register)(struct rspi_data *rspi, int access_size);
|
||||||
|
int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg,
|
||||||
|
struct spi_transfer *t);
|
||||||
|
int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg,
|
||||||
|
struct spi_transfer *t);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* functions for RSPI
|
||||||
|
*/
|
||||||
|
static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
|
||||||
{
|
{
|
||||||
int tmp;
|
int spbr;
|
||||||
unsigned char spbr;
|
|
||||||
|
|
||||||
tmp = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
|
/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
|
||||||
spbr = clamp(tmp, 0, 255);
|
rspi_write8(rspi, 0x00, RSPI_SPPCR);
|
||||||
|
|
||||||
return spbr;
|
/* Sets transfer bit rate */
|
||||||
|
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
|
||||||
|
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
|
||||||
|
|
||||||
|
/* Sets number of frames to be used: 1 frame */
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPDCR);
|
||||||
|
|
||||||
|
/* Sets RSPCK, SSL, next-access delay value */
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPCKD);
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SSLND);
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPND);
|
||||||
|
|
||||||
|
/* Sets parity, interrupt mask */
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPCR2);
|
||||||
|
|
||||||
|
/* Sets SPCMD */
|
||||||
|
rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP,
|
||||||
|
RSPI_SPCMD0);
|
||||||
|
|
||||||
|
/* Sets RSPI mode */
|
||||||
|
rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* functions for QSPI
|
||||||
|
*/
|
||||||
|
static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
|
||||||
|
{
|
||||||
|
u16 spcmd;
|
||||||
|
int spbr;
|
||||||
|
|
||||||
|
/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPPCR);
|
||||||
|
|
||||||
|
/* Sets transfer bit rate */
|
||||||
|
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
|
||||||
|
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
|
||||||
|
|
||||||
|
/* Sets number of frames to be used: 1 frame */
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPDCR);
|
||||||
|
|
||||||
|
/* Sets RSPCK, SSL, next-access delay value */
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPCKD);
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SSLND);
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPND);
|
||||||
|
|
||||||
|
/* Data Length Setting */
|
||||||
|
if (access_size == 8)
|
||||||
|
spcmd = SPCMD_SPB_8BIT;
|
||||||
|
else if (access_size == 16)
|
||||||
|
spcmd = SPCMD_SPB_16BIT;
|
||||||
|
else if (access_size == 32)
|
||||||
|
spcmd = SPCMD_SPB_32BIT;
|
||||||
|
|
||||||
|
spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SSLKP | SPCMD_SPNDEN;
|
||||||
|
|
||||||
|
/* Resets transfer data length */
|
||||||
|
rspi_write32(rspi, 0, QSPI_SPBMUL0);
|
||||||
|
|
||||||
|
/* Resets transmit and receive buffer */
|
||||||
|
rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
|
||||||
|
/* Sets buffer to allow normal operation */
|
||||||
|
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
|
||||||
|
|
||||||
|
/* Sets SPCMD */
|
||||||
|
rspi_write16(rspi, spcmd, RSPI_SPCMD0);
|
||||||
|
|
||||||
|
/* Enables SPI function in a master mode */
|
||||||
|
rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define set_config_register(spi, n) spi->ops->set_config_register(spi, n)
|
||||||
|
|
||||||
static void rspi_enable_irq(struct rspi_data *rspi, u8 enable)
|
static void rspi_enable_irq(struct rspi_data *rspi, u8 enable)
|
||||||
{
|
{
|
||||||
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR);
|
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR);
|
||||||
@ -220,35 +326,6 @@ static void rspi_negate_ssl(struct rspi_data *rspi)
|
|||||||
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
|
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
|
|
||||||
{
|
|
||||||
/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
|
|
||||||
rspi_write8(rspi, 0x00, RSPI_SPPCR);
|
|
||||||
|
|
||||||
/* Sets transfer bit rate */
|
|
||||||
rspi_write8(rspi, rspi_calc_spbr(rspi), RSPI_SPBR);
|
|
||||||
|
|
||||||
/* Sets number of frames to be used: 1 frame */
|
|
||||||
rspi_write8(rspi, 0x00, RSPI_SPDCR);
|
|
||||||
|
|
||||||
/* Sets RSPCK, SSL, next-access delay value */
|
|
||||||
rspi_write8(rspi, 0x00, RSPI_SPCKD);
|
|
||||||
rspi_write8(rspi, 0x00, RSPI_SSLND);
|
|
||||||
rspi_write8(rspi, 0x00, RSPI_SPND);
|
|
||||||
|
|
||||||
/* Sets parity, interrupt mask */
|
|
||||||
rspi_write8(rspi, 0x00, RSPI_SPCR2);
|
|
||||||
|
|
||||||
/* Sets SPCMD */
|
|
||||||
rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP,
|
|
||||||
RSPI_SPCMD0);
|
|
||||||
|
|
||||||
/* Sets RSPI mode */
|
|
||||||
rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
|
static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
|
||||||
struct spi_transfer *t)
|
struct spi_transfer *t)
|
||||||
{
|
{
|
||||||
@ -277,6 +354,43 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
|
||||||
|
struct spi_transfer *t)
|
||||||
|
{
|
||||||
|
int remain = t->len;
|
||||||
|
u8 *data;
|
||||||
|
|
||||||
|
rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
|
||||||
|
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
|
||||||
|
|
||||||
|
data = (u8 *)t->tx_buf;
|
||||||
|
while (remain > 0) {
|
||||||
|
|
||||||
|
if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
|
||||||
|
dev_err(&rspi->master->dev,
|
||||||
|
"%s: tx empty timeout\n", __func__);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
rspi_write8(rspi, *data++, RSPI_SPDR);
|
||||||
|
|
||||||
|
if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
|
||||||
|
dev_err(&rspi->master->dev,
|
||||||
|
"%s: receive timeout\n", __func__);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
rspi_read8(rspi, RSPI_SPDR);
|
||||||
|
|
||||||
|
remain--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Waiting for the last transmition */
|
||||||
|
rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
|
||||||
|
|
||||||
static void rspi_dma_complete(void *arg)
|
static void rspi_dma_complete(void *arg)
|
||||||
{
|
{
|
||||||
struct rspi_data *rspi = arg;
|
struct rspi_data *rspi = arg;
|
||||||
@ -442,6 +556,51 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qspi_receive_init(struct rspi_data *rspi)
|
||||||
|
{
|
||||||
|
unsigned char spsr;
|
||||||
|
|
||||||
|
spsr = rspi_read8(rspi, RSPI_SPSR);
|
||||||
|
if (spsr & SPSR_SPRF)
|
||||||
|
rspi_read8(rspi, RSPI_SPDR); /* dummy read */
|
||||||
|
rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
|
||||||
|
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
|
||||||
|
struct spi_transfer *t)
|
||||||
|
{
|
||||||
|
int remain = t->len;
|
||||||
|
u8 *data;
|
||||||
|
|
||||||
|
qspi_receive_init(rspi);
|
||||||
|
|
||||||
|
data = (u8 *)t->rx_buf;
|
||||||
|
while (remain > 0) {
|
||||||
|
|
||||||
|
if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
|
||||||
|
dev_err(&rspi->master->dev,
|
||||||
|
"%s: tx empty timeout\n", __func__);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
/* dummy write for generate clock */
|
||||||
|
rspi_write8(rspi, 0x00, RSPI_SPDR);
|
||||||
|
|
||||||
|
if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
|
||||||
|
dev_err(&rspi->master->dev,
|
||||||
|
"%s: receive timeout\n", __func__);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
/* SPDR allows 8, 16 or 32-bit access */
|
||||||
|
*data++ = rspi_read8(rspi, RSPI_SPDR);
|
||||||
|
remain--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)
|
||||||
|
|
||||||
static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
|
static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
|
||||||
{
|
{
|
||||||
struct scatterlist sg, sg_dummy;
|
struct scatterlist sg, sg_dummy;
|
||||||
@ -581,7 +740,7 @@ static void rspi_work(struct work_struct *work)
|
|||||||
if (rspi_is_dma(rspi, t))
|
if (rspi_is_dma(rspi, t))
|
||||||
ret = rspi_send_dma(rspi, t);
|
ret = rspi_send_dma(rspi, t);
|
||||||
else
|
else
|
||||||
ret = rspi_send_pio(rspi, mesg, t);
|
ret = send_pio(rspi, mesg, t);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -589,7 +748,7 @@ static void rspi_work(struct work_struct *work)
|
|||||||
if (rspi_is_dma(rspi, t))
|
if (rspi_is_dma(rspi, t))
|
||||||
ret = rspi_receive_dma(rspi, t);
|
ret = rspi_receive_dma(rspi, t);
|
||||||
else
|
else
|
||||||
ret = rspi_receive_pio(rspi, mesg, t);
|
ret = receive_pio(rspi, mesg, t);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -616,7 +775,7 @@ static int rspi_setup(struct spi_device *spi)
|
|||||||
spi->bits_per_word = 8;
|
spi->bits_per_word = 8;
|
||||||
rspi->max_speed_hz = spi->max_speed_hz;
|
rspi->max_speed_hz = spi->max_speed_hz;
|
||||||
|
|
||||||
rspi_set_config_register(rspi, 8);
|
set_config_register(rspi, 8);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -745,7 +904,16 @@ static int rspi_probe(struct platform_device *pdev)
|
|||||||
struct rspi_data *rspi;
|
struct rspi_data *rspi;
|
||||||
int ret, irq;
|
int ret, irq;
|
||||||
char clk_name[16];
|
char clk_name[16];
|
||||||
|
struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
|
||||||
|
const struct spi_ops *ops;
|
||||||
|
const struct platform_device_id *id_entry = pdev->id_entry;
|
||||||
|
|
||||||
|
ops = (struct spi_ops *)id_entry->driver_data;
|
||||||
|
/* ops parameter check */
|
||||||
|
if (!ops->set_config_register) {
|
||||||
|
dev_err(&pdev->dev, "there is no set_config_register\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
/* get base addr */
|
/* get base addr */
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (unlikely(res == NULL)) {
|
if (unlikely(res == NULL)) {
|
||||||
@ -767,7 +935,7 @@ static int rspi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
rspi = spi_master_get_devdata(master);
|
rspi = spi_master_get_devdata(master);
|
||||||
platform_set_drvdata(pdev, rspi);
|
platform_set_drvdata(pdev, rspi);
|
||||||
|
rspi->ops = ops;
|
||||||
rspi->master = master;
|
rspi->master = master;
|
||||||
rspi->addr = ioremap(res->start, resource_size(res));
|
rspi->addr = ioremap(res->start, resource_size(res));
|
||||||
if (rspi->addr == NULL) {
|
if (rspi->addr == NULL) {
|
||||||
@ -776,7 +944,7 @@ static int rspi_probe(struct platform_device *pdev)
|
|||||||
goto error1;
|
goto error1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(clk_name, sizeof(clk_name), "rspi%d", pdev->id);
|
snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
|
||||||
rspi->clk = clk_get(&pdev->dev, clk_name);
|
rspi->clk = clk_get(&pdev->dev, clk_name);
|
||||||
if (IS_ERR(rspi->clk)) {
|
if (IS_ERR(rspi->clk)) {
|
||||||
dev_err(&pdev->dev, "cannot get clock\n");
|
dev_err(&pdev->dev, "cannot get clock\n");
|
||||||
@ -790,7 +958,10 @@ static int rspi_probe(struct platform_device *pdev)
|
|||||||
INIT_WORK(&rspi->ws, rspi_work);
|
INIT_WORK(&rspi->ws, rspi_work);
|
||||||
init_waitqueue_head(&rspi->wait);
|
init_waitqueue_head(&rspi->wait);
|
||||||
|
|
||||||
master->num_chipselect = 2;
|
master->num_chipselect = rspi_pd->num_chipselect;
|
||||||
|
if (!master->num_chipselect)
|
||||||
|
master->num_chipselect = 2; /* default */
|
||||||
|
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->setup = rspi_setup;
|
master->setup = rspi_setup;
|
||||||
master->transfer = rspi_transfer;
|
master->transfer = rspi_transfer;
|
||||||
@ -832,11 +1003,32 @@ error1:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct spi_ops rspi_ops = {
|
||||||
|
.set_config_register = rspi_set_config_register,
|
||||||
|
.send_pio = rspi_send_pio,
|
||||||
|
.receive_pio = rspi_receive_pio,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct spi_ops qspi_ops = {
|
||||||
|
.set_config_register = qspi_set_config_register,
|
||||||
|
.send_pio = qspi_send_pio,
|
||||||
|
.receive_pio = qspi_receive_pio,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device_id spi_driver_ids[] = {
|
||||||
|
{ "rspi", (kernel_ulong_t)&rspi_ops },
|
||||||
|
{ "qspi", (kernel_ulong_t)&qspi_ops },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
|
||||||
|
|
||||||
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,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "rspi",
|
.name = "renesas_spi",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -280,7 +280,7 @@ static inline u32 ack_bit(unsigned int irq)
|
|||||||
* so the caller does not need to do anything more than start the transfer
|
* so the caller does not need to do anything more than start the transfer
|
||||||
* as normal, since the IRQ will have been re-routed to the FIQ handler.
|
* as normal, since the IRQ will have been re-routed to the FIQ handler.
|
||||||
*/
|
*/
|
||||||
void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw)
|
static void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw)
|
||||||
{
|
{
|
||||||
struct pt_regs regs;
|
struct pt_regs regs;
|
||||||
enum spi_fiq_mode mode;
|
enum spi_fiq_mode mode;
|
||||||
@ -524,7 +524,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
|
|||||||
hw = spi_master_get_devdata(master);
|
hw = spi_master_get_devdata(master);
|
||||||
memset(hw, 0, sizeof(struct s3c24xx_spi));
|
memset(hw, 0, sizeof(struct s3c24xx_spi));
|
||||||
|
|
||||||
hw->master = spi_master_get(master);
|
hw->master = master;
|
||||||
hw->pdata = pdata = dev_get_platdata(&pdev->dev);
|
hw->pdata = pdata = dev_get_platdata(&pdev->dev);
|
||||||
hw->dev = &pdev->dev;
|
hw->dev = &pdev->dev;
|
||||||
|
|
||||||
|
@ -205,7 +205,6 @@ struct s3c64xx_spi_driver_data {
|
|||||||
#endif
|
#endif
|
||||||
struct s3c64xx_spi_port_config *port_conf;
|
struct s3c64xx_spi_port_config *port_conf;
|
||||||
unsigned int port_id;
|
unsigned int port_id;
|
||||||
unsigned long gpios[4];
|
|
||||||
bool cs_gpio;
|
bool cs_gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -559,25 +558,18 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
|
|||||||
static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
|
static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
|
||||||
struct spi_device *spi)
|
struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct s3c64xx_spi_csinfo *cs;
|
|
||||||
|
|
||||||
if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
|
if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
|
||||||
if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
|
if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
|
||||||
/* Deselect the last toggled device */
|
/* Deselect the last toggled device */
|
||||||
cs = sdd->tgl_spi->controller_data;
|
if (spi->cs_gpio >= 0)
|
||||||
if (sdd->cs_gpio)
|
gpio_set_value(spi->cs_gpio,
|
||||||
gpio_set_value(cs->line,
|
|
||||||
spi->mode & SPI_CS_HIGH ? 0 : 1);
|
spi->mode & SPI_CS_HIGH ? 0 : 1);
|
||||||
}
|
}
|
||||||
sdd->tgl_spi = NULL;
|
sdd->tgl_spi = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cs = spi->controller_data;
|
if (spi->cs_gpio >= 0)
|
||||||
if (sdd->cs_gpio)
|
gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0);
|
||||||
gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
|
|
||||||
|
|
||||||
/* Start the signals */
|
|
||||||
writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
|
static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
|
||||||
@ -702,16 +694,11 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
|
|||||||
static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
|
static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
|
||||||
struct spi_device *spi)
|
struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
|
|
||||||
|
|
||||||
if (sdd->tgl_spi == spi)
|
if (sdd->tgl_spi == spi)
|
||||||
sdd->tgl_spi = NULL;
|
sdd->tgl_spi = NULL;
|
||||||
|
|
||||||
if (sdd->cs_gpio)
|
if (spi->cs_gpio >= 0)
|
||||||
gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
|
gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
|
||||||
|
|
||||||
/* Quiese the signals */
|
|
||||||
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
||||||
@ -862,16 +849,12 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
|
static int s3c64xx_spi_prepare_message(struct spi_master *master,
|
||||||
struct spi_message *msg)
|
struct spi_message *msg)
|
||||||
{
|
{
|
||||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||||
struct spi_device *spi = msg->spi;
|
struct spi_device *spi = msg->spi;
|
||||||
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
|
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
|
||||||
struct spi_transfer *xfer;
|
|
||||||
int status = 0, cs_toggle = 0;
|
|
||||||
u32 speed;
|
|
||||||
u8 bpw;
|
|
||||||
|
|
||||||
/* If Master's(controller) state differs from that needed by Slave */
|
/* If Master's(controller) state differs from that needed by Slave */
|
||||||
if (sdd->cur_speed != spi->max_speed_hz
|
if (sdd->cur_speed != spi->max_speed_hz
|
||||||
@ -887,107 +870,99 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
|
|||||||
if (s3c64xx_spi_map_mssg(sdd, msg)) {
|
if (s3c64xx_spi_map_mssg(sdd, msg)) {
|
||||||
dev_err(&spi->dev,
|
dev_err(&spi->dev,
|
||||||
"Xfer: Unable to map message buffers!\n");
|
"Xfer: Unable to map message buffers!\n");
|
||||||
status = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure feedback delay */
|
/* Configure feedback delay */
|
||||||
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
|
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
|
||||||
|
|
||||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long flags;
|
static int s3c64xx_spi_transfer_one(struct spi_master *master,
|
||||||
int use_dma;
|
struct spi_device *spi,
|
||||||
|
struct spi_transfer *xfer)
|
||||||
|
{
|
||||||
|
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||||
|
int status;
|
||||||
|
u32 speed;
|
||||||
|
u8 bpw;
|
||||||
|
unsigned long flags;
|
||||||
|
int use_dma;
|
||||||
|
|
||||||
INIT_COMPLETION(sdd->xfer_completion);
|
INIT_COMPLETION(sdd->xfer_completion);
|
||||||
|
|
||||||
/* Only BPW and Speed may change across transfers */
|
/* Only BPW and Speed may change across transfers */
|
||||||
bpw = xfer->bits_per_word;
|
bpw = xfer->bits_per_word;
|
||||||
speed = xfer->speed_hz ? : spi->max_speed_hz;
|
speed = xfer->speed_hz ? : spi->max_speed_hz;
|
||||||
|
|
||||||
if (xfer->len % (bpw / 8)) {
|
if (xfer->len % (bpw / 8)) {
|
||||||
dev_err(&spi->dev,
|
dev_err(&spi->dev,
|
||||||
"Xfer length(%u) not a multiple of word size(%u)\n",
|
"Xfer length(%u) not a multiple of word size(%u)\n",
|
||||||
xfer->len, bpw / 8);
|
xfer->len, bpw / 8);
|
||||||
status = -EIO;
|
return -EIO;
|
||||||
goto out;
|
}
|
||||||
|
|
||||||
|
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
|
||||||
|
sdd->cur_bpw = bpw;
|
||||||
|
sdd->cur_speed = speed;
|
||||||
|
s3c64xx_spi_config(sdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Polling method for xfers not bigger than FIFO capacity */
|
||||||
|
use_dma = 0;
|
||||||
|
if (!is_polling(sdd) &&
|
||||||
|
(sdd->rx_dma.ch && sdd->tx_dma.ch &&
|
||||||
|
(xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1))))
|
||||||
|
use_dma = 1;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&sdd->lock, flags);
|
||||||
|
|
||||||
|
/* Pending only which is to be done */
|
||||||
|
sdd->state &= ~RXBUSY;
|
||||||
|
sdd->state &= ~TXBUSY;
|
||||||
|
|
||||||
|
enable_datapath(sdd, spi, xfer, use_dma);
|
||||||
|
|
||||||
|
/* Start the signals */
|
||||||
|
writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||||
|
|
||||||
|
/* Start the signals */
|
||||||
|
writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&sdd->lock, flags);
|
||||||
|
|
||||||
|
status = wait_for_xfer(sdd, xfer, use_dma);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
|
||||||
|
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
|
||||||
|
(sdd->state & RXBUSY) ? 'f' : 'p',
|
||||||
|
(sdd->state & TXBUSY) ? 'f' : 'p',
|
||||||
|
xfer->len);
|
||||||
|
|
||||||
|
if (use_dma) {
|
||||||
|
if (xfer->tx_buf != NULL
|
||||||
|
&& (sdd->state & TXBUSY))
|
||||||
|
s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
|
||||||
|
if (xfer->rx_buf != NULL
|
||||||
|
&& (sdd->state & RXBUSY))
|
||||||
|
s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
|
|
||||||
sdd->cur_bpw = bpw;
|
|
||||||
sdd->cur_speed = speed;
|
|
||||||
s3c64xx_spi_config(sdd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Polling method for xfers not bigger than FIFO capacity */
|
|
||||||
use_dma = 0;
|
|
||||||
if (!is_polling(sdd) &&
|
|
||||||
(sdd->rx_dma.ch && sdd->tx_dma.ch &&
|
|
||||||
(xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1))))
|
|
||||||
use_dma = 1;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&sdd->lock, flags);
|
|
||||||
|
|
||||||
/* Pending only which is to be done */
|
|
||||||
sdd->state &= ~RXBUSY;
|
|
||||||
sdd->state &= ~TXBUSY;
|
|
||||||
|
|
||||||
enable_datapath(sdd, spi, xfer, use_dma);
|
|
||||||
|
|
||||||
/* Slave Select */
|
|
||||||
enable_cs(sdd, spi);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&sdd->lock, flags);
|
|
||||||
|
|
||||||
status = wait_for_xfer(sdd, xfer, use_dma);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
|
|
||||||
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
|
|
||||||
(sdd->state & RXBUSY) ? 'f' : 'p',
|
|
||||||
(sdd->state & TXBUSY) ? 'f' : 'p',
|
|
||||||
xfer->len);
|
|
||||||
|
|
||||||
if (use_dma) {
|
|
||||||
if (xfer->tx_buf != NULL
|
|
||||||
&& (sdd->state & TXBUSY))
|
|
||||||
s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
|
|
||||||
if (xfer->rx_buf != NULL
|
|
||||||
&& (sdd->state & RXBUSY))
|
|
||||||
s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
|
|
||||||
}
|
|
||||||
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xfer->delay_usecs)
|
|
||||||
udelay(xfer->delay_usecs);
|
|
||||||
|
|
||||||
if (xfer->cs_change) {
|
|
||||||
/* Hint that the next mssg is gonna be
|
|
||||||
for the same device */
|
|
||||||
if (list_is_last(&xfer->transfer_list,
|
|
||||||
&msg->transfers))
|
|
||||||
cs_toggle = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->actual_length += xfer->len;
|
|
||||||
|
|
||||||
flush_fifo(sdd);
|
flush_fifo(sdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
return status;
|
||||||
if (!cs_toggle || status)
|
}
|
||||||
disable_cs(sdd, spi);
|
|
||||||
else
|
static int s3c64xx_spi_unprepare_message(struct spi_master *master,
|
||||||
sdd->tgl_spi = spi;
|
struct spi_message *msg)
|
||||||
|
{
|
||||||
|
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||||
|
|
||||||
s3c64xx_spi_unmap_mssg(sdd, msg);
|
s3c64xx_spi_unmap_mssg(sdd, msg);
|
||||||
|
|
||||||
msg->status = status;
|
|
||||||
|
|
||||||
spi_finalize_current_message(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1071,6 +1046,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
|||||||
cs->line, err);
|
cs->line, err);
|
||||||
goto err_gpio_req;
|
goto err_gpio_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spi->cs_gpio = cs->line;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_set_ctldata(spi, cs);
|
spi_set_ctldata(spi, cs);
|
||||||
@ -1117,11 +1094,14 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_put(&sdd->pdev->dev);
|
pm_runtime_put(&sdd->pdev->dev);
|
||||||
|
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||||
disable_cs(sdd, spi);
|
disable_cs(sdd, spi);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
setup_exit:
|
setup_exit:
|
||||||
|
pm_runtime_put(&sdd->pdev->dev);
|
||||||
/* setup() returns with device de-selected */
|
/* setup() returns with device de-selected */
|
||||||
|
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||||
disable_cs(sdd, spi);
|
disable_cs(sdd, spi);
|
||||||
|
|
||||||
gpio_free(cs->line);
|
gpio_free(cs->line);
|
||||||
@ -1140,8 +1120,8 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi)
|
|||||||
struct s3c64xx_spi_driver_data *sdd;
|
struct s3c64xx_spi_driver_data *sdd;
|
||||||
|
|
||||||
sdd = spi_master_get_devdata(spi->master);
|
sdd = spi_master_get_devdata(spi->master);
|
||||||
if (cs && sdd->cs_gpio) {
|
if (spi->cs_gpio) {
|
||||||
gpio_free(cs->line);
|
gpio_free(spi->cs_gpio);
|
||||||
if (spi->dev.of_node)
|
if (spi->dev.of_node)
|
||||||
kfree(cs);
|
kfree(cs);
|
||||||
}
|
}
|
||||||
@ -1359,7 +1339,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||||||
master->setup = s3c64xx_spi_setup;
|
master->setup = s3c64xx_spi_setup;
|
||||||
master->cleanup = s3c64xx_spi_cleanup;
|
master->cleanup = s3c64xx_spi_cleanup;
|
||||||
master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
|
master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
|
||||||
master->transfer_one_message = s3c64xx_spi_transfer_one_message;
|
master->prepare_message = s3c64xx_spi_prepare_message;
|
||||||
|
master->transfer_one = s3c64xx_spi_transfer_one;
|
||||||
|
master->unprepare_message = s3c64xx_spi_unprepare_message;
|
||||||
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
|
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
|
||||||
master->num_chipselect = sci->num_cs;
|
master->num_chipselect = sci->num_cs;
|
||||||
master->dma_alignment = 8;
|
master->dma_alignment = 8;
|
||||||
@ -1428,11 +1410,12 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||||||
S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
|
S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
|
||||||
sdd->regs + S3C64XX_SPI_INT_EN);
|
sdd->regs + S3C64XX_SPI_INT_EN);
|
||||||
|
|
||||||
|
pm_runtime_set_active(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
|
||||||
if (spi_register_master(master)) {
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
dev_err(&pdev->dev, "cannot register SPI master\n");
|
if (ret != 0) {
|
||||||
ret = -EBUSY;
|
dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret);
|
||||||
goto err3;
|
goto err3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1461,16 +1444,12 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
|
writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
|
||||||
|
|
||||||
clk_disable_unprepare(sdd->src_clk);
|
clk_disable_unprepare(sdd->src_clk);
|
||||||
|
|
||||||
clk_disable_unprepare(sdd->clk);
|
clk_disable_unprepare(sdd->clk);
|
||||||
|
|
||||||
spi_master_put(master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1480,11 +1459,14 @@ static int s3c64xx_spi_suspend(struct device *dev)
|
|||||||
struct spi_master *master = dev_get_drvdata(dev);
|
struct spi_master *master = dev_get_drvdata(dev);
|
||||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spi_master_suspend(master);
|
int ret = spi_master_suspend(master);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Disable the clock */
|
if (!pm_runtime_suspended(dev)) {
|
||||||
clk_disable_unprepare(sdd->src_clk);
|
clk_disable_unprepare(sdd->clk);
|
||||||
clk_disable_unprepare(sdd->clk);
|
clk_disable_unprepare(sdd->src_clk);
|
||||||
|
}
|
||||||
|
|
||||||
sdd->cur_speed = 0; /* Output Clock is stopped */
|
sdd->cur_speed = 0; /* Output Clock is stopped */
|
||||||
|
|
||||||
@ -1500,15 +1482,14 @@ static int s3c64xx_spi_resume(struct device *dev)
|
|||||||
if (sci->cfg_gpio)
|
if (sci->cfg_gpio)
|
||||||
sci->cfg_gpio();
|
sci->cfg_gpio();
|
||||||
|
|
||||||
/* Enable the clock */
|
if (!pm_runtime_suspended(dev)) {
|
||||||
clk_prepare_enable(sdd->src_clk);
|
clk_prepare_enable(sdd->src_clk);
|
||||||
clk_prepare_enable(sdd->clk);
|
clk_prepare_enable(sdd->clk);
|
||||||
|
}
|
||||||
|
|
||||||
s3c64xx_spi_hwinit(sdd, sdd->port_id);
|
s3c64xx_spi_hwinit(sdd, sdd->port_id);
|
||||||
|
|
||||||
spi_master_resume(master);
|
return spi_master_resume(master);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
@ -1528,9 +1509,17 @@ static int s3c64xx_spi_runtime_resume(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct spi_master *master = dev_get_drvdata(dev);
|
struct spi_master *master = dev_get_drvdata(dev);
|
||||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||||
|
int ret;
|
||||||
|
|
||||||
clk_prepare_enable(sdd->src_clk);
|
ret = clk_prepare_enable(sdd->src_clk);
|
||||||
clk_prepare_enable(sdd->clk);
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(sdd->clk);
|
||||||
|
if (ret != 0) {
|
||||||
|
clk_disable_unprepare(sdd->src_clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1616,6 +1605,18 @@ static struct platform_device_id s3c64xx_spi_driver_ids[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id s3c64xx_spi_dt_match[] = {
|
static const struct of_device_id s3c64xx_spi_dt_match[] = {
|
||||||
|
{ .compatible = "samsung,s3c2443-spi",
|
||||||
|
.data = (void *)&s3c2443_spi_port_config,
|
||||||
|
},
|
||||||
|
{ .compatible = "samsung,s3c6410-spi",
|
||||||
|
.data = (void *)&s3c6410_spi_port_config,
|
||||||
|
},
|
||||||
|
{ .compatible = "samsung,s5pc100-spi",
|
||||||
|
.data = (void *)&s5pc100_spi_port_config,
|
||||||
|
},
|
||||||
|
{ .compatible = "samsung,s5pv210-spi",
|
||||||
|
.data = (void *)&s5pv210_spi_port_config,
|
||||||
|
},
|
||||||
{ .compatible = "samsung,exynos4210-spi",
|
{ .compatible = "samsung,exynos4210-spi",
|
||||||
.data = (void *)&exynos4_spi_port_config,
|
.data = (void *)&exynos4_spi_port_config,
|
||||||
},
|
},
|
||||||
@ -1633,22 +1634,13 @@ static struct platform_driver s3c64xx_spi_driver = {
|
|||||||
.pm = &s3c64xx_spi_pm,
|
.pm = &s3c64xx_spi_pm,
|
||||||
.of_match_table = of_match_ptr(s3c64xx_spi_dt_match),
|
.of_match_table = of_match_ptr(s3c64xx_spi_dt_match),
|
||||||
},
|
},
|
||||||
|
.probe = s3c64xx_spi_probe,
|
||||||
.remove = s3c64xx_spi_remove,
|
.remove = s3c64xx_spi_remove,
|
||||||
.id_table = s3c64xx_spi_driver_ids,
|
.id_table = s3c64xx_spi_driver_ids,
|
||||||
};
|
};
|
||||||
MODULE_ALIAS("platform:s3c64xx-spi");
|
MODULE_ALIAS("platform:s3c64xx-spi");
|
||||||
|
|
||||||
static int __init s3c64xx_spi_init(void)
|
module_platform_driver(s3c64xx_spi_driver);
|
||||||
{
|
|
||||||
return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe);
|
|
||||||
}
|
|
||||||
subsys_initcall(s3c64xx_spi_init);
|
|
||||||
|
|
||||||
static void __exit s3c64xx_spi_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&s3c64xx_spi_driver);
|
|
||||||
}
|
|
||||||
module_exit(s3c64xx_spi_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
|
MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
|
||||||
MODULE_DESCRIPTION("S3C64XX SPI Controller Driver");
|
MODULE_DESCRIPTION("S3C64XX SPI Controller Driver");
|
||||||
|
@ -137,7 +137,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
|
|||||||
rate /= 16;
|
rate /= 16;
|
||||||
|
|
||||||
/* CLKCx calculation */
|
/* CLKCx calculation */
|
||||||
rate /= (((idiv_clk & 0x1F) + 1) * 2) ;
|
rate /= (((idiv_clk & 0x1F) + 1) * 2);
|
||||||
|
|
||||||
/* save best settings */
|
/* save best settings */
|
||||||
tmp = abs(target_rate - rate);
|
tmp = abs(target_rate - rate);
|
||||||
@ -303,9 +303,10 @@ static int hspi_probe(struct platform_device *pdev)
|
|||||||
master->setup = hspi_setup;
|
master->setup = hspi_setup;
|
||||||
master->cleanup = hspi_cleanup;
|
master->cleanup = hspi_cleanup;
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||||
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
master->auto_runtime_pm = true;
|
master->auto_runtime_pm = true;
|
||||||
master->transfer_one_message = hspi_transfer_one_message;
|
master->transfer_one_message = hspi_transfer_one_message;
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "spi_register_master error.\n");
|
dev_err(&pdev->dev, "spi_register_master error.\n");
|
||||||
goto error1;
|
goto error1;
|
||||||
@ -328,17 +329,23 @@ static int hspi_remove(struct platform_device *pdev)
|
|||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
clk_put(hspi->clk);
|
clk_put(hspi->clk);
|
||||||
spi_unregister_master(hspi->master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct of_device_id hspi_of_match[] = {
|
||||||
|
{ .compatible = "renesas,hspi", },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, hspi_of_match);
|
||||||
|
|
||||||
static struct platform_driver hspi_driver = {
|
static struct platform_driver hspi_driver = {
|
||||||
.probe = hspi_probe,
|
.probe = hspi_probe,
|
||||||
.remove = hspi_remove,
|
.remove = hspi_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sh-hspi",
|
.name = "sh-hspi",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = hspi_of_match,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
module_platform_driver(hspi_driver);
|
module_platform_driver(hspi_driver);
|
||||||
|
@ -133,7 +133,7 @@ static int sh_sci_spi_probe(struct platform_device *dev)
|
|||||||
sp->info = dev_get_platdata(&dev->dev);
|
sp->info = dev_get_platdata(&dev->dev);
|
||||||
|
|
||||||
/* setup spi bitbang adaptor */
|
/* setup spi bitbang adaptor */
|
||||||
sp->bitbang.master = spi_master_get(master);
|
sp->bitbang.master = master;
|
||||||
sp->bitbang.master->bus_num = sp->info->bus_num;
|
sp->bitbang.master->bus_num = sp->info->bus_num;
|
||||||
sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
|
sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
|
||||||
sp->bitbang.chipselect = sh_sci_spi_chipselect;
|
sp->bitbang.chipselect = sh_sci_spi_chipselect;
|
||||||
|
@ -632,7 +632,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto free_master;
|
goto free_master;
|
||||||
|
|
||||||
sspi->bitbang.master = spi_master_get(master);
|
sspi->bitbang.master = master;
|
||||||
sspi->bitbang.chipselect = spi_sirfsoc_chipselect;
|
sspi->bitbang.chipselect = spi_sirfsoc_chipselect;
|
||||||
sspi->bitbang.setup_transfer = spi_sirfsoc_setup_transfer;
|
sspi->bitbang.setup_transfer = spi_sirfsoc_setup_transfer;
|
||||||
sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
|
sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
|
||||||
|
@ -182,6 +182,7 @@ struct tegra_spi_data {
|
|||||||
u32 cur_speed;
|
u32 cur_speed;
|
||||||
|
|
||||||
struct spi_device *cur_spi;
|
struct spi_device *cur_spi;
|
||||||
|
struct spi_device *cs_control;
|
||||||
unsigned cur_pos;
|
unsigned cur_pos;
|
||||||
unsigned cur_len;
|
unsigned cur_len;
|
||||||
unsigned words_per_32bit;
|
unsigned words_per_32bit;
|
||||||
@ -267,7 +268,7 @@ static unsigned tegra_spi_calculate_curr_xfer_param(
|
|||||||
unsigned max_len;
|
unsigned max_len;
|
||||||
unsigned total_fifo_words;
|
unsigned total_fifo_words;
|
||||||
|
|
||||||
tspi->bytes_per_word = (bits_per_word - 1) / 8 + 1;
|
tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8);
|
||||||
|
|
||||||
if (bits_per_word == 8 || bits_per_word == 16) {
|
if (bits_per_word == 8 || bits_per_word == 16) {
|
||||||
tspi->is_packed = 1;
|
tspi->is_packed = 1;
|
||||||
@ -676,15 +677,12 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
|
|||||||
dma_release_channel(dma_chan);
|
dma_release_channel(dma_chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra_spi_start_transfer_one(struct spi_device *spi,
|
static unsigned long tegra_spi_setup_transfer_one(struct spi_device *spi,
|
||||||
struct spi_transfer *t, bool is_first_of_msg,
|
struct spi_transfer *t, bool is_first_of_msg)
|
||||||
bool is_single_xfer)
|
|
||||||
{
|
{
|
||||||
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
||||||
u32 speed = t->speed_hz;
|
u32 speed = t->speed_hz;
|
||||||
u8 bits_per_word = t->bits_per_word;
|
u8 bits_per_word = t->bits_per_word;
|
||||||
unsigned total_fifo_words;
|
|
||||||
int ret;
|
|
||||||
unsigned long command1;
|
unsigned long command1;
|
||||||
int req_mode;
|
int req_mode;
|
||||||
|
|
||||||
@ -698,7 +696,6 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
|
|||||||
tspi->cur_rx_pos = 0;
|
tspi->cur_rx_pos = 0;
|
||||||
tspi->cur_tx_pos = 0;
|
tspi->cur_tx_pos = 0;
|
||||||
tspi->curr_xfer = t;
|
tspi->curr_xfer = t;
|
||||||
total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t);
|
|
||||||
|
|
||||||
if (is_first_of_msg) {
|
if (is_first_of_msg) {
|
||||||
tegra_spi_clear_status(tspi);
|
tegra_spi_clear_status(tspi);
|
||||||
@ -717,7 +714,12 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
|
|||||||
else if (req_mode == SPI_MODE_3)
|
else if (req_mode == SPI_MODE_3)
|
||||||
command1 |= SPI_CONTROL_MODE_3;
|
command1 |= SPI_CONTROL_MODE_3;
|
||||||
|
|
||||||
tegra_spi_writel(tspi, command1, SPI_COMMAND1);
|
if (tspi->cs_control) {
|
||||||
|
if (tspi->cs_control != spi)
|
||||||
|
tegra_spi_writel(tspi, command1, SPI_COMMAND1);
|
||||||
|
tspi->cs_control = NULL;
|
||||||
|
} else
|
||||||
|
tegra_spi_writel(tspi, command1, SPI_COMMAND1);
|
||||||
|
|
||||||
command1 |= SPI_CS_SW_HW;
|
command1 |= SPI_CS_SW_HW;
|
||||||
if (spi->mode & SPI_CS_HIGH)
|
if (spi->mode & SPI_CS_HIGH)
|
||||||
@ -732,6 +734,18 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
|
|||||||
command1 |= SPI_BIT_LENGTH(bits_per_word - 1);
|
command1 |= SPI_BIT_LENGTH(bits_per_word - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return command1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_spi_start_transfer_one(struct spi_device *spi,
|
||||||
|
struct spi_transfer *t, unsigned long command1)
|
||||||
|
{
|
||||||
|
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
||||||
|
unsigned total_fifo_words;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t);
|
||||||
|
|
||||||
if (tspi->is_packed)
|
if (tspi->is_packed)
|
||||||
command1 |= SPI_PACKED;
|
command1 |= SPI_PACKED;
|
||||||
|
|
||||||
@ -803,29 +817,50 @@ static int tegra_spi_setup(struct spi_device *spi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tegra_spi_transfer_delay(int delay)
|
||||||
|
{
|
||||||
|
if (!delay)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (delay >= 1000)
|
||||||
|
mdelay(delay / 1000);
|
||||||
|
|
||||||
|
udelay(delay % 1000);
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra_spi_transfer_one_message(struct spi_master *master,
|
static int tegra_spi_transfer_one_message(struct spi_master *master,
|
||||||
struct spi_message *msg)
|
struct spi_message *msg)
|
||||||
{
|
{
|
||||||
bool is_first_msg = true;
|
bool is_first_msg = true;
|
||||||
int single_xfer;
|
|
||||||
struct tegra_spi_data *tspi = spi_master_get_devdata(master);
|
struct tegra_spi_data *tspi = spi_master_get_devdata(master);
|
||||||
struct spi_transfer *xfer;
|
struct spi_transfer *xfer;
|
||||||
struct spi_device *spi = msg->spi;
|
struct spi_device *spi = msg->spi;
|
||||||
int ret;
|
int ret;
|
||||||
|
bool skip = false;
|
||||||
|
|
||||||
msg->status = 0;
|
msg->status = 0;
|
||||||
msg->actual_length = 0;
|
msg->actual_length = 0;
|
||||||
|
|
||||||
single_xfer = list_is_singular(&msg->transfers);
|
|
||||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||||
|
unsigned long cmd1;
|
||||||
|
|
||||||
INIT_COMPLETION(tspi->xfer_completion);
|
INIT_COMPLETION(tspi->xfer_completion);
|
||||||
ret = tegra_spi_start_transfer_one(spi, xfer,
|
|
||||||
is_first_msg, single_xfer);
|
cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg);
|
||||||
|
|
||||||
|
if (!xfer->len) {
|
||||||
|
ret = 0;
|
||||||
|
skip = true;
|
||||||
|
goto complete_xfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tegra_spi_start_transfer_one(spi, xfer, cmd1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(tspi->dev,
|
dev_err(tspi->dev,
|
||||||
"spi can not start transfer, err %d\n", ret);
|
"spi can not start transfer, err %d\n", ret);
|
||||||
goto exit;
|
goto complete_xfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_first_msg = false;
|
is_first_msg = false;
|
||||||
ret = wait_for_completion_timeout(&tspi->xfer_completion,
|
ret = wait_for_completion_timeout(&tspi->xfer_completion,
|
||||||
SPI_DMA_TIMEOUT);
|
SPI_DMA_TIMEOUT);
|
||||||
@ -833,24 +868,40 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
|
|||||||
dev_err(tspi->dev,
|
dev_err(tspi->dev,
|
||||||
"spi trasfer timeout, err %d\n", ret);
|
"spi trasfer timeout, err %d\n", ret);
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto exit;
|
goto complete_xfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tspi->tx_status || tspi->rx_status) {
|
if (tspi->tx_status || tspi->rx_status) {
|
||||||
dev_err(tspi->dev, "Error in Transfer\n");
|
dev_err(tspi->dev, "Error in Transfer\n");
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto exit;
|
goto complete_xfer;
|
||||||
}
|
}
|
||||||
msg->actual_length += xfer->len;
|
msg->actual_length += xfer->len;
|
||||||
if (xfer->cs_change && xfer->delay_usecs) {
|
|
||||||
|
complete_xfer:
|
||||||
|
if (ret < 0 || skip) {
|
||||||
tegra_spi_writel(tspi, tspi->def_command1_reg,
|
tegra_spi_writel(tspi, tspi->def_command1_reg,
|
||||||
SPI_COMMAND1);
|
SPI_COMMAND1);
|
||||||
udelay(xfer->delay_usecs);
|
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||||
|
goto exit;
|
||||||
|
} else if (msg->transfers.prev == &xfer->transfer_list) {
|
||||||
|
/* This is the last transfer in message */
|
||||||
|
if (xfer->cs_change)
|
||||||
|
tspi->cs_control = spi;
|
||||||
|
else {
|
||||||
|
tegra_spi_writel(tspi, tspi->def_command1_reg,
|
||||||
|
SPI_COMMAND1);
|
||||||
|
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||||
|
}
|
||||||
|
} else if (xfer->cs_change) {
|
||||||
|
tegra_spi_writel(tspi, tspi->def_command1_reg,
|
||||||
|
SPI_COMMAND1);
|
||||||
|
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
exit:
|
exit:
|
||||||
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
|
|
||||||
msg->status = ret;
|
msg->status = ret;
|
||||||
spi_finalize_current_message(master);
|
spi_finalize_current_message(master);
|
||||||
return ret;
|
return ret;
|
||||||
@ -1115,7 +1166,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
|||||||
pm_runtime_put(&pdev->dev);
|
pm_runtime_put(&pdev->dev);
|
||||||
|
|
||||||
master->dev.of_node = pdev->dev.of_node;
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
||||||
goto exit_pm_disable;
|
goto exit_pm_disable;
|
||||||
@ -1142,7 +1193,6 @@ static int tegra_spi_remove(struct platform_device *pdev)
|
|||||||
struct tegra_spi_data *tspi = spi_master_get_devdata(master);
|
struct tegra_spi_data *tspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
free_irq(tspi->irq, tspi);
|
free_irq(tspi->irq, tspi);
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
if (tspi->tx_dma_chan)
|
if (tspi->tx_dma_chan)
|
||||||
tegra_spi_deinit_dma_param(tspi, false);
|
tegra_spi_deinit_dma_param(tspi, false);
|
||||||
|
@ -173,7 +173,7 @@ static unsigned tegra_sflash_calculate_curr_xfer_param(
|
|||||||
unsigned remain_len = t->len - tsd->cur_pos;
|
unsigned remain_len = t->len - tsd->cur_pos;
|
||||||
unsigned max_word;
|
unsigned max_word;
|
||||||
|
|
||||||
tsd->bytes_per_word = (t->bits_per_word - 1) / 8 + 1;
|
tsd->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);
|
||||||
max_word = remain_len / tsd->bytes_per_word;
|
max_word = remain_len / tsd->bytes_per_word;
|
||||||
if (max_word > SPI_FIFO_DEPTH)
|
if (max_word > SPI_FIFO_DEPTH)
|
||||||
max_word = SPI_FIFO_DEPTH;
|
max_word = SPI_FIFO_DEPTH;
|
||||||
@ -529,7 +529,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
|
|||||||
pm_runtime_put(&pdev->dev);
|
pm_runtime_put(&pdev->dev);
|
||||||
|
|
||||||
master->dev.of_node = pdev->dev.of_node;
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
||||||
goto exit_pm_disable;
|
goto exit_pm_disable;
|
||||||
@ -553,7 +553,6 @@ static int tegra_sflash_remove(struct platform_device *pdev)
|
|||||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
||||||
|
|
||||||
free_irq(tsd->irq, tsd);
|
free_irq(tsd->irq, tsd);
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||||
|
@ -278,12 +278,12 @@ static unsigned tegra_slink_calculate_curr_xfer_param(
|
|||||||
{
|
{
|
||||||
unsigned remain_len = t->len - tspi->cur_pos;
|
unsigned remain_len = t->len - tspi->cur_pos;
|
||||||
unsigned max_word;
|
unsigned max_word;
|
||||||
unsigned bits_per_word ;
|
unsigned bits_per_word;
|
||||||
unsigned max_len;
|
unsigned max_len;
|
||||||
unsigned total_fifo_words;
|
unsigned total_fifo_words;
|
||||||
|
|
||||||
bits_per_word = t->bits_per_word;
|
bits_per_word = t->bits_per_word;
|
||||||
tspi->bytes_per_word = (bits_per_word - 1) / 8 + 1;
|
tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8);
|
||||||
|
|
||||||
if (bits_per_word == 8 || bits_per_word == 16) {
|
if (bits_per_word == 8 || bits_per_word == 16) {
|
||||||
tspi->is_packed = 1;
|
tspi->is_packed = 1;
|
||||||
@ -707,8 +707,7 @@ static void tegra_slink_deinit_dma_param(struct tegra_slink_data *tspi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int tegra_slink_start_transfer_one(struct spi_device *spi,
|
static int tegra_slink_start_transfer_one(struct spi_device *spi,
|
||||||
struct spi_transfer *t, bool is_first_of_msg,
|
struct spi_transfer *t)
|
||||||
bool is_single_xfer)
|
|
||||||
{
|
{
|
||||||
struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master);
|
struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master);
|
||||||
u32 speed;
|
u32 speed;
|
||||||
@ -732,32 +731,12 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi,
|
|||||||
tspi->curr_xfer = t;
|
tspi->curr_xfer = t;
|
||||||
total_fifo_words = tegra_slink_calculate_curr_xfer_param(spi, tspi, t);
|
total_fifo_words = tegra_slink_calculate_curr_xfer_param(spi, tspi, t);
|
||||||
|
|
||||||
if (is_first_of_msg) {
|
command = tspi->command_reg;
|
||||||
tegra_slink_clear_status(tspi);
|
command &= ~SLINK_BIT_LENGTH(~0);
|
||||||
|
command |= SLINK_BIT_LENGTH(bits_per_word - 1);
|
||||||
|
|
||||||
command = tspi->def_command_reg;
|
command2 = tspi->command2_reg;
|
||||||
command |= SLINK_BIT_LENGTH(bits_per_word - 1);
|
command2 &= ~(SLINK_RXEN | SLINK_TXEN);
|
||||||
command |= SLINK_CS_SW | SLINK_CS_VALUE;
|
|
||||||
|
|
||||||
command2 = tspi->def_command2_reg;
|
|
||||||
command2 |= SLINK_SS_EN_CS(spi->chip_select);
|
|
||||||
|
|
||||||
command &= ~SLINK_MODES;
|
|
||||||
if (spi->mode & SPI_CPHA)
|
|
||||||
command |= SLINK_CK_SDA;
|
|
||||||
|
|
||||||
if (spi->mode & SPI_CPOL)
|
|
||||||
command |= SLINK_IDLE_SCLK_DRIVE_HIGH;
|
|
||||||
else
|
|
||||||
command |= SLINK_IDLE_SCLK_DRIVE_LOW;
|
|
||||||
} else {
|
|
||||||
command = tspi->command_reg;
|
|
||||||
command &= ~SLINK_BIT_LENGTH(~0);
|
|
||||||
command |= SLINK_BIT_LENGTH(bits_per_word - 1);
|
|
||||||
|
|
||||||
command2 = tspi->command2_reg;
|
|
||||||
command2 &= ~(SLINK_RXEN | SLINK_TXEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
tegra_slink_writel(tspi, command, SLINK_COMMAND);
|
tegra_slink_writel(tspi, command, SLINK_COMMAND);
|
||||||
tspi->command_reg = command;
|
tspi->command_reg = command;
|
||||||
@ -824,58 +803,72 @@ static int tegra_slink_setup(struct spi_device *spi)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra_slink_transfer_one_message(struct spi_master *master,
|
static int tegra_slink_prepare_message(struct spi_master *master,
|
||||||
struct spi_message *msg)
|
struct spi_message *msg)
|
||||||
{
|
{
|
||||||
bool is_first_msg = true;
|
|
||||||
int single_xfer;
|
|
||||||
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
||||||
struct spi_transfer *xfer;
|
|
||||||
struct spi_device *spi = msg->spi;
|
struct spi_device *spi = msg->spi;
|
||||||
|
|
||||||
|
tegra_slink_clear_status(tspi);
|
||||||
|
|
||||||
|
tspi->command_reg = tspi->def_command_reg;
|
||||||
|
tspi->command_reg |= SLINK_CS_SW | SLINK_CS_VALUE;
|
||||||
|
|
||||||
|
tspi->command2_reg = tspi->def_command2_reg;
|
||||||
|
tspi->command2_reg |= SLINK_SS_EN_CS(spi->chip_select);
|
||||||
|
|
||||||
|
tspi->command_reg &= ~SLINK_MODES;
|
||||||
|
if (spi->mode & SPI_CPHA)
|
||||||
|
tspi->command_reg |= SLINK_CK_SDA;
|
||||||
|
|
||||||
|
if (spi->mode & SPI_CPOL)
|
||||||
|
tspi->command_reg |= SLINK_IDLE_SCLK_DRIVE_HIGH;
|
||||||
|
else
|
||||||
|
tspi->command_reg |= SLINK_IDLE_SCLK_DRIVE_LOW;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_slink_transfer_one(struct spi_master *master,
|
||||||
|
struct spi_device *spi,
|
||||||
|
struct spi_transfer *xfer)
|
||||||
|
{
|
||||||
|
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
msg->status = 0;
|
INIT_COMPLETION(tspi->xfer_completion);
|
||||||
msg->actual_length = 0;
|
ret = tegra_slink_start_transfer_one(spi, xfer);
|
||||||
|
if (ret < 0) {
|
||||||
single_xfer = list_is_singular(&msg->transfers);
|
dev_err(tspi->dev,
|
||||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
"spi can not start transfer, err %d\n", ret);
|
||||||
INIT_COMPLETION(tspi->xfer_completion);
|
return ret;
|
||||||
ret = tegra_slink_start_transfer_one(spi, xfer,
|
|
||||||
is_first_msg, single_xfer);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(tspi->dev,
|
|
||||||
"spi can not start transfer, err %d\n", ret);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
is_first_msg = false;
|
|
||||||
ret = wait_for_completion_timeout(&tspi->xfer_completion,
|
|
||||||
SLINK_DMA_TIMEOUT);
|
|
||||||
if (WARN_ON(ret == 0)) {
|
|
||||||
dev_err(tspi->dev,
|
|
||||||
"spi trasfer timeout, err %d\n", ret);
|
|
||||||
ret = -EIO;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tspi->tx_status || tspi->rx_status) {
|
|
||||||
dev_err(tspi->dev, "Error in Transfer\n");
|
|
||||||
ret = -EIO;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
msg->actual_length += xfer->len;
|
|
||||||
if (xfer->cs_change && xfer->delay_usecs) {
|
|
||||||
tegra_slink_writel(tspi, tspi->def_command_reg,
|
|
||||||
SLINK_COMMAND);
|
|
||||||
udelay(xfer->delay_usecs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ret = 0;
|
|
||||||
exit:
|
ret = wait_for_completion_timeout(&tspi->xfer_completion,
|
||||||
|
SLINK_DMA_TIMEOUT);
|
||||||
|
if (WARN_ON(ret == 0)) {
|
||||||
|
dev_err(tspi->dev,
|
||||||
|
"spi trasfer timeout, err %d\n", ret);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tspi->tx_status)
|
||||||
|
return tspi->tx_status;
|
||||||
|
if (tspi->rx_status)
|
||||||
|
return tspi->rx_status;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_slink_unprepare_message(struct spi_master *master,
|
||||||
|
struct spi_message *msg)
|
||||||
|
{
|
||||||
|
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
|
tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
|
||||||
tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
|
tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
|
||||||
msg->status = ret;
|
|
||||||
spi_finalize_current_message(master);
|
return 0;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t handle_cpu_based_xfer(struct tegra_slink_data *tspi)
|
static irqreturn_t handle_cpu_based_xfer(struct tegra_slink_data *tspi)
|
||||||
@ -1078,7 +1071,9 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
|||||||
/* the spi->mode bits understood by this driver: */
|
/* the spi->mode bits understood by this driver: */
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||||
master->setup = tegra_slink_setup;
|
master->setup = tegra_slink_setup;
|
||||||
master->transfer_one_message = tegra_slink_transfer_one_message;
|
master->prepare_message = tegra_slink_prepare_message;
|
||||||
|
master->transfer_one = tegra_slink_transfer_one;
|
||||||
|
master->unprepare_message = tegra_slink_unprepare_message;
|
||||||
master->auto_runtime_pm = true;
|
master->auto_runtime_pm = true;
|
||||||
master->num_chipselect = MAX_CHIP_SELECT;
|
master->num_chipselect = MAX_CHIP_SELECT;
|
||||||
master->bus_num = -1;
|
master->bus_num = -1;
|
||||||
@ -1164,7 +1159,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
|||||||
pm_runtime_put(&pdev->dev);
|
pm_runtime_put(&pdev->dev);
|
||||||
|
|
||||||
master->dev.of_node = pdev->dev.of_node;
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
||||||
goto exit_pm_disable;
|
goto exit_pm_disable;
|
||||||
@ -1191,7 +1186,6 @@ static int tegra_slink_remove(struct platform_device *pdev)
|
|||||||
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
free_irq(tspi->irq, tspi);
|
free_irq(tspi->irq, tspi);
|
||||||
spi_unregister_master(master);
|
|
||||||
|
|
||||||
if (tspi->tx_dma_chan)
|
if (tspi->tx_dma_chan)
|
||||||
tegra_slink_deinit_dma_param(tspi, false);
|
tegra_slink_deinit_dma_param(tspi, false);
|
||||||
|
@ -41,9 +41,6 @@ struct ti_qspi_regs {
|
|||||||
struct ti_qspi {
|
struct ti_qspi {
|
||||||
struct completion transfer_complete;
|
struct completion transfer_complete;
|
||||||
|
|
||||||
/* IRQ synchronization */
|
|
||||||
spinlock_t lock;
|
|
||||||
|
|
||||||
/* list synchronization */
|
/* list synchronization */
|
||||||
struct mutex list_lock;
|
struct mutex list_lock;
|
||||||
|
|
||||||
@ -57,7 +54,6 @@ struct ti_qspi {
|
|||||||
u32 spi_max_frequency;
|
u32 spi_max_frequency;
|
||||||
u32 cmd;
|
u32 cmd;
|
||||||
u32 dc;
|
u32 dc;
|
||||||
u32 stat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define QSPI_PID (0x0)
|
#define QSPI_PID (0x0)
|
||||||
@ -397,13 +393,12 @@ static irqreturn_t ti_qspi_isr(int irq, void *dev_id)
|
|||||||
{
|
{
|
||||||
struct ti_qspi *qspi = dev_id;
|
struct ti_qspi *qspi = dev_id;
|
||||||
u16 int_stat;
|
u16 int_stat;
|
||||||
|
u32 stat;
|
||||||
|
|
||||||
irqreturn_t ret = IRQ_HANDLED;
|
irqreturn_t ret = IRQ_HANDLED;
|
||||||
|
|
||||||
spin_lock(&qspi->lock);
|
|
||||||
|
|
||||||
int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR);
|
int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR);
|
||||||
qspi->stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
|
stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
|
||||||
|
|
||||||
if (!int_stat) {
|
if (!int_stat) {
|
||||||
dev_dbg(qspi->dev, "No IRQ triggered\n");
|
dev_dbg(qspi->dev, "No IRQ triggered\n");
|
||||||
@ -411,33 +406,12 @@ static irqreturn_t ti_qspi_isr(int irq, void *dev_id)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = IRQ_WAKE_THREAD;
|
|
||||||
|
|
||||||
ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG);
|
|
||||||
ti_qspi_write(qspi, QSPI_WC_INT_DISABLE,
|
ti_qspi_write(qspi, QSPI_WC_INT_DISABLE,
|
||||||
QSPI_INTR_STATUS_ENABLED_CLEAR);
|
QSPI_INTR_STATUS_ENABLED_CLEAR);
|
||||||
|
if (stat & WC)
|
||||||
out:
|
|
||||||
spin_unlock(&qspi->lock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t ti_qspi_threaded_isr(int this_irq, void *dev_id)
|
|
||||||
{
|
|
||||||
struct ti_qspi *qspi = dev_id;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&qspi->lock, flags);
|
|
||||||
|
|
||||||
if (qspi->stat & WC)
|
|
||||||
complete(&qspi->transfer_complete);
|
complete(&qspi->transfer_complete);
|
||||||
|
out:
|
||||||
spin_unlock_irqrestore(&qspi->lock, flags);
|
return ret;
|
||||||
|
|
||||||
ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ti_qspi_runtime_resume(struct device *dev)
|
static int ti_qspi_runtime_resume(struct device *dev)
|
||||||
@ -472,7 +446,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
|
|||||||
if (!master)
|
if (!master)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
|
||||||
|
|
||||||
master->bus_num = -1;
|
master->bus_num = -1;
|
||||||
master->flags = SPI_MASTER_HALF_DUPLEX;
|
master->flags = SPI_MASTER_HALF_DUPLEX;
|
||||||
@ -499,7 +473,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
|
|||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_init(&qspi->lock);
|
|
||||||
mutex_init(&qspi->list_lock);
|
mutex_init(&qspi->list_lock);
|
||||||
|
|
||||||
qspi->base = devm_ioremap_resource(&pdev->dev, r);
|
qspi->base = devm_ioremap_resource(&pdev->dev, r);
|
||||||
@ -508,8 +481,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
|
|||||||
goto free_master;
|
goto free_master;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(&pdev->dev, irq, ti_qspi_isr,
|
ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0,
|
||||||
ti_qspi_threaded_isr, 0,
|
|
||||||
dev_name(&pdev->dev), qspi);
|
dev_name(&pdev->dev), qspi);
|
||||||
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",
|
||||||
@ -532,7 +504,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
|
|||||||
if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
|
if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
|
||||||
qspi->spi_max_frequency = max_freq;
|
qspi->spi_max_frequency = max_freq;
|
||||||
|
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_master;
|
goto free_master;
|
||||||
|
|
||||||
@ -547,7 +519,7 @@ static int ti_qspi_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct ti_qspi *qspi = platform_get_drvdata(pdev);
|
struct ti_qspi *qspi = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
spi_unregister_master(qspi->master);
|
ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -558,7 +530,7 @@ static const struct dev_pm_ops ti_qspi_pm_ops = {
|
|||||||
|
|
||||||
static struct platform_driver ti_qspi_driver = {
|
static struct platform_driver ti_qspi_driver = {
|
||||||
.probe = ti_qspi_probe,
|
.probe = ti_qspi_probe,
|
||||||
.remove = ti_qspi_remove,
|
.remove = ti_qspi_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ti,dra7xxx-qspi",
|
.name = "ti,dra7xxx-qspi",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
@ -506,8 +506,8 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(&pspi->dev, "%s Transfer List not empty. "
|
dev_dbg(&pspi->dev,
|
||||||
"Transfer Speed is set.\n", __func__);
|
"%s Transfer List not empty. Transfer Speed is set.\n", __func__);
|
||||||
|
|
||||||
spin_lock_irqsave(&data->lock, flags);
|
spin_lock_irqsave(&data->lock, flags);
|
||||||
/* validate Tx/Rx buffers and Transfer length */
|
/* validate Tx/Rx buffers and Transfer length */
|
||||||
@ -526,8 +526,9 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
|
|||||||
goto err_return_spinlock;
|
goto err_return_spinlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length"
|
dev_dbg(&pspi->dev,
|
||||||
" valid\n", __func__);
|
"%s Tx/Rx buffer valid. Transfer length valid\n",
|
||||||
|
__func__);
|
||||||
|
|
||||||
/* if baud rate has been specified validate the same */
|
/* if baud rate has been specified validate the same */
|
||||||
if (transfer->speed_hz > PCH_MAX_BAUDRATE)
|
if (transfer->speed_hz > PCH_MAX_BAUDRATE)
|
||||||
@ -1181,8 +1182,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
|
|||||||
spin_lock(&data->lock);
|
spin_lock(&data->lock);
|
||||||
/* check if suspend has been initiated;if yes flush queue */
|
/* check if suspend has been initiated;if yes flush queue */
|
||||||
if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) {
|
if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) {
|
||||||
dev_dbg(&data->master->dev, "%s suspend/remove initiated,"
|
dev_dbg(&data->master->dev,
|
||||||
"flushing queue\n", __func__);
|
"%s suspend/remove initiated, flushing queue\n", __func__);
|
||||||
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
|
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
|
||||||
pmsg->status = -EIO;
|
pmsg->status = -EIO;
|
||||||
|
|
||||||
@ -1410,13 +1411,13 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
|
|||||||
/* baseaddress + address offset) */
|
/* baseaddress + address offset) */
|
||||||
data->io_base_addr = pci_resource_start(board_dat->pdev, 1) +
|
data->io_base_addr = pci_resource_start(board_dat->pdev, 1) +
|
||||||
PCH_ADDRESS_SIZE * plat_dev->id;
|
PCH_ADDRESS_SIZE * plat_dev->id;
|
||||||
data->io_remap_addr = pci_iomap(board_dat->pdev, 1, 0) +
|
data->io_remap_addr = pci_iomap(board_dat->pdev, 1, 0);
|
||||||
PCH_ADDRESS_SIZE * plat_dev->id;
|
|
||||||
if (!data->io_remap_addr) {
|
if (!data->io_remap_addr) {
|
||||||
dev_err(&plat_dev->dev, "%s pci_iomap failed\n", __func__);
|
dev_err(&plat_dev->dev, "%s pci_iomap failed\n", __func__);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_pci_iomap;
|
goto err_pci_iomap;
|
||||||
}
|
}
|
||||||
|
data->io_remap_addr += PCH_ADDRESS_SIZE * plat_dev->id;
|
||||||
|
|
||||||
dev_dbg(&plat_dev->dev, "[ch%d] remap_addr=%p\n",
|
dev_dbg(&plat_dev->dev, "[ch%d] remap_addr=%p\n",
|
||||||
plat_dev->id, data->io_remap_addr);
|
plat_dev->id, data->io_remap_addr);
|
||||||
|
@ -177,7 +177,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
|
|||||||
| 0x08,
|
| 0x08,
|
||||||
TXx9_SPCR0);
|
TXx9_SPCR0);
|
||||||
|
|
||||||
list_for_each_entry (t, &m->transfers, transfer_list) {
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
const void *txbuf = t->tx_buf;
|
const void *txbuf = t->tx_buf;
|
||||||
void *rxbuf = t->rx_buf;
|
void *rxbuf = t->rx_buf;
|
||||||
u32 data;
|
u32 data;
|
||||||
@ -308,7 +308,7 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
|
|||||||
m->actual_length = 0;
|
m->actual_length = 0;
|
||||||
|
|
||||||
/* check each transfer's parameters */
|
/* check each transfer's parameters */
|
||||||
list_for_each_entry (t, &m->transfers, transfer_list) {
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
|
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
|
||||||
u8 bits_per_word = t->bits_per_word;
|
u8 bits_per_word = t->bits_per_word;
|
||||||
|
|
||||||
@ -406,7 +406,7 @@ static int txx9spi_probe(struct platform_device *dev)
|
|||||||
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
|
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
|
||||||
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||||
|
|
||||||
ret = spi_register_master(master);
|
ret = devm_spi_register_master(&dev->dev, master);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto exit;
|
goto exit;
|
||||||
return 0;
|
return 0;
|
||||||
@ -428,11 +428,9 @@ static int txx9spi_remove(struct platform_device *dev)
|
|||||||
struct spi_master *master = spi_master_get(platform_get_drvdata(dev));
|
struct spi_master *master = spi_master_get(platform_get_drvdata(dev));
|
||||||
struct txx9spi *c = spi_master_get_devdata(master);
|
struct txx9spi *c = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
|
||||||
destroy_workqueue(c->workqueue);
|
destroy_workqueue(c->workqueue);
|
||||||
clk_disable(c->clk);
|
clk_disable(c->clk);
|
||||||
clk_put(c->clk);
|
clk_put(c->clk);
|
||||||
spi_master_put(master);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,6 +438,7 @@ static int txx9spi_remove(struct platform_device *dev)
|
|||||||
MODULE_ALIAS("platform:spi_txx9");
|
MODULE_ALIAS("platform:spi_txx9");
|
||||||
|
|
||||||
static struct platform_driver txx9spi_driver = {
|
static struct platform_driver txx9spi_driver = {
|
||||||
|
.probe = txx9spi_probe,
|
||||||
.remove = txx9spi_remove,
|
.remove = txx9spi_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "spi_txx9",
|
.name = "spi_txx9",
|
||||||
@ -449,7 +448,7 @@ static struct platform_driver txx9spi_driver = {
|
|||||||
|
|
||||||
static int __init txx9spi_init(void)
|
static int __init txx9spi_init(void)
|
||||||
{
|
{
|
||||||
return platform_driver_probe(&txx9spi_driver, txx9spi_probe);
|
return platform_driver_register(&txx9spi_driver);
|
||||||
}
|
}
|
||||||
subsys_initcall(txx9spi_init);
|
subsys_initcall(txx9spi_init);
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
|||||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||||
|
|
||||||
xspi = spi_master_get_devdata(master);
|
xspi = spi_master_get_devdata(master);
|
||||||
xspi->bitbang.master = spi_master_get(master);
|
xspi->bitbang.master = master;
|
||||||
xspi->bitbang.chipselect = xilinx_spi_chipselect;
|
xspi->bitbang.chipselect = xilinx_spi_chipselect;
|
||||||
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
|
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
|
||||||
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
|
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
|
||||||
|
#define CREATE_TRACE_POINTS
|
||||||
|
#include <trace/events/spi.h>
|
||||||
|
|
||||||
static void spidev_release(struct device *dev)
|
static void spidev_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct spi_device *spi = to_spi_device(dev);
|
struct spi_device *spi = to_spi_device(dev);
|
||||||
@ -58,11 +61,13 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
|
|||||||
|
|
||||||
return sprintf(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias);
|
return sprintf(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias);
|
||||||
}
|
}
|
||||||
|
static DEVICE_ATTR_RO(modalias);
|
||||||
|
|
||||||
static struct device_attribute spi_dev_attrs[] = {
|
static struct attribute *spi_dev_attrs[] = {
|
||||||
__ATTR_RO(modalias),
|
&dev_attr_modalias.attr,
|
||||||
__ATTR_NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
ATTRIBUTE_GROUPS(spi_dev);
|
||||||
|
|
||||||
/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
|
/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
|
||||||
* and the sysfs version makes coldplug work too.
|
* and the sysfs version makes coldplug work too.
|
||||||
@ -229,7 +234,7 @@ static const struct dev_pm_ops spi_pm = {
|
|||||||
|
|
||||||
struct bus_type spi_bus_type = {
|
struct bus_type spi_bus_type = {
|
||||||
.name = "spi",
|
.name = "spi",
|
||||||
.dev_attrs = spi_dev_attrs,
|
.dev_groups = spi_dev_groups,
|
||||||
.match = spi_match_device,
|
.match = spi_match_device,
|
||||||
.uevent = spi_uevent,
|
.uevent = spi_uevent,
|
||||||
.pm = &spi_pm,
|
.pm = &spi_pm,
|
||||||
@ -323,7 +328,7 @@ struct spi_device *spi_alloc_device(struct spi_master *master)
|
|||||||
if (!spi_master_get(master))
|
if (!spi_master_get(master))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
spi = kzalloc(sizeof *spi, GFP_KERNEL);
|
spi = kzalloc(sizeof(*spi), GFP_KERNEL);
|
||||||
if (!spi) {
|
if (!spi) {
|
||||||
dev_err(dev, "cannot alloc spi_device\n");
|
dev_err(dev, "cannot alloc spi_device\n");
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
@ -523,6 +528,95 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
|
{
|
||||||
|
if (spi->mode & SPI_CS_HIGH)
|
||||||
|
enable = !enable;
|
||||||
|
|
||||||
|
if (spi->cs_gpio >= 0)
|
||||||
|
gpio_set_value(spi->cs_gpio, !enable);
|
||||||
|
else if (spi->master->set_cs)
|
||||||
|
spi->master->set_cs(spi, !enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* spi_transfer_one_message - Default implementation of transfer_one_message()
|
||||||
|
*
|
||||||
|
* This is a standard implementation of transfer_one_message() for
|
||||||
|
* drivers which impelment a transfer_one() operation. It provides
|
||||||
|
* standard handling of delays and chip select management.
|
||||||
|
*/
|
||||||
|
static int spi_transfer_one_message(struct spi_master *master,
|
||||||
|
struct spi_message *msg)
|
||||||
|
{
|
||||||
|
struct spi_transfer *xfer;
|
||||||
|
bool cur_cs = true;
|
||||||
|
bool keep_cs = false;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
spi_set_cs(msg->spi, true);
|
||||||
|
|
||||||
|
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||||
|
trace_spi_transfer_start(msg, xfer);
|
||||||
|
|
||||||
|
INIT_COMPLETION(master->xfer_completion);
|
||||||
|
|
||||||
|
ret = master->transfer_one(master, msg->spi, xfer);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&msg->spi->dev,
|
||||||
|
"SPI transfer failed: %d\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret > 0)
|
||||||
|
wait_for_completion(&master->xfer_completion);
|
||||||
|
|
||||||
|
trace_spi_transfer_stop(msg, xfer);
|
||||||
|
|
||||||
|
if (msg->status != -EINPROGRESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (xfer->delay_usecs)
|
||||||
|
udelay(xfer->delay_usecs);
|
||||||
|
|
||||||
|
if (xfer->cs_change) {
|
||||||
|
if (list_is_last(&xfer->transfer_list,
|
||||||
|
&msg->transfers)) {
|
||||||
|
keep_cs = true;
|
||||||
|
} else {
|
||||||
|
cur_cs = !cur_cs;
|
||||||
|
spi_set_cs(msg->spi, cur_cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->actual_length += xfer->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (ret != 0 || !keep_cs)
|
||||||
|
spi_set_cs(msg->spi, false);
|
||||||
|
|
||||||
|
if (msg->status == -EINPROGRESS)
|
||||||
|
msg->status = ret;
|
||||||
|
|
||||||
|
spi_finalize_current_message(master);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spi_finalize_current_transfer - report completion of a transfer
|
||||||
|
*
|
||||||
|
* Called by SPI drivers using the core transfer_one_message()
|
||||||
|
* implementation to notify it that the current interrupt driven
|
||||||
|
* transfer has finised and the next one may be scheduled.
|
||||||
|
*/
|
||||||
|
void spi_finalize_current_transfer(struct spi_master *master)
|
||||||
|
{
|
||||||
|
complete(&master->xfer_completion);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_pump_messages - kthread work function which processes spi message queue
|
* spi_pump_messages - kthread work function which processes spi message queue
|
||||||
* @work: pointer to kthread work struct contained in the master struct
|
* @work: pointer to kthread work struct contained in the master struct
|
||||||
@ -557,6 +651,7 @@ static void spi_pump_messages(struct kthread_work *work)
|
|||||||
pm_runtime_mark_last_busy(master->dev.parent);
|
pm_runtime_mark_last_busy(master->dev.parent);
|
||||||
pm_runtime_put_autosuspend(master->dev.parent);
|
pm_runtime_put_autosuspend(master->dev.parent);
|
||||||
}
|
}
|
||||||
|
trace_spi_master_idle(master);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,6 +680,9 @@ static void spi_pump_messages(struct kthread_work *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!was_busy)
|
||||||
|
trace_spi_master_busy(master);
|
||||||
|
|
||||||
if (!was_busy && master->prepare_transfer_hardware) {
|
if (!was_busy && master->prepare_transfer_hardware) {
|
||||||
ret = master->prepare_transfer_hardware(master);
|
ret = master->prepare_transfer_hardware(master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -597,6 +695,20 @@ static void spi_pump_messages(struct kthread_work *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace_spi_message_start(master->cur_msg);
|
||||||
|
|
||||||
|
if (master->prepare_message) {
|
||||||
|
ret = master->prepare_message(master, master->cur_msg);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&master->dev,
|
||||||
|
"failed to prepare message: %d\n", ret);
|
||||||
|
master->cur_msg->status = ret;
|
||||||
|
spi_finalize_current_message(master);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
master->cur_msg_prepared = true;
|
||||||
|
}
|
||||||
|
|
||||||
ret = master->transfer_one_message(master, master->cur_msg);
|
ret = master->transfer_one_message(master, master->cur_msg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&master->dev,
|
dev_err(&master->dev,
|
||||||
@ -678,6 +790,7 @@ void spi_finalize_current_message(struct spi_master *master)
|
|||||||
{
|
{
|
||||||
struct spi_message *mesg;
|
struct spi_message *mesg;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&master->queue_lock, flags);
|
spin_lock_irqsave(&master->queue_lock, flags);
|
||||||
mesg = master->cur_msg;
|
mesg = master->cur_msg;
|
||||||
@ -686,9 +799,20 @@ void spi_finalize_current_message(struct spi_master *master)
|
|||||||
queue_kthread_work(&master->kworker, &master->pump_messages);
|
queue_kthread_work(&master->kworker, &master->pump_messages);
|
||||||
spin_unlock_irqrestore(&master->queue_lock, flags);
|
spin_unlock_irqrestore(&master->queue_lock, flags);
|
||||||
|
|
||||||
|
if (master->cur_msg_prepared && master->unprepare_message) {
|
||||||
|
ret = master->unprepare_message(master, mesg);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&master->dev,
|
||||||
|
"failed to unprepare message: %d\n", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
master->cur_msg_prepared = false;
|
||||||
|
|
||||||
mesg->state = NULL;
|
mesg->state = NULL;
|
||||||
if (mesg->complete)
|
if (mesg->complete)
|
||||||
mesg->complete(mesg->context);
|
mesg->complete(mesg->context);
|
||||||
|
|
||||||
|
trace_spi_message_done(mesg);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_finalize_current_message);
|
EXPORT_SYMBOL_GPL(spi_finalize_current_message);
|
||||||
|
|
||||||
@ -803,6 +927,8 @@ static int spi_master_initialize_queue(struct spi_master *master)
|
|||||||
|
|
||||||
master->queued = true;
|
master->queued = true;
|
||||||
master->transfer = spi_queued_transfer;
|
master->transfer = spi_queued_transfer;
|
||||||
|
if (!master->transfer_one_message)
|
||||||
|
master->transfer_one_message = spi_transfer_one_message;
|
||||||
|
|
||||||
/* Initialize and start queue */
|
/* Initialize and start queue */
|
||||||
ret = spi_init_queue(master);
|
ret = spi_init_queue(master);
|
||||||
@ -838,10 +964,8 @@ static void of_register_spi_devices(struct spi_master *master)
|
|||||||
{
|
{
|
||||||
struct spi_device *spi;
|
struct spi_device *spi;
|
||||||
struct device_node *nc;
|
struct device_node *nc;
|
||||||
const __be32 *prop;
|
|
||||||
char modalias[SPI_NAME_SIZE + 4];
|
|
||||||
int rc;
|
int rc;
|
||||||
int len;
|
u32 value;
|
||||||
|
|
||||||
if (!master->dev.of_node)
|
if (!master->dev.of_node)
|
||||||
return;
|
return;
|
||||||
@ -866,14 +990,14 @@ static void of_register_spi_devices(struct spi_master *master)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Device address */
|
/* Device address */
|
||||||
prop = of_get_property(nc, "reg", &len);
|
rc = of_property_read_u32(nc, "reg", &value);
|
||||||
if (!prop || len < sizeof(*prop)) {
|
if (rc) {
|
||||||
dev_err(&master->dev, "%s has no 'reg' property\n",
|
dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
|
||||||
nc->full_name);
|
nc->full_name, rc);
|
||||||
spi_dev_put(spi);
|
spi_dev_put(spi);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
spi->chip_select = be32_to_cpup(prop);
|
spi->chip_select = value;
|
||||||
|
|
||||||
/* Mode (clock phase/polarity/etc.) */
|
/* Mode (clock phase/polarity/etc.) */
|
||||||
if (of_find_property(nc, "spi-cpha", NULL))
|
if (of_find_property(nc, "spi-cpha", NULL))
|
||||||
@ -886,55 +1010,53 @@ static void of_register_spi_devices(struct spi_master *master)
|
|||||||
spi->mode |= SPI_3WIRE;
|
spi->mode |= SPI_3WIRE;
|
||||||
|
|
||||||
/* Device DUAL/QUAD mode */
|
/* Device DUAL/QUAD mode */
|
||||||
prop = of_get_property(nc, "spi-tx-bus-width", &len);
|
if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
|
||||||
if (prop && len == sizeof(*prop)) {
|
switch (value) {
|
||||||
switch (be32_to_cpup(prop)) {
|
case 1:
|
||||||
case SPI_NBITS_SINGLE:
|
|
||||||
break;
|
break;
|
||||||
case SPI_NBITS_DUAL:
|
case 2:
|
||||||
spi->mode |= SPI_TX_DUAL;
|
spi->mode |= SPI_TX_DUAL;
|
||||||
break;
|
break;
|
||||||
case SPI_NBITS_QUAD:
|
case 4:
|
||||||
spi->mode |= SPI_TX_QUAD;
|
spi->mode |= SPI_TX_QUAD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(&master->dev,
|
dev_err(&master->dev,
|
||||||
"spi-tx-bus-width %d not supported\n",
|
"spi-tx-bus-width %d not supported\n",
|
||||||
be32_to_cpup(prop));
|
value);
|
||||||
spi_dev_put(spi);
|
spi_dev_put(spi);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prop = of_get_property(nc, "spi-rx-bus-width", &len);
|
if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
|
||||||
if (prop && len == sizeof(*prop)) {
|
switch (value) {
|
||||||
switch (be32_to_cpup(prop)) {
|
case 1:
|
||||||
case SPI_NBITS_SINGLE:
|
|
||||||
break;
|
break;
|
||||||
case SPI_NBITS_DUAL:
|
case 2:
|
||||||
spi->mode |= SPI_RX_DUAL;
|
spi->mode |= SPI_RX_DUAL;
|
||||||
break;
|
break;
|
||||||
case SPI_NBITS_QUAD:
|
case 4:
|
||||||
spi->mode |= SPI_RX_QUAD;
|
spi->mode |= SPI_RX_QUAD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(&master->dev,
|
dev_err(&master->dev,
|
||||||
"spi-rx-bus-width %d not supported\n",
|
"spi-rx-bus-width %d not supported\n",
|
||||||
be32_to_cpup(prop));
|
value);
|
||||||
spi_dev_put(spi);
|
spi_dev_put(spi);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Device speed */
|
/* Device speed */
|
||||||
prop = of_get_property(nc, "spi-max-frequency", &len);
|
rc = of_property_read_u32(nc, "spi-max-frequency", &value);
|
||||||
if (!prop || len < sizeof(*prop)) {
|
if (rc) {
|
||||||
dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n",
|
dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
|
||||||
nc->full_name);
|
nc->full_name, rc);
|
||||||
spi_dev_put(spi);
|
spi_dev_put(spi);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
spi->max_speed_hz = be32_to_cpup(prop);
|
spi->max_speed_hz = value;
|
||||||
|
|
||||||
/* IRQ */
|
/* IRQ */
|
||||||
spi->irq = irq_of_parse_and_map(nc, 0);
|
spi->irq = irq_of_parse_and_map(nc, 0);
|
||||||
@ -944,9 +1066,7 @@ static void of_register_spi_devices(struct spi_master *master)
|
|||||||
spi->dev.of_node = nc;
|
spi->dev.of_node = nc;
|
||||||
|
|
||||||
/* Register the new device */
|
/* Register the new device */
|
||||||
snprintf(modalias, sizeof(modalias), "%s%s", SPI_MODULE_PREFIX,
|
request_module("%s%s", SPI_MODULE_PREFIX, spi->modalias);
|
||||||
spi->modalias);
|
|
||||||
request_module(modalias);
|
|
||||||
rc = spi_add_device(spi);
|
rc = spi_add_device(spi);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(&master->dev, "spi_device register error %s\n",
|
dev_err(&master->dev, "spi_device register error %s\n",
|
||||||
@ -1025,7 +1145,7 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
|
|||||||
return AE_OK;
|
return AE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
|
strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias));
|
||||||
if (spi_add_device(spi)) {
|
if (spi_add_device(spi)) {
|
||||||
dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
|
dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
|
||||||
dev_name(&adev->dev));
|
dev_name(&adev->dev));
|
||||||
@ -1097,7 +1217,7 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
|
|||||||
if (!dev)
|
if (!dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
master = kzalloc(size + sizeof *master, GFP_KERNEL);
|
master = kzalloc(size + sizeof(*master), GFP_KERNEL);
|
||||||
if (!master)
|
if (!master)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -1122,7 +1242,7 @@ static int of_spi_register_master(struct spi_master *master)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nb = of_gpio_named_count(np, "cs-gpios");
|
nb = of_gpio_named_count(np, "cs-gpios");
|
||||||
master->num_chipselect = max(nb, (int)master->num_chipselect);
|
master->num_chipselect = max_t(int, nb, master->num_chipselect);
|
||||||
|
|
||||||
/* Return error only for an incorrectly formed cs-gpios property */
|
/* Return error only for an incorrectly formed cs-gpios property */
|
||||||
if (nb == 0 || nb == -ENOENT)
|
if (nb == 0 || nb == -ENOENT)
|
||||||
@ -1209,6 +1329,7 @@ int spi_register_master(struct spi_master *master)
|
|||||||
spin_lock_init(&master->bus_lock_spinlock);
|
spin_lock_init(&master->bus_lock_spinlock);
|
||||||
mutex_init(&master->bus_lock_mutex);
|
mutex_init(&master->bus_lock_mutex);
|
||||||
master->bus_lock_flag = 0;
|
master->bus_lock_flag = 0;
|
||||||
|
init_completion(&master->xfer_completion);
|
||||||
|
|
||||||
/* register the device, then userspace will see it.
|
/* register the device, then userspace will see it.
|
||||||
* registration fails if the bus ID is in use.
|
* registration fails if the bus ID is in use.
|
||||||
@ -1245,6 +1366,41 @@ done:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_register_master);
|
EXPORT_SYMBOL_GPL(spi_register_master);
|
||||||
|
|
||||||
|
static void devm_spi_unregister(struct device *dev, void *res)
|
||||||
|
{
|
||||||
|
spi_unregister_master(*(struct spi_master **)res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_spi_register_master - register managed SPI master controller
|
||||||
|
* @dev: device managing SPI master
|
||||||
|
* @master: initialized master, originally from spi_alloc_master()
|
||||||
|
* Context: can sleep
|
||||||
|
*
|
||||||
|
* Register a SPI device as with spi_register_master() which will
|
||||||
|
* automatically be unregister
|
||||||
|
*/
|
||||||
|
int devm_spi_register_master(struct device *dev, struct spi_master *master)
|
||||||
|
{
|
||||||
|
struct spi_master **ptr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ptr = devres_alloc(devm_spi_unregister, sizeof(*ptr), GFP_KERNEL);
|
||||||
|
if (!ptr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = spi_register_master(master);
|
||||||
|
if (ret != 0) {
|
||||||
|
*ptr = master;
|
||||||
|
devres_add(dev, ptr);
|
||||||
|
} else {
|
||||||
|
devres_free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devm_spi_register_master);
|
||||||
|
|
||||||
static int __unregister(struct device *dev, void *null)
|
static int __unregister(struct device *dev, void *null)
|
||||||
{
|
{
|
||||||
spi_unregister_device(to_spi_device(dev));
|
spi_unregister_device(to_spi_device(dev));
|
||||||
@ -1402,8 +1558,7 @@ int spi_setup(struct spi_device *spi)
|
|||||||
if (spi->master->setup)
|
if (spi->master->setup)
|
||||||
status = spi->master->setup(spi);
|
status = spi->master->setup(spi);
|
||||||
|
|
||||||
dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"
|
dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
|
||||||
"%u bits/w, %u Hz max --> %d\n",
|
|
||||||
(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
|
(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
|
||||||
(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
|
(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
|
||||||
(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
|
(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
|
||||||
@ -1421,6 +1576,10 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
|||||||
struct spi_master *master = spi->master;
|
struct spi_master *master = spi->master;
|
||||||
struct spi_transfer *xfer;
|
struct spi_transfer *xfer;
|
||||||
|
|
||||||
|
message->spi = spi;
|
||||||
|
|
||||||
|
trace_spi_message_submit(message);
|
||||||
|
|
||||||
if (list_empty(&message->transfers))
|
if (list_empty(&message->transfers))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!message->complete)
|
if (!message->complete)
|
||||||
@ -1520,7 +1679,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message->spi = spi;
|
|
||||||
message->status = -EINPROGRESS;
|
message->status = -EINPROGRESS;
|
||||||
return master->transfer(spi, message);
|
return master->transfer(spi, message);
|
||||||
}
|
}
|
||||||
@ -1762,7 +1920,7 @@ int spi_bus_unlock(struct spi_master *master)
|
|||||||
EXPORT_SYMBOL_GPL(spi_bus_unlock);
|
EXPORT_SYMBOL_GPL(spi_bus_unlock);
|
||||||
|
|
||||||
/* portable code must never pass more than 32 bytes */
|
/* portable code must never pass more than 32 bytes */
|
||||||
#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES)
|
#define SPI_BUFSIZ max(32, SMP_CACHE_BYTES)
|
||||||
|
|
||||||
static u8 *buf;
|
static u8 *buf;
|
||||||
|
|
||||||
@ -1811,7 +1969,7 @@ int spi_write_then_read(struct spi_device *spi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
spi_message_init(&message);
|
spi_message_init(&message);
|
||||||
memset(x, 0, sizeof x);
|
memset(x, 0, sizeof(x));
|
||||||
if (n_tx) {
|
if (n_tx) {
|
||||||
x[0].len = n_tx;
|
x[0].len = n_tx;
|
||||||
spi_message_add_tail(&x[0], &message);
|
spi_message_add_tail(&x[0], &message);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/spidev.h>
|
#include <linux/spi/spidev.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -206,9 +206,9 @@ spidev_write(struct file *filp, const char __user *buf,
|
|||||||
|
|
||||||
mutex_lock(&spidev->buf_lock);
|
mutex_lock(&spidev->buf_lock);
|
||||||
missing = copy_from_user(spidev->buffer, buf, count);
|
missing = copy_from_user(spidev->buffer, buf, count);
|
||||||
if (missing == 0) {
|
if (missing == 0)
|
||||||
status = spidev_sync_write(spidev, count);
|
status = spidev_sync_write(spidev, count);
|
||||||
} else
|
else
|
||||||
status = -EFAULT;
|
status = -EFAULT;
|
||||||
mutex_unlock(&spidev->buf_lock);
|
mutex_unlock(&spidev->buf_lock);
|
||||||
|
|
||||||
@ -629,7 +629,6 @@ static int spidev_remove(struct spi_device *spi)
|
|||||||
/* make sure ops on existing fds can abort cleanly */
|
/* make sure ops on existing fds can abort cleanly */
|
||||||
spin_lock_irq(&spidev->spi_lock);
|
spin_lock_irq(&spidev->spi_lock);
|
||||||
spidev->spi = NULL;
|
spidev->spi = NULL;
|
||||||
spi_set_drvdata(spi, NULL);
|
|
||||||
spin_unlock_irq(&spidev->spi_lock);
|
spin_unlock_irq(&spidev->spi_lock);
|
||||||
|
|
||||||
/* prevent new opens */
|
/* prevent new opens */
|
||||||
|
@ -86,7 +86,7 @@ static int ade7753_spi_read_reg_16(struct device *dev,
|
|||||||
struct ade7753_state *st = iio_priv(indio_dev);
|
struct ade7753_state *st = iio_priv(indio_dev);
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
ret = spi_w8r16(st->us, ADE7753_READ_REG(reg_address));
|
ret = spi_w8r16be(st->us, ADE7753_READ_REG(reg_address));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
|
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
|
||||||
reg_address);
|
reg_address);
|
||||||
@ -94,7 +94,6 @@ static int ade7753_spi_read_reg_16(struct device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*val = ret;
|
*val = ret;
|
||||||
*val = be16_to_cpup(val);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ static int ade7754_spi_read_reg_16(struct device *dev,
|
|||||||
struct ade7754_state *st = iio_priv(indio_dev);
|
struct ade7754_state *st = iio_priv(indio_dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = spi_w8r16(st->us, ADE7754_READ_REG(reg_address));
|
ret = spi_w8r16be(st->us, ADE7754_READ_REG(reg_address));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
|
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
|
||||||
reg_address);
|
reg_address);
|
||||||
@ -94,7 +94,6 @@ static int ade7754_spi_read_reg_16(struct device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*val = ret;
|
*val = ret;
|
||||||
*val = be16_to_cpup(val);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ static int ade7759_spi_read_reg_16(struct device *dev,
|
|||||||
struct ade7759_state *st = iio_priv(indio_dev);
|
struct ade7759_state *st = iio_priv(indio_dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = spi_w8r16(st->us, ADE7759_READ_REG(reg_address));
|
ret = spi_w8r16be(st->us, ADE7759_READ_REG(reg_address));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
|
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
|
||||||
reg_address);
|
reg_address);
|
||||||
@ -94,7 +94,6 @@ static int ade7759_spi_read_reg_16(struct device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*val = ret;
|
*val = ret;
|
||||||
*val = be16_to_cpup(val);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ struct rspi_plat_data {
|
|||||||
unsigned int dma_rx_id;
|
unsigned int dma_rx_id;
|
||||||
|
|
||||||
unsigned dma_width_16bit:1; /* DMAC read/write width = 16-bit */
|
unsigned dma_width_16bit:1; /* DMAC read/write width = 16-bit */
|
||||||
|
|
||||||
|
u16 num_chipselect;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <linux/mod_devicetable.h>
|
#include <linux/mod_devicetable.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* INTERFACES between SPI master-side drivers and SPI infrastructure.
|
* INTERFACES between SPI master-side drivers and SPI infrastructure.
|
||||||
@ -150,8 +151,7 @@ static inline void *spi_get_drvdata(struct spi_device *spi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct spi_message;
|
struct spi_message;
|
||||||
|
struct spi_transfer;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct spi_driver - Host side "protocol" driver
|
* struct spi_driver - Host side "protocol" driver
|
||||||
@ -257,6 +257,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
|||||||
* @queue_lock: spinlock to syncronise access to message queue
|
* @queue_lock: spinlock to syncronise access to message queue
|
||||||
* @queue: message queue
|
* @queue: message queue
|
||||||
* @cur_msg: the currently in-flight message
|
* @cur_msg: the currently in-flight message
|
||||||
|
* @cur_msg_prepared: spi_prepare_message was called for the currently
|
||||||
|
* in-flight message
|
||||||
|
* @xfer_completion: used by core tranfer_one_message()
|
||||||
* @busy: message pump is busy
|
* @busy: message pump is busy
|
||||||
* @running: message pump is running
|
* @running: message pump is running
|
||||||
* @rt: whether this queue is set to run as a realtime task
|
* @rt: whether this queue is set to run as a realtime task
|
||||||
@ -274,6 +277,16 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
|||||||
* @unprepare_transfer_hardware: there are currently no more messages on the
|
* @unprepare_transfer_hardware: there are currently no more messages on the
|
||||||
* queue so the subsystem notifies the driver that it may relax the
|
* queue so the subsystem notifies the driver that it may relax the
|
||||||
* hardware by issuing this call
|
* hardware by issuing this call
|
||||||
|
* @set_cs: assert or deassert chip select, true to assert. May be called
|
||||||
|
* from interrupt context.
|
||||||
|
* @prepare_message: set up the controller to transfer a single message,
|
||||||
|
* for example doing DMA mapping. Called from threaded
|
||||||
|
* context.
|
||||||
|
* @transfer_one: transfer a single spi_transfer. When the
|
||||||
|
* driver is finished with this transfer it must call
|
||||||
|
* spi_finalize_current_transfer() so the subsystem can issue
|
||||||
|
* the next transfer
|
||||||
|
* @unprepare_message: undo any work done by prepare_message().
|
||||||
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
|
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
|
||||||
* number. Any individual value may be -ENOENT for CS lines that
|
* number. Any individual value may be -ENOENT for CS lines that
|
||||||
* are not GPIOs (driven by the SPI controller itself).
|
* are not GPIOs (driven by the SPI controller itself).
|
||||||
@ -388,11 +401,25 @@ struct spi_master {
|
|||||||
bool running;
|
bool running;
|
||||||
bool rt;
|
bool rt;
|
||||||
bool auto_runtime_pm;
|
bool auto_runtime_pm;
|
||||||
|
bool cur_msg_prepared;
|
||||||
|
struct completion xfer_completion;
|
||||||
|
|
||||||
int (*prepare_transfer_hardware)(struct spi_master *master);
|
int (*prepare_transfer_hardware)(struct spi_master *master);
|
||||||
int (*transfer_one_message)(struct spi_master *master,
|
int (*transfer_one_message)(struct spi_master *master,
|
||||||
struct spi_message *mesg);
|
struct spi_message *mesg);
|
||||||
int (*unprepare_transfer_hardware)(struct spi_master *master);
|
int (*unprepare_transfer_hardware)(struct spi_master *master);
|
||||||
|
int (*prepare_message)(struct spi_master *master,
|
||||||
|
struct spi_message *message);
|
||||||
|
int (*unprepare_message)(struct spi_master *master,
|
||||||
|
struct spi_message *message);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These hooks are for drivers that use a generic implementation
|
||||||
|
* of transfer_one_message() provied by the core.
|
||||||
|
*/
|
||||||
|
void (*set_cs)(struct spi_device *spi, bool enable);
|
||||||
|
int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
|
||||||
|
struct spi_transfer *transfer);
|
||||||
|
|
||||||
/* gpio chip select */
|
/* gpio chip select */
|
||||||
int *cs_gpios;
|
int *cs_gpios;
|
||||||
@ -428,12 +455,15 @@ extern int spi_master_resume(struct spi_master *master);
|
|||||||
/* Calls the driver make to interact with the message queue */
|
/* Calls the driver make to interact with the message queue */
|
||||||
extern struct spi_message *spi_get_next_queued_message(struct spi_master *master);
|
extern struct spi_message *spi_get_next_queued_message(struct spi_master *master);
|
||||||
extern void spi_finalize_current_message(struct spi_master *master);
|
extern void spi_finalize_current_message(struct spi_master *master);
|
||||||
|
extern void spi_finalize_current_transfer(struct spi_master *master);
|
||||||
|
|
||||||
/* the spi driver core manages memory for the spi_master classdev */
|
/* the spi driver core manages memory for the spi_master classdev */
|
||||||
extern struct spi_master *
|
extern struct spi_master *
|
||||||
spi_alloc_master(struct device *host, unsigned size);
|
spi_alloc_master(struct device *host, unsigned size);
|
||||||
|
|
||||||
extern int spi_register_master(struct spi_master *master);
|
extern int spi_register_master(struct spi_master *master);
|
||||||
|
extern int devm_spi_register_master(struct device *dev,
|
||||||
|
struct spi_master *master);
|
||||||
extern void spi_unregister_master(struct spi_master *master);
|
extern void spi_unregister_master(struct spi_master *master);
|
||||||
|
|
||||||
extern struct spi_master *spi_busnum_to_master(u16 busnum);
|
extern struct spi_master *spi_busnum_to_master(u16 busnum);
|
||||||
@ -823,6 +853,33 @@ static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
|
|||||||
return (status < 0) ? status : result;
|
return (status < 0) ? status : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spi_w8r16be - SPI synchronous 8 bit write followed by 16 bit big-endian read
|
||||||
|
* @spi: device with which data will be exchanged
|
||||||
|
* @cmd: command to be written before data is read back
|
||||||
|
* Context: can sleep
|
||||||
|
*
|
||||||
|
* This returns the (unsigned) sixteen bit number returned by the device in cpu
|
||||||
|
* endianness, or else a negative error code. Callable only from contexts that
|
||||||
|
* can sleep.
|
||||||
|
*
|
||||||
|
* This function is similar to spi_w8r16, with the exception that it will
|
||||||
|
* convert the read 16 bit data word from big-endian to native endianness.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd)
|
||||||
|
|
||||||
|
{
|
||||||
|
ssize_t status;
|
||||||
|
__be16 result;
|
||||||
|
|
||||||
|
status = spi_write_then_read(spi, &cmd, 1, &result, 2);
|
||||||
|
if (status < 0)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
return be16_to_cpu(result);
|
||||||
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
156
include/trace/events/spi.h
Normal file
156
include/trace/events/spi.h
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#undef TRACE_SYSTEM
|
||||||
|
#define TRACE_SYSTEM spi
|
||||||
|
|
||||||
|
#if !defined(_TRACE_SPI_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||||
|
#define _TRACE_SPI_H
|
||||||
|
|
||||||
|
#include <linux/ktime.h>
|
||||||
|
#include <linux/tracepoint.h>
|
||||||
|
|
||||||
|
DECLARE_EVENT_CLASS(spi_master,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_master *master),
|
||||||
|
|
||||||
|
TP_ARGS(master),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( int, bus_num )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->bus_num = master->bus_num;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("spi%d", (int)__entry->bus_num)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(spi_master, spi_master_idle,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_master *master),
|
||||||
|
|
||||||
|
TP_ARGS(master)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(spi_master, spi_master_busy,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_master *master),
|
||||||
|
|
||||||
|
TP_ARGS(master)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
DECLARE_EVENT_CLASS(spi_message,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_message *msg),
|
||||||
|
|
||||||
|
TP_ARGS(msg),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( int, bus_num )
|
||||||
|
__field( int, chip_select )
|
||||||
|
__field( struct spi_message *, msg )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->bus_num = msg->spi->master->bus_num;
|
||||||
|
__entry->chip_select = msg->spi->chip_select;
|
||||||
|
__entry->msg = msg;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("spi%d.%d %p", (int)__entry->bus_num,
|
||||||
|
(int)__entry->chip_select,
|
||||||
|
(struct spi_message *)__entry->msg)
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(spi_message, spi_message_submit,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_message *msg),
|
||||||
|
|
||||||
|
TP_ARGS(msg)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(spi_message, spi_message_start,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_message *msg),
|
||||||
|
|
||||||
|
TP_ARGS(msg)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(spi_message_done,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_message *msg),
|
||||||
|
|
||||||
|
TP_ARGS(msg),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( int, bus_num )
|
||||||
|
__field( int, chip_select )
|
||||||
|
__field( struct spi_message *, msg )
|
||||||
|
__field( unsigned, frame )
|
||||||
|
__field( unsigned, actual )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->bus_num = msg->spi->master->bus_num;
|
||||||
|
__entry->chip_select = msg->spi->chip_select;
|
||||||
|
__entry->msg = msg;
|
||||||
|
__entry->frame = msg->frame_length;
|
||||||
|
__entry->actual = msg->actual_length;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("spi%d.%d %p len=%u/%u", (int)__entry->bus_num,
|
||||||
|
(int)__entry->chip_select,
|
||||||
|
(struct spi_message *)__entry->msg,
|
||||||
|
(unsigned)__entry->actual, (unsigned)__entry->frame)
|
||||||
|
);
|
||||||
|
|
||||||
|
DECLARE_EVENT_CLASS(spi_transfer,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_message *msg, struct spi_transfer *xfer),
|
||||||
|
|
||||||
|
TP_ARGS(msg, xfer),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( int, bus_num )
|
||||||
|
__field( int, chip_select )
|
||||||
|
__field( struct spi_transfer *, xfer )
|
||||||
|
__field( int, len )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->bus_num = msg->spi->master->bus_num;
|
||||||
|
__entry->chip_select = msg->spi->chip_select;
|
||||||
|
__entry->xfer = xfer;
|
||||||
|
__entry->len = xfer->len;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("spi%d.%d %p len=%d", (int)__entry->bus_num,
|
||||||
|
(int)__entry->chip_select,
|
||||||
|
(struct spi_message *)__entry->xfer,
|
||||||
|
(int)__entry->len)
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(spi_transfer, spi_transfer_start,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_message *msg, struct spi_transfer *xfer),
|
||||||
|
|
||||||
|
TP_ARGS(msg, xfer)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(spi_transfer, spi_transfer_stop,
|
||||||
|
|
||||||
|
TP_PROTO(struct spi_message *msg, struct spi_transfer *xfer),
|
||||||
|
|
||||||
|
TP_ARGS(msg, xfer)
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* _TRACE_POWER_H */
|
||||||
|
|
||||||
|
/* This part must be outside protection */
|
||||||
|
#include <trace/define_trace.h>
|
Loading…
Reference in New Issue
Block a user