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:
Linus Torvalds 2013-11-12 15:01:39 +09:00
commit f095ca6b31
62 changed files with 1281 additions and 715 deletions

View 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

View File

@ -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()

View File

@ -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)

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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,
}; };

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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:

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);

View File

@ -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;
} }

View File

@ -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)

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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,
}, },
}; };

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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))

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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

View File

@ -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
View 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>