diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 13 | ||||
-rw-r--r-- | drivers/spi/spi-altera.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-ath79.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-atmel.c | 7 | ||||
-rw-r--r-- | drivers/spi/spi-au1550.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-bitbang.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-butterfly.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-dw-mmio.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-dw-pci.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-dw.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-gpio.c | 5 | ||||
-rw-r--r-- | drivers/spi/spi-nuc900.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-oc-tiny.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-omap-uwire.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-orion.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-pl022.c | 233 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx-pci.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-s3c24xx.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 189 | ||||
-rw-r--r-- | drivers/spi/spi-sh-msiof.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-sh-sci.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-ti-ssp.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-tle62x0.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-txx9.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi.c | 3 |
25 files changed, 281 insertions, 190 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a1c468e25918..3f9a47ec67dc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -87,12 +87,12 @@ config SPI_BFIN_SPORT Enable support for a SPI bus via the Blackfin SPORT peripheral. config SPI_AU1550 - tristate "Au1550/Au12x0 SPI Controller" - depends on (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL + tristate "Au1550/Au1200/Au1300 SPI Controller" + depends on MIPS_ALCHEMY && EXPERIMENTAL select SPI_BITBANG help If you say yes to this option, support will be included for the - Au1550 SPI controller (may also work with Au1200,Au1210,Au1250). + PSC SPI controller found on Au1550, Au1200 and Au1300 series. config SPI_BITBANG tristate "Utilities for Bitbanging SPI masters" @@ -174,8 +174,7 @@ config SPI_LM70_LLP config SPI_MPC52xx tristate "Freescale MPC52xx SPI (non-PSC) controller support" - depends on PPC_MPC52xx && SPI - select SPI_MASTER_OF + depends on PPC_MPC52xx help This drivers supports the MPC52xx SPI controller in master SPI mode. @@ -199,7 +198,7 @@ config SPI_FSL_LIB depends on FSL_SOC config SPI_FSL_SPI - tristate "Freescale SPI controller" + bool "Freescale SPI controller" depends on FSL_SOC select SPI_FSL_LIB help @@ -208,7 +207,7 @@ config SPI_FSL_SPI MPC8569 uses the controller in QE mode, MPC8610 in cpu mode. config SPI_FSL_ESPI - tristate "Freescale eSPI controller" + bool "Freescale eSPI controller" depends on FSL_SOC select SPI_FSL_LIB help diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 881c1967741d..c00d00e96ee4 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 024b48aed5ca..acc88b4d2869 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -13,6 +13,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/spinlock.h> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index a356392ab2f6..16d6a839c7fa 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -22,7 +22,7 @@ #include <asm/io.h> #include <mach/board.h> -#include <mach/gpio.h> +#include <asm/gpio.h> #include <mach/cpu.h> /* SPI register offsets */ @@ -907,7 +907,7 @@ static void atmel_spi_cleanup(struct spi_device *spi) /*-------------------------------------------------------------------------*/ -static int __init atmel_spi_probe(struct platform_device *pdev) +static int __devinit atmel_spi_probe(struct platform_device *pdev) { struct resource *regs; int irq; @@ -1003,7 +1003,7 @@ out_free: return ret; } -static int __exit atmel_spi_remove(struct platform_device *pdev) +static int __devexit atmel_spi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct atmel_spi *as = spi_master_get_devdata(master); @@ -1072,6 +1072,7 @@ static struct platform_driver atmel_spi_driver = { }, .suspend = atmel_spi_suspend, .resume = atmel_spi_resume, + .probe = atmel_spi_probe, .remove = __exit_p(atmel_spi_remove), }; module_platform_driver(atmel_spi_driver); diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index bddee5f516b2..5784c8799616 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -25,6 +25,7 @@ #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/resource.h> diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 02d57fbba295..aef59b1a15f7 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -20,6 +20,7 @@ #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/platform_device.h> diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index 9f907ec52def..5ed08e537433 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/device.h> #include <linux/parport.h> diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index fac399c3022c..db2f1ba06eab 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/scatterlist.h> +#include <linux/module.h> #include "spi-dw.h" diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index c5f37f03ac8b..f64250ea1611 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -21,6 +21,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/spi/spi.h> +#include <linux/module.h> #include "spi-dw.h" diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 296d94f4cf72..082458d73ce9 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -19,6 +19,7 @@ #include <linux/dma-mapping.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/highmem.h> #include <linux/delay.h> #include <linux/slab.h> diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 635ff08b377f..0094c645ff0d 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -18,6 +18,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/gpio.h> @@ -255,7 +256,7 @@ static void spi_gpio_cleanup(struct spi_device *spi) spi_bitbang_cleanup(spi); } -static int __init spi_gpio_alloc(unsigned pin, const char *label, bool is_in) +static int __devinit spi_gpio_alloc(unsigned pin, const char *label, bool is_in) { int value; @@ -269,7 +270,7 @@ static int __init spi_gpio_alloc(unsigned pin, const char *label, bool is_in) return value; } -static int __init +static int __devinit spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label, u16 *res_flags) { diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index e763254741c2..182e9c873822 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -8,6 +8,7 @@ * */ +#include <linux/module.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/workqueue.h> @@ -426,7 +427,7 @@ static int __devinit nuc900_spi_probe(struct platform_device *pdev) goto err_clk; } - mfp_set_groupg(&pdev->dev); + mfp_set_groupg(&pdev->dev, NULL); nuc900_init_spi(hw); err = spi_bitbang_start(&hw->bitbang); diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 897274e8715c..698018fd992b 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 00a8e9d7dbe4..610f7391456e 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -45,6 +45,7 @@ #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/irq.h> diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 9421a390a5e3..13448c832c44 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -17,6 +17,7 @@ #include <linux/io.h> #include <linux/spi/spi.h> #include <linux/spi/orion_spi.h> +#include <linux/module.h> #include <asm/unaligned.h> #define DRIVER_NAME "orion_spi" diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index c828dc607d99..f1f5efbc3404 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -340,6 +340,10 @@ struct vendor_data { * @cur_msg: Pointer to current spi_message being processed * @cur_transfer: Pointer to current spi_transfer * @cur_chip: pointer to current clients chip(assigned from controller_state) + * @next_msg_cs_active: the next message in the queue has been examined + * and it was found that it uses the same chip select as the previous + * message, so we left it active after the previous transfer, and it's + * active already. * @tx: current position in TX buffer to be read * @tx_end: end position in TX buffer to be read * @rx: current position in RX buffer to be written @@ -373,6 +377,7 @@ struct pl022 { struct spi_message *cur_msg; struct spi_transfer *cur_transfer; struct chip_data *cur_chip; + bool next_msg_cs_active; void *tx; void *tx_end; void *rx; @@ -445,23 +450,9 @@ static void giveback(struct pl022 *pl022) struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; - void (*curr_cs_control) (u32 command); + pl022->next_msg_cs_active = false; - /* - * This local reference to the chip select function - * is needed because we set curr_chip to NULL - * as a step toward termininating the message. - */ - curr_cs_control = pl022->cur_chip->cs_control; - spin_lock_irqsave(&pl022->queue_lock, flags); - msg = pl022->cur_msg; - pl022->cur_msg = NULL; - pl022->cur_transfer = NULL; - pl022->cur_chip = NULL; - queue_work(pl022->workqueue, &pl022->pump_messages); - spin_unlock_irqrestore(&pl022->queue_lock, flags); - - last_transfer = list_entry(msg->transfers.prev, + last_transfer = list_entry(pl022->cur_msg->transfers.prev, struct spi_transfer, transfer_list); @@ -473,18 +464,13 @@ static void giveback(struct pl022 *pl022) */ udelay(last_transfer->delay_usecs); - /* - * Drop chip select UNLESS cs_change is true or we are returning - * a message with an error, or next message is for another chip - */ - if (!last_transfer->cs_change) - curr_cs_control(SSP_CHIP_DESELECT); - else { + if (!last_transfer->cs_change) { struct spi_message *next_msg; - /* Holding of cs was hinted, but we need to make sure - * the next message is for the same chip. Don't waste - * time with the following tests unless this was hinted. + /* + * cs_change was not set. We can keep the chip select + * enabled if there is message in the queue and it is + * for the same spi device. * * We cannot postpone this until pump_messages, because * after calling msg->complete (below) the driver that @@ -501,22 +487,29 @@ static void giveback(struct pl022 *pl022) struct spi_message, queue); spin_unlock_irqrestore(&pl022->queue_lock, flags); - /* see if the next and current messages point - * to the same chip + /* + * see if the next and current messages point + * to the same spi device. */ - if (next_msg && next_msg->spi != msg->spi) + if (next_msg && next_msg->spi != pl022->cur_msg->spi) next_msg = NULL; - if (!next_msg || msg->state == STATE_ERROR) - curr_cs_control(SSP_CHIP_DESELECT); + if (!next_msg || pl022->cur_msg->state == STATE_ERROR) + pl022->cur_chip->cs_control(SSP_CHIP_DESELECT); + else + pl022->next_msg_cs_active = true; } + + spin_lock_irqsave(&pl022->queue_lock, flags); + msg = pl022->cur_msg; + pl022->cur_msg = NULL; + pl022->cur_transfer = NULL; + pl022->cur_chip = NULL; + queue_work(pl022->workqueue, &pl022->pump_messages); + spin_unlock_irqrestore(&pl022->queue_lock, flags); + msg->state = NULL; if (msg->complete) msg->complete(msg->context); - /* This message is completed, so let's turn off the clocks & power */ - clk_disable(pl022->clk); - amba_pclk_disable(pl022->adev); - amba_vcore_disable(pl022->adev); - pm_runtime_put(&pl022->adev->dev); } /** @@ -1247,9 +1240,9 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) if ((pl022->tx == pl022->tx_end) && (flag == 0)) { flag = 1; - /* Disable Transmit interrupt */ - writew(readw(SSP_IMSC(pl022->virtbase)) & - (~SSP_IMSC_MASK_TXIM), + /* Disable Transmit interrupt, enable receive interrupt */ + writew((readw(SSP_IMSC(pl022->virtbase)) & + ~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase)); } @@ -1355,7 +1348,7 @@ static void pump_transfers(unsigned long data) */ udelay(previous->delay_usecs); - /* Drop chip select only if cs_change is requested */ + /* Reselect chip select only if cs_change was requested */ if (previous->cs_change) pl022->cur_chip->cs_control(SSP_CHIP_SELECT); } else { @@ -1382,15 +1375,22 @@ static void pump_transfers(unsigned long data) } err_config_dma: - writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); + /* enable all interrupts except RX */ + writew(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase)); } static void do_interrupt_dma_transfer(struct pl022 *pl022) { - u32 irqflags = ENABLE_ALL_INTERRUPTS; + /* + * Default is to enable all interrupts except RX - + * this will be enabled once TX is complete + */ + u32 irqflags = ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM; + + /* Enable target chip, if not already active */ + if (!pl022->next_msg_cs_active) + pl022->cur_chip->cs_control(SSP_CHIP_SELECT); - /* Enable target chip */ - pl022->cur_chip->cs_control(SSP_CHIP_SELECT); if (set_up_next_transfer(pl022, pl022->cur_transfer)) { /* Error path */ pl022->cur_msg->state = STATE_ERROR; @@ -1445,7 +1445,8 @@ static void do_polling_transfer(struct pl022 *pl022) } else { /* STATE_START */ message->state = STATE_RUNNING; - pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + if (!pl022->next_msg_cs_active) + pl022->cur_chip->cs_control(SSP_CHIP_SELECT); } /* Configuration Changing Per Transfer */ @@ -1507,14 +1508,28 @@ static void pump_messages(struct work_struct *work) struct pl022 *pl022 = container_of(work, struct pl022, pump_messages); unsigned long flags; + bool was_busy = false; /* Lock queue and check for queue work */ spin_lock_irqsave(&pl022->queue_lock, flags); if (list_empty(&pl022->queue) || !pl022->running) { + if (pl022->busy) { + /* nothing more to do - disable spi/ssp and power off */ + writew((readw(SSP_CR1(pl022->virtbase)) & + (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); + + if (pl022->master_info->autosuspend_delay > 0) { + pm_runtime_mark_last_busy(&pl022->adev->dev); + pm_runtime_put_autosuspend(&pl022->adev->dev); + } else { + pm_runtime_put(&pl022->adev->dev); + } + } pl022->busy = false; spin_unlock_irqrestore(&pl022->queue_lock, flags); return; } + /* Make sure we are not already running a message */ if (pl022->cur_msg) { spin_unlock_irqrestore(&pl022->queue_lock, flags); @@ -1525,7 +1540,10 @@ static void pump_messages(struct work_struct *work) list_entry(pl022->queue.next, struct spi_message, queue); list_del_init(&pl022->cur_msg->queue); - pl022->busy = true; + if (pl022->busy) + was_busy = true; + else + pl022->busy = true; spin_unlock_irqrestore(&pl022->queue_lock, flags); /* Initial message state */ @@ -1535,15 +1553,14 @@ static void pump_messages(struct work_struct *work) /* Setup the SPI using the per chip configuration */ pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi); - /* - * We enable the core voltage and clocks here, then the clocks - * and core will be disabled when giveback() is called in each method - * (poll/interrupt/DMA) - */ - pm_runtime_get_sync(&pl022->adev->dev); - amba_vcore_enable(pl022->adev); - amba_pclk_enable(pl022->adev); - clk_enable(pl022->clk); + if (!was_busy) + /* + * We enable the core voltage and clocks here, then the clocks + * and core will be disabled when this workqueue is run again + * and there is no more work to be done. + */ + pm_runtime_get_sync(&pl022->adev->dev); + restore_state(pl022); flush(pl022); @@ -1588,6 +1605,7 @@ static int start_queue(struct pl022 *pl022) pl022->cur_msg = NULL; pl022->cur_transfer = NULL; pl022->cur_chip = NULL; + pl022->next_msg_cs_active = false; spin_unlock_irqrestore(&pl022->queue_lock, flags); queue_work(pl022->workqueue, &pl022->pump_messages); @@ -1887,7 +1905,7 @@ static int pl022_setup(struct spi_device *spi) { struct pl022_config_chip const *chip_info; struct chip_data *chip; - struct ssp_clock_params clk_freq = {0, }; + struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0}; int status = 0; struct pl022 *pl022 = spi_master_get_devdata(spi->master); unsigned int bits = spi->bits_per_word; @@ -2176,8 +2194,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) } printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n", adev->res.start, pl022->virtbase); - pm_runtime_enable(dev); - pm_runtime_resume(dev); pl022->clk = clk_get(&adev->dev, NULL); if (IS_ERR(pl022->clk)) { @@ -2186,6 +2202,18 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_clk; } + status = clk_prepare(pl022->clk); + if (status) { + dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n"); + goto err_clk_prep; + } + + status = clk_enable(pl022->clk); + if (status) { + dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n"); + goto err_no_clk_en; + } + /* Disable SSP */ writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); @@ -2225,12 +2253,19 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_spi_register; } dev_dbg(dev, "probe succeeded\n"); - /* - * Disable the silicon block pclk and any voltage domain and just - * power it up and clock it when it's needed - */ - amba_pclk_disable(adev); - amba_vcore_disable(adev); + + /* let runtime pm put suspend */ + if (platform_info->autosuspend_delay > 0) { + dev_info(&adev->dev, + "will use autosuspend for runtime pm, delay %dms\n", + platform_info->autosuspend_delay); + pm_runtime_set_autosuspend_delay(dev, + platform_info->autosuspend_delay); + pm_runtime_use_autosuspend(dev); + pm_runtime_put_autosuspend(dev); + } else { + pm_runtime_put(dev); + } return 0; err_spi_register: @@ -2241,8 +2276,11 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) pl022_dma_remove(pl022); free_irq(adev->irq[0], pl022); - pm_runtime_disable(&adev->dev); err_no_irq: + clk_disable(pl022->clk); + err_no_clk_en: + clk_unprepare(pl022->clk); + err_clk_prep: clk_put(pl022->clk); err_no_clk: iounmap(pl022->virtbase); @@ -2263,6 +2301,12 @@ pl022_remove(struct amba_device *adev) if (!pl022) return 0; + /* + * undo pm_runtime_put() in probe. I assume that we're not + * accessing the primecell here. + */ + pm_runtime_get_noresume(&adev->dev); + /* Remove the queue */ if (destroy_queue(pl022) != 0) dev_err(&adev->dev, "queue remove failed\n"); @@ -2272,6 +2316,7 @@ pl022_remove(struct amba_device *adev) free_irq(adev->irq[0], pl022); clk_disable(pl022->clk); + clk_unprepare(pl022->clk); clk_put(pl022->clk); iounmap(pl022->virtbase); amba_release_regions(adev); @@ -2282,46 +2327,65 @@ pl022_remove(struct amba_device *adev) return 0; } -#ifdef CONFIG_PM -static int pl022_suspend(struct amba_device *adev, pm_message_t state) +#ifdef CONFIG_SUSPEND +static int pl022_suspend(struct device *dev) { - struct pl022 *pl022 = amba_get_drvdata(adev); + struct pl022 *pl022 = dev_get_drvdata(dev); int status = 0; status = stop_queue(pl022); if (status) { - dev_warn(&adev->dev, "suspend cannot stop queue\n"); + dev_warn(dev, "suspend cannot stop queue\n"); return status; } - amba_vcore_enable(adev); - amba_pclk_enable(adev); - load_ssp_default_config(pl022); - amba_pclk_disable(adev); - amba_vcore_disable(adev); - dev_dbg(&adev->dev, "suspended\n"); + dev_dbg(dev, "suspended\n"); return 0; } -static int pl022_resume(struct amba_device *adev) +static int pl022_resume(struct device *dev) { - struct pl022 *pl022 = amba_get_drvdata(adev); + struct pl022 *pl022 = dev_get_drvdata(dev); int status = 0; /* Start the queue running */ status = start_queue(pl022); if (status) - dev_err(&adev->dev, "problem starting queue (%d)\n", status); + dev_err(dev, "problem starting queue (%d)\n", status); else - dev_dbg(&adev->dev, "resumed\n"); + dev_dbg(dev, "resumed\n"); return status; } -#else -#define pl022_suspend NULL -#define pl022_resume NULL #endif /* CONFIG_PM */ +#ifdef CONFIG_PM_RUNTIME +static int pl022_runtime_suspend(struct device *dev) +{ + struct pl022 *pl022 = dev_get_drvdata(dev); + + clk_disable(pl022->clk); + amba_vcore_disable(pl022->adev); + + return 0; +} + +static int pl022_runtime_resume(struct device *dev) +{ + struct pl022 *pl022 = dev_get_drvdata(dev); + + amba_vcore_enable(pl022->adev); + clk_enable(pl022->clk); + + return 0; +} +#endif + +static const struct dev_pm_ops pl022_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume) + SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL) +}; + static struct vendor_data vendor_arm = { .fifodepth = 8, .max_bpw = 16, @@ -2397,15 +2461,16 @@ static struct amba_id pl022_ids[] = { { 0, 0 }, }; +MODULE_DEVICE_TABLE(amba, pl022_ids); + static struct amba_driver pl022_driver = { .drv = { .name = "ssp-pl022", + .pm = &pl022_dev_pm_ops, }, .id_table = pl022_ids, .probe = pl022_probe, .remove = __devexit_p(pl022_remove), - .suspend = pl022_suspend, - .resume = pl022_resume, }; static int __init pl022_init(void) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 378e504f89eb..8caa07d58e69 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -5,6 +5,7 @@ #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/of_device.h> +#include <linux/module.h> #include <linux/spi/pxa2xx_spi.h> struct ce4100_info { diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index b857a3e7af94..fc064535f4fc 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -24,6 +24,7 @@ #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> +#include <linux/module.h> #include <plat/regs-spi.h> #include <mach/spi.h> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 595dacc7645f..dcf7e1006426 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -131,6 +131,12 @@ #define RXBUSY (1<<2) #define TXBUSY (1<<3) +struct s3c64xx_spi_dma_data { + unsigned ch; + enum dma_data_direction direction; + enum dma_ch dmach; +}; + /** * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. * @clk: Pointer to the spi clock. @@ -164,13 +170,14 @@ struct s3c64xx_spi_driver_data { struct work_struct work; struct list_head queue; spinlock_t lock; - enum dma_ch rx_dmach; - enum dma_ch tx_dmach; unsigned long sfr_start; struct completion xfer_completion; unsigned state; unsigned cur_mode, cur_bpw; unsigned cur_speed; + struct s3c64xx_spi_dma_data rx_dma; + struct s3c64xx_spi_dma_data tx_dma; + struct samsung_dma_ops *ops; }; static struct s3c2410_dma_client s3c64xx_spi_dma_client = { @@ -226,6 +233,78 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) writel(val, regs + S3C64XX_SPI_CH_CFG); } +static void s3c64xx_spi_dmacb(void *data) +{ + struct s3c64xx_spi_driver_data *sdd; + struct s3c64xx_spi_dma_data *dma = data; + unsigned long flags; + + if (dma->direction == DMA_FROM_DEVICE) + sdd = container_of(data, + struct s3c64xx_spi_driver_data, rx_dma); + else + sdd = container_of(data, + struct s3c64xx_spi_driver_data, tx_dma); + + spin_lock_irqsave(&sdd->lock, flags); + + if (dma->direction == DMA_FROM_DEVICE) { + sdd->state &= ~RXBUSY; + if (!(sdd->state & TXBUSY)) + complete(&sdd->xfer_completion); + } else { + sdd->state &= ~TXBUSY; + if (!(sdd->state & RXBUSY)) + complete(&sdd->xfer_completion); + } + + spin_unlock_irqrestore(&sdd->lock, flags); +} + +static void prepare_dma(struct s3c64xx_spi_dma_data *dma, + unsigned len, dma_addr_t buf) +{ + struct s3c64xx_spi_driver_data *sdd; + struct samsung_dma_prep_info info; + + if (dma->direction == DMA_FROM_DEVICE) + sdd = container_of((void *)dma, + struct s3c64xx_spi_driver_data, rx_dma); + else + sdd = container_of((void *)dma, + struct s3c64xx_spi_driver_data, tx_dma); + + info.cap = DMA_SLAVE; + info.len = len; + info.fp = s3c64xx_spi_dmacb; + info.fp_param = dma; + info.direction = dma->direction; + info.buf = buf; + + sdd->ops->prepare(dma->ch, &info); + sdd->ops->trigger(dma->ch); +} + +static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) +{ + struct samsung_dma_info info; + + sdd->ops = samsung_dma_get_ops(); + + info.cap = DMA_SLAVE; + info.client = &s3c64xx_spi_dma_client; + info.width = sdd->cur_bpw / 8; + + info.direction = sdd->rx_dma.direction; + info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; + sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info); + info.direction = sdd->tx_dma.direction; + info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; + sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info); + + return 1; +} + static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi, struct spi_transfer *xfer, int dma_mode) @@ -258,10 +337,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; - s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8); - s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd, - xfer->tx_dma, xfer->len); - s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START); + prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma); } else { switch (sdd->cur_bpw) { case 32: @@ -293,10 +369,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); - s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8); - s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd, - xfer->rx_dma, xfer->len); - s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START); + prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma); } } @@ -482,46 +555,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) } } -static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, - int size, enum s3c2410_dma_buffresult res) -{ - struct s3c64xx_spi_driver_data *sdd = buf_id; - unsigned long flags; - - spin_lock_irqsave(&sdd->lock, flags); - - if (res == S3C2410_RES_OK) - sdd->state &= ~RXBUSY; - else - dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size); - - /* If the other done */ - if (!(sdd->state & TXBUSY)) - complete(&sdd->xfer_completion); - - spin_unlock_irqrestore(&sdd->lock, flags); -} - -static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id, - int size, enum s3c2410_dma_buffresult res) -{ - struct s3c64xx_spi_driver_data *sdd = buf_id; - unsigned long flags; - - spin_lock_irqsave(&sdd->lock, flags); - - if (res == S3C2410_RES_OK) - sdd->state &= ~TXBUSY; - else - dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size); - - /* If the other done */ - if (!(sdd->state & RXBUSY)) - complete(&sdd->xfer_completion); - - spin_unlock_irqrestore(&sdd->lock, flags); -} - #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, @@ -696,12 +729,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, if (use_dma) { if (xfer->tx_buf != NULL && (sdd->state & TXBUSY)) - s3c2410_dma_ctrl(sdd->tx_dmach, - S3C2410_DMAOP_FLUSH); + sdd->ops->stop(sdd->tx_dma.ch); if (xfer->rx_buf != NULL && (sdd->state & RXBUSY)) - s3c2410_dma_ctrl(sdd->rx_dmach, - S3C2410_DMAOP_FLUSH); + sdd->ops->stop(sdd->rx_dma.ch); } goto out; @@ -739,30 +770,6 @@ out: msg->complete(msg->context); } -static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) -{ - if (s3c2410_dma_request(sdd->rx_dmach, - &s3c64xx_spi_dma_client, NULL) < 0) { - dev_err(&sdd->pdev->dev, "cannot get RxDMA\n"); - return 0; - } - s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb); - s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW, - sdd->sfr_start + S3C64XX_SPI_RX_DATA); - - if (s3c2410_dma_request(sdd->tx_dmach, - &s3c64xx_spi_dma_client, NULL) < 0) { - dev_err(&sdd->pdev->dev, "cannot get TxDMA\n"); - s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client); - return 0; - } - s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb); - s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM, - sdd->sfr_start + S3C64XX_SPI_TX_DATA); - - return 1; -} - static void s3c64xx_spi_work(struct work_struct *work) { struct s3c64xx_spi_driver_data *sdd = container_of(work, @@ -799,8 +806,8 @@ static void s3c64xx_spi_work(struct work_struct *work) spin_unlock_irqrestore(&sdd->lock, flags); /* Free DMA channels */ - s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client); - s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client); + sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client); + sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client); } static int s3c64xx_spi_transfer(struct spi_device *spi, @@ -964,6 +971,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) struct s3c64xx_spi_info *sci; struct spi_master *master; int ret; + char clk_name[16]; if (pdev->id < 0) { dev_err(&pdev->dev, @@ -977,11 +985,6 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) } sci = pdev->dev.platform_data; - if (!sci->src_clk_name) { - dev_err(&pdev->dev, - "Board init must call s3c64xx_spi_set_info()\n"); - return -EINVAL; - } /* Check for availability of necessary resource */ @@ -1017,8 +1020,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) sdd->cntrlr_info = sci; sdd->pdev = pdev; sdd->sfr_start = mem_res->start; - sdd->tx_dmach = dmatx_res->start; - sdd->rx_dmach = dmarx_res->start; + sdd->tx_dma.dmach = dmatx_res->start; + sdd->tx_dma.direction = DMA_TO_DEVICE; + sdd->rx_dma.dmach = dmarx_res->start; + sdd->rx_dma.direction = DMA_FROM_DEVICE; sdd->cur_bpw = 8; @@ -1064,17 +1069,17 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err4; } - sdd->src_clk = clk_get(&pdev->dev, sci->src_clk_name); + sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr); + sdd->src_clk = clk_get(&pdev->dev, clk_name); if (IS_ERR(sdd->src_clk)) { dev_err(&pdev->dev, - "Unable to acquire clock '%s'\n", sci->src_clk_name); + "Unable to acquire clock '%s'\n", clk_name); ret = PTR_ERR(sdd->src_clk); goto err5; } if (clk_enable(sdd->src_clk)) { - dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", - sci->src_clk_name); + dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name); ret = -EBUSY; goto err6; } @@ -1106,7 +1111,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) pdev->id, master->num_chipselect); dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n", mem_res->end, mem_res->start, - sdd->rx_dmach, sdd->tx_dmach); + sdd->rx_dma.dmach, sdd->tx_dma.dmach); return 0; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 0f4834ae28cd..1f466bc66d9d 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 8844bc342782..097e506042be 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -22,6 +22,7 @@ #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> +#include <linux/module.h> #include <asm/spi.h> #include <asm/io.h> diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c index 7963c60063d6..3f6f6e81c655 100644 --- a/drivers/spi/spi-ti-ssp.c +++ b/drivers/spi/spi-ti-ssp.c @@ -22,6 +22,7 @@ #include <linux/err.h> #include <linux/completion.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/mfd/ti_ssp.h> diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index 940e73d1cf09..0ce5c12aab55 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -11,6 +11,7 @@ #include <linux/device.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/spi/spi.h> diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index f0a2ab0428a3..d5a3cbb646cb 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -25,6 +25,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/module.h> #include <asm/gpio.h> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4d1b9f517ce8..b2ccdea30cb9 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -29,6 +29,7 @@ #include <linux/spi/spi.h> #include <linux/of_spi.h> #include <linux/pm_runtime.h> +#include <linux/export.h> static void spidev_release(struct device *dev) { @@ -318,7 +319,7 @@ struct spi_device *spi_alloc_device(struct spi_master *master) } spi->master = master; - spi->dev.parent = dev; + spi->dev.parent = &master->dev; spi->dev.bus = &spi_bus_type; spi->dev.release = spidev_release; device_initialize(&spi->dev); |