diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 6 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/spi-altera.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-gpio.c | 131 | ||||
-rw-r--r-- | drivers/spi/spi-imx.c | 6 | ||||
-rw-r--r-- | drivers/spi/spi-mpc512x-psc.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-mpc52xx-psc.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-mpc52xx.c | 9 | ||||
-rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 321 | ||||
-rw-r--r-- | drivers/spi/spi-orion.c | 209 | ||||
-rw-r--r-- | drivers/spi/spi-pl022.c | 251 | ||||
-rw-r--r-- | drivers/spi/spi-s3c24xx.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 11 | ||||
-rw-r--r-- | drivers/spi/spi-sc18is602.c | 364 | ||||
-rw-r--r-- | drivers/spi/spi-sh-hspi.c | 5 | ||||
-rw-r--r-- | drivers/spi/spi-stmp.c | 6 | ||||
-rw-r--r-- | drivers/spi/spi-tegra.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-tle62x0.c | 13 | ||||
-rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 2 |
19 files changed, 962 insertions, 388 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 6992b30b4e42..63a79437aca1 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -325,6 +325,12 @@ config SPI_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. +config SPI_SC18IS602 + tristate "NXP SC18IS602/602B/603 I2C to SPI bridge" + depends on I2C + help + SPI driver for NXP SC18IS602/602B/603 I2C to SPI bridge. + config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" depends on SUPERH && HAVE_CLK diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3b72d87b3309..938705644bb6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o +obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o obj-$(CONFIG_SPI_SH) += spi-sh.o obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index c00d00e96ee4..f1fec2a19d10 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -307,8 +307,6 @@ static const struct of_device_id altera_spi_match[] = { {}, }; MODULE_DEVICE_TABLE(of, altera_spi_match); -#else /* CONFIG_OF */ -#define altera_spi_match NULL #endif /* CONFIG_OF */ static struct platform_driver altera_spi_driver = { @@ -318,7 +316,7 @@ static struct platform_driver altera_spi_driver = { .name = DRV_NAME, .owner = THIS_MODULE, .pm = NULL, - .of_match_table = altera_spi_match, + .of_match_table = of_match_ptr(altera_spi_match), }, }; module_platform_driver(altera_spi_driver); diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 0b56cfc71fab..a2b50c516b31 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -22,6 +22,8 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> @@ -46,6 +48,7 @@ struct spi_gpio { struct spi_bitbang bitbang; struct spi_gpio_platform_data pdata; struct platform_device *pdev; + int cs_gpios[0]; }; /*----------------------------------------------------------------------*/ @@ -89,15 +92,21 @@ struct spi_gpio { /*----------------------------------------------------------------------*/ -static inline const struct spi_gpio_platform_data * __pure -spi_to_pdata(const struct spi_device *spi) +static inline struct spi_gpio * __pure +spi_to_spi_gpio(const struct spi_device *spi) { const struct spi_bitbang *bang; - const struct spi_gpio *spi_gpio; + struct spi_gpio *spi_gpio; bang = spi_master_get_devdata(spi->master); spi_gpio = container_of(bang, struct spi_gpio, bitbang); - return &spi_gpio->pdata; + return spi_gpio; +} + +static inline struct spi_gpio_platform_data * __pure +spi_to_pdata(const struct spi_device *spi) +{ + return &spi_to_spi_gpio(spi)->pdata; } /* this is #defined to avoid unused-variable warnings when inlining */ @@ -210,7 +219,8 @@ static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, static void spi_gpio_chipselect(struct spi_device *spi, int is_active) { - unsigned long cs = (unsigned long) spi->controller_data; + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + unsigned int cs = spi_gpio->cs_gpios[spi->chip_select]; /* set initial clock polarity */ if (is_active) @@ -224,12 +234,27 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active) static int spi_gpio_setup(struct spi_device *spi) { - unsigned long cs = (unsigned long) spi->controller_data; - int status = 0; + unsigned int cs; + int status = 0; + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + struct device_node *np = spi->master->dev.of_node; if (spi->bits_per_word > 32) return -EINVAL; + if (np) { + /* + * In DT environments, the CS GPIOs have already been + * initialized from the "cs-gpios" property of the node. + */ + cs = spi_gpio->cs_gpios[spi->chip_select]; + } else { + /* + * ... otherwise, take it from spi->controller_data + */ + cs = (unsigned int) spi->controller_data; + } + if (!spi->controller_state) { if (cs != SPI_GPIO_NO_CHIPSELECT) { status = gpio_request(cs, dev_name(&spi->dev)); @@ -239,8 +264,12 @@ static int spi_gpio_setup(struct spi_device *spi) !(spi->mode & SPI_CS_HIGH)); } } - if (!status) + if (!status) { status = spi_bitbang_setup(spi); + /* in case it was initialized from static board data */ + spi_gpio->cs_gpios[spi->chip_select] = cs; + } + if (status) { if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT) gpio_free(cs); @@ -250,7 +279,8 @@ static int spi_gpio_setup(struct spi_device *spi) static void spi_gpio_cleanup(struct spi_device *spi) { - unsigned long cs = (unsigned long) spi->controller_data; + struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); + unsigned int cs = spi_gpio->cs_gpios[spi->chip_select]; if (cs != SPI_GPIO_NO_CHIPSELECT) gpio_free(cs); @@ -313,6 +343,55 @@ done: return value; } +#ifdef CONFIG_OF +static struct of_device_id spi_gpio_dt_ids[] = { + { .compatible = "spi-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); + +static int spi_gpio_probe_dt(struct platform_device *pdev) +{ + int ret; + u32 tmp; + struct spi_gpio_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(spi_gpio_dt_ids, &pdev->dev); + + if (!of_id) + return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->sck = of_get_named_gpio(np, "gpio-sck", 0); + pdata->miso = of_get_named_gpio(np, "gpio-miso", 0); + pdata->mosi = of_get_named_gpio(np, "gpio-mosi", 0); + + ret = of_property_read_u32(np, "num-chipselects", &tmp); + if (ret < 0) { + dev_err(&pdev->dev, "num-chipselects property not found\n"); + goto error_free; + } + + pdata->num_chipselect = tmp; + pdev->dev.platform_data = pdata; + + return 1; + +error_free: + devm_kfree(&pdev->dev, pdata); + return ret; +} +#else +static inline int spi_gpio_probe_dt(struct platform_device *pdev) +{ + return 0; +} +#endif + static int __devinit spi_gpio_probe(struct platform_device *pdev) { int status; @@ -320,6 +399,13 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev) struct spi_gpio *spi_gpio; struct spi_gpio_platform_data *pdata; u16 master_flags = 0; + bool use_of = 0; + + status = spi_gpio_probe_dt(pdev); + if (status < 0) + return status; + if (status > 0) + use_of = 1; pdata = pdev->dev.platform_data; #ifdef GENERIC_BITBANG @@ -331,7 +417,8 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev) if (status < 0) return status; - master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio); + master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) + + (sizeof(int) * SPI_N_CHIPSEL)); if (!master) { status = -ENOMEM; goto gpio_free; @@ -348,6 +435,23 @@ static int __devinit spi_gpio_probe(struct platform_device *pdev) master->num_chipselect = SPI_N_CHIPSEL; master->setup = spi_gpio_setup; master->cleanup = spi_gpio_cleanup; +#ifdef CONFIG_OF + master->dev.of_node = pdev->dev.of_node; + + if (use_of) { + int i; + struct device_node *np = pdev->dev.of_node; + + /* + * In DT environments, take the CS GPIO from the "cs-gpios" + * property of the node. + */ + + for (i = 0; i < SPI_N_CHIPSEL; i++) + spi_gpio->cs_gpios[i] = + of_get_named_gpio(np, "cs-gpios", i); + } +#endif spi_gpio->bitbang.master = spi_master_get(master); spi_gpio->bitbang.chipselect = spi_gpio_chipselect; @@ -408,8 +512,11 @@ static int __devexit spi_gpio_remove(struct platform_device *pdev) MODULE_ALIAS("platform:" DRIVER_NAME); static struct platform_driver spi_gpio_driver = { - .driver.name = DRIVER_NAME, - .driver.owner = THIS_MODULE, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(spi_gpio_dt_ids), + }, .probe = spi_gpio_probe, .remove = __devexit_p(spi_gpio_remove), }; diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index e834ff8c0188..d64655b70b59 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -197,6 +197,7 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, #define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4)) #define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8)) #define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs) + 12)) +#define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs) + 20)) #define MX51_ECSPI_INT 0x10 #define MX51_ECSPI_INT_TEEN (1 << 0) @@ -287,9 +288,10 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, if (config->mode & SPI_CPHA) cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs); - if (config->mode & SPI_CPOL) + if (config->mode & SPI_CPOL) { cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs); - + cfg |= MX51_ECSPI_CONFIG_SCLKCTL(config->cs); + } if (config->mode & SPI_CS_HIGH) cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs); diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 4c63f772780a..0a1e39e94d06 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -494,7 +494,7 @@ free_master: static int __devexit mpc512x_psc_spi_do_remove(struct device *dev) { - struct spi_master *master = 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); flush_workqueue(mps->workqueue); @@ -503,6 +503,7 @@ static int __devexit mpc512x_psc_spi_do_remove(struct device *dev) free_irq(mps->irq, mps); if (mps->psc) iounmap(mps->psc); + spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index 66047156d90d..bd47d262d53f 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -481,7 +481,7 @@ static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op) static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op) { - struct spi_master *master = dev_get_drvdata(&op->dev); + struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev)); struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master); flush_workqueue(mps->workqueue); @@ -490,6 +490,7 @@ static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op) free_irq(mps->irq, mps); if (mps->psc) iounmap(mps->psc); + spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index cb3a3830b0a5..045410650212 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -454,7 +454,7 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op) GFP_KERNEL); if (!ms->gpio_cs) { rc = -ENOMEM; - goto err_alloc; + goto err_alloc_gpio; } for (i = 0; i < ms->gpio_cs_count; i++) { @@ -514,12 +514,13 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op) err_register: dev_err(&ms->master->dev, "initialization failed\n"); - spi_master_put(master); err_gpio: while (i-- > 0) gpio_free(ms->gpio_cs[i]); kfree(ms->gpio_cs); + err_alloc_gpio: + spi_master_put(master); err_alloc: err_init: iounmap(regs); @@ -528,7 +529,7 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op) static int __devexit mpc52xx_spi_remove(struct platform_device *op) { - struct spi_master *master = dev_get_drvdata(&op->dev); + struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev)); struct mpc52xx_spi *ms = spi_master_get_devdata(master); int i; @@ -540,8 +541,8 @@ static int __devexit mpc52xx_spi_remove(struct platform_device *op) kfree(ms->gpio_cs); spi_unregister_master(master); - spi_master_put(master); iounmap(ms->regs); + spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index b2fb141da375..06684d995d3b 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -38,6 +38,8 @@ #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> +#include <linux/err.h> #include <linux/spi/spi.h> @@ -140,13 +142,6 @@ struct omap2_mcspi_cs { u32 chconf0; }; -#define MOD_REG_BIT(val, mask, set) do { \ - if (set) \ - val |= mask; \ - else \ - val &= ~mask; \ -} while (0) - static inline void mcspi_write_reg(struct spi_master *master, int idx, u32 val) { @@ -205,7 +200,11 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi, else rw = OMAP2_MCSPI_CHCONF_DMAW; - MOD_REG_BIT(l, rw, enable); + if (enable) + l |= rw; + else + l &= ~rw; + mcspi_write_chconf0(spi, l); } @@ -224,7 +223,11 @@ static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active) u32 l; l = mcspi_cached_chconf0(spi); - MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active); + if (cs_active) + l |= OMAP2_MCSPI_CHCONF_FORCE; + else + l &= ~OMAP2_MCSPI_CHCONF_FORCE; + mcspi_write_chconf0(spi, l); } @@ -239,9 +242,8 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master) * to single-channel master mode */ l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL); - MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0); - MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0); - MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1); + l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS); + l |= OMAP2_MCSPI_MODULCTRL_SINGLE; mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l); ctx->modulctrl = l; @@ -260,16 +262,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) list_for_each_entry(cs, &ctx->cs, node) __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); } -static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi) -{ - pm_runtime_mark_last_busy(mcspi->dev); - pm_runtime_put_autosuspend(mcspi->dev); -} - -static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi) -{ - return pm_runtime_get_sync(mcspi->dev); -} static int omap2_prepare_transfer(struct spi_master *master) { @@ -325,49 +317,27 @@ static void omap2_mcspi_tx_callback(void *data) omap2_mcspi_set_dma_req(spi, 0, 0); } -static unsigned -omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) +static void omap2_mcspi_tx_dma(struct spi_device *spi, + struct spi_transfer *xfer, + struct dma_slave_config cfg) { struct omap2_mcspi *mcspi; - struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi_dma *mcspi_dma; unsigned int count; - int word_len, element_count; - int elements = 0; - u32 l; u8 * rx; const u8 * tx; void __iomem *chstat_reg; - struct dma_slave_config cfg; - enum dma_slave_buswidth width; - unsigned es; + struct omap2_mcspi_cs *cs = spi->controller_state; mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; - l = mcspi_cached_chconf0(spi); + count = xfer->len; + rx = xfer->rx_buf; + tx = xfer->tx_buf; chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; - if (cs->word_len <= 8) { - width = DMA_SLAVE_BUSWIDTH_1_BYTE; - es = 1; - } else if (cs->word_len <= 16) { - width = DMA_SLAVE_BUSWIDTH_2_BYTES; - es = 2; - } else { - width = DMA_SLAVE_BUSWIDTH_4_BYTES; - es = 4; - } - - memset(&cfg, 0, sizeof(cfg)); - cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; - cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; - cfg.src_addr_width = width; - cfg.dst_addr_width = width; - cfg.src_maxburst = 1; - cfg.dst_maxburst = 1; - - if (xfer->tx_buf && mcspi_dma->dma_tx) { + if (mcspi_dma->dma_tx) { struct dma_async_tx_descriptor *tx; struct scatterlist sg; @@ -378,7 +348,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) sg_dma_len(&sg) = xfer->len; tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1, - DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (tx) { tx->callback = omap2_mcspi_tx_callback; tx->callback_param = spi; @@ -387,8 +357,50 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) /* FIXME: fall back to PIO? */ } } + dma_async_issue_pending(mcspi_dma->dma_tx); + omap2_mcspi_set_dma_req(spi, 0, 1); + + wait_for_completion(&mcspi_dma->dma_tx_completion); + dma_unmap_single(mcspi->dev, xfer->tx_dma, count, + DMA_TO_DEVICE); + + /* for TX_ONLY mode, be sure all words have shifted out */ + if (rx == NULL) { + if (mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_TXS) < 0) + dev_err(&spi->dev, "TXS timed out\n"); + else if (mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_EOT) < 0) + dev_err(&spi->dev, "EOT timed out\n"); + } +} + +static unsigned +omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, + struct dma_slave_config cfg, + unsigned es) +{ + struct omap2_mcspi *mcspi; + struct omap2_mcspi_dma *mcspi_dma; + unsigned int count; + u32 l; + int elements = 0; + int word_len, element_count; + struct omap2_mcspi_cs *cs = spi->controller_state; + mcspi = spi_master_get_devdata(spi->master); + mcspi_dma = &mcspi->dma_channels[spi->chip_select]; + count = xfer->len; + word_len = cs->word_len; + l = mcspi_cached_chconf0(spi); - if (xfer->rx_buf && mcspi_dma->dma_rx) { + if (word_len <= 8) + element_count = count; + else if (word_len <= 16) + element_count = count >> 1; + else /* word_len <= 32 */ + element_count = count >> 2; + + if (mcspi_dma->dma_rx) { struct dma_async_tx_descriptor *tx; struct scatterlist sg; size_t len = xfer->len - es; @@ -403,108 +415,120 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) sg_dma_len(&sg) = len; tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | + DMA_CTRL_ACK); if (tx) { tx->callback = omap2_mcspi_rx_callback; tx->callback_param = spi; dmaengine_submit(tx); } else { - /* FIXME: fall back to PIO? */ - } - } - - count = xfer->len; - word_len = cs->word_len; - - rx = xfer->rx_buf; - tx = xfer->tx_buf; - - if (word_len <= 8) { - element_count = count; - } else if (word_len <= 16) { - element_count = count >> 1; - } else /* word_len <= 32 */ { - element_count = count >> 2; - } - - if (tx != NULL) { - dma_async_issue_pending(mcspi_dma->dma_tx); - omap2_mcspi_set_dma_req(spi, 0, 1); - } - - if (rx != NULL) { - dma_async_issue_pending(mcspi_dma->dma_rx); - omap2_mcspi_set_dma_req(spi, 1, 1); - } - - if (tx != NULL) { - wait_for_completion(&mcspi_dma->dma_tx_completion); - dma_unmap_single(mcspi->dev, xfer->tx_dma, count, - DMA_TO_DEVICE); - - /* for TX_ONLY mode, be sure all words have shifted out */ - if (rx == NULL) { - if (mcspi_wait_for_reg_bit(chstat_reg, - OMAP2_MCSPI_CHSTAT_TXS) < 0) - dev_err(&spi->dev, "TXS timed out\n"); - else if (mcspi_wait_for_reg_bit(chstat_reg, - OMAP2_MCSPI_CHSTAT_EOT) < 0) - dev_err(&spi->dev, "EOT timed out\n"); + /* FIXME: fall back to PIO? */ } } - if (rx != NULL) { - wait_for_completion(&mcspi_dma->dma_rx_completion); - dma_unmap_single(mcspi->dev, xfer->rx_dma, count, - DMA_FROM_DEVICE); - omap2_mcspi_set_enable(spi, 0); + dma_async_issue_pending(mcspi_dma->dma_rx); + omap2_mcspi_set_dma_req(spi, 1, 1); - elements = element_count - 1; + wait_for_completion(&mcspi_dma->dma_rx_completion); + dma_unmap_single(mcspi->dev, xfer->rx_dma, count, + DMA_FROM_DEVICE); + omap2_mcspi_set_enable(spi, 0); - if (l & OMAP2_MCSPI_CHCONF_TURBO) { - elements--; + elements = element_count - 1; - if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) - & OMAP2_MCSPI_CHSTAT_RXS)) { - u32 w; - - w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); - if (word_len <= 8) - ((u8 *)xfer->rx_buf)[elements++] = w; - else if (word_len <= 16) - ((u16 *)xfer->rx_buf)[elements++] = w; - else /* word_len <= 32 */ - ((u32 *)xfer->rx_buf)[elements++] = w; - } else { - dev_err(&spi->dev, - "DMA RX penultimate word empty"); - count -= (word_len <= 8) ? 2 : - (word_len <= 16) ? 4 : - /* word_len <= 32 */ 8; - omap2_mcspi_set_enable(spi, 1); - return count; - } - } + if (l & OMAP2_MCSPI_CHCONF_TURBO) { + elements--; if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) - & OMAP2_MCSPI_CHSTAT_RXS)) { + & OMAP2_MCSPI_CHSTAT_RXS)) { u32 w; w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); if (word_len <= 8) - ((u8 *)xfer->rx_buf)[elements] = w; + ((u8 *)xfer->rx_buf)[elements++] = w; else if (word_len <= 16) - ((u16 *)xfer->rx_buf)[elements] = w; + ((u16 *)xfer->rx_buf)[elements++] = w; else /* word_len <= 32 */ - ((u32 *)xfer->rx_buf)[elements] = w; + ((u32 *)xfer->rx_buf)[elements++] = w; } else { - dev_err(&spi->dev, "DMA RX last word empty"); - count -= (word_len <= 8) ? 1 : - (word_len <= 16) ? 2 : - /* word_len <= 32 */ 4; + dev_err(&spi->dev, "DMA RX penultimate word empty"); + count -= (word_len <= 8) ? 2 : + (word_len <= 16) ? 4 : + /* word_len <= 32 */ 8; + omap2_mcspi_set_enable(spi, 1); + return count; } - omap2_mcspi_set_enable(spi, 1); } + if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) + & OMAP2_MCSPI_CHSTAT_RXS)) { + u32 w; + + w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); + if (word_len <= 8) + ((u8 *)xfer->rx_buf)[elements] = w; + else if (word_len <= 16) + ((u16 *)xfer->rx_buf)[elements] = w; + else /* word_len <= 32 */ + ((u32 *)xfer->rx_buf)[elements] = w; + } else { + dev_err(&spi->dev, "DMA RX last word empty"); + count -= (word_len <= 8) ? 1 : + (word_len <= 16) ? 2 : + /* word_len <= 32 */ 4; + } + omap2_mcspi_set_enable(spi, 1); + return count; +} + +static unsigned +omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) +{ + struct omap2_mcspi *mcspi; + struct omap2_mcspi_cs *cs = spi->controller_state; + struct omap2_mcspi_dma *mcspi_dma; + unsigned int count; + u32 l; + u8 *rx; + const u8 *tx; + struct dma_slave_config cfg; + enum dma_slave_buswidth width; + unsigned es; + + mcspi = spi_master_get_devdata(spi->master); + mcspi_dma = &mcspi->dma_channels[spi->chip_select]; + l = mcspi_cached_chconf0(spi); + + + if (cs->word_len <= 8) { + width = DMA_SLAVE_BUSWIDTH_1_BYTE; + es = 1; + } else if (cs->word_len <= 16) { + width = DMA_SLAVE_BUSWIDTH_2_BYTES; + es = 2; + } else { + width = DMA_SLAVE_BUSWIDTH_4_BYTES; + es = 4; + } + + memset(&cfg, 0, sizeof(cfg)); + cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; + cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; + cfg.src_addr_width = width; + cfg.dst_addr_width = width; + cfg.src_maxburst = 1; + cfg.dst_maxburst = 1; + + rx = xfer->rx_buf; + tx = xfer->tx_buf; + + count = xfer->len; + + if (tx != NULL) + omap2_mcspi_tx_dma(spi, xfer, cfg); + + if (rx != NULL) + return omap2_mcspi_rx_dma(spi, xfer, cfg, es); + return count; } @@ -848,12 +872,13 @@ static int omap2_mcspi_setup(struct spi_device *spi) return ret; } - ret = omap2_mcspi_enable_clocks(mcspi); + ret = pm_runtime_get_sync(mcspi->dev); if (ret < 0) return ret; ret = omap2_mcspi_setup_transfer(spi, NULL); - omap2_mcspi_disable_clocks(mcspi); + pm_runtime_mark_last_busy(mcspi->dev); + pm_runtime_put_autosuspend(mcspi->dev); return ret; } @@ -1067,7 +1092,7 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) struct omap2_mcspi_regs *ctx = &mcspi->ctx; int ret = 0; - ret = omap2_mcspi_enable_clocks(mcspi); + ret = pm_runtime_get_sync(mcspi->dev); if (ret < 0) return ret; @@ -1076,7 +1101,8 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; omap2_mcspi_set_master_mode(master); - omap2_mcspi_disable_clocks(mcspi); + pm_runtime_mark_last_busy(mcspi->dev); + pm_runtime_put_autosuspend(mcspi->dev); return 0; } @@ -1124,6 +1150,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) static int bus_num = 1; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; + struct pinctrl *pinctrl; master = spi_alloc_master(&pdev->dev, sizeof *mcspi); if (master == NULL) { @@ -1219,6 +1246,11 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) if (status < 0) goto dma_chnl_free; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, + "pins are not configured from the driver\n"); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_enable(&pdev->dev); @@ -1238,7 +1270,6 @@ dma_chnl_free: kfree(mcspi->dma_channels); free_master: spi_master_put(master); - platform_set_drvdata(pdev, NULL); return status; } @@ -1252,12 +1283,11 @@ static int __devexit omap2_mcspi_remove(struct platform_device *pdev) mcspi = spi_master_get_devdata(master); dma_channels = mcspi->dma_channels; - omap2_mcspi_disable_clocks(mcspi); + pm_runtime_put_sync(mcspi->dev); pm_runtime_disable(&pdev->dev); spi_unregister_master(master); kfree(dma_channels); - platform_set_drvdata(pdev, NULL); return 0; } @@ -1278,20 +1308,21 @@ static int omap2_mcspi_resume(struct device *dev) struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_cs *cs; - omap2_mcspi_enable_clocks(mcspi); + pm_runtime_get_sync(mcspi->dev); list_for_each_entry(cs, &ctx->cs, node) { if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { /* * We need to toggle CS state for OMAP take this * change in account. */ - MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1); + cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE; __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); - MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0); + cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); } } - omap2_mcspi_disable_clocks(mcspi); + pm_runtime_mark_last_busy(mcspi->dev); + pm_runtime_put_autosuspend(mcspi->dev); return 0; } #else diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 9b0caddce503..b17c09cf0a05 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -36,12 +36,6 @@ #define ORION_SPI_CLK_PRESCALE_MASK 0x1F struct orion_spi { - struct work_struct work; - - /* Lock access to transfer list. */ - spinlock_t lock; - - struct list_head msg_queue; struct spi_master *master; void __iomem *base; unsigned int max_speed; @@ -49,8 +43,6 @@ struct orion_spi { struct clk *clk; }; -static struct workqueue_struct *orion_spi_wq; - static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) { return orion_spi->base + reg; @@ -277,73 +269,78 @@ out: } -static void orion_spi_work(struct work_struct *work) +static int orion_spi_transfer_one_message(struct spi_master *master, + struct spi_message *m) { - struct orion_spi *orion_spi = - container_of(work, struct orion_spi, work); - - spin_lock_irq(&orion_spi->lock); - while (!list_empty(&orion_spi->msg_queue)) { - struct spi_message *m; - struct spi_device *spi; - struct spi_transfer *t = NULL; - int par_override = 0; - int status = 0; - int cs_active = 0; - - m = container_of(orion_spi->msg_queue.next, struct spi_message, - queue); + struct orion_spi *orion_spi = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + struct spi_transfer *t = NULL; + int par_override = 0; + int status = 0; + int cs_active = 0; - list_del_init(&m->queue); - spin_unlock_irq(&orion_spi->lock); + /* Load defaults */ + status = orion_spi_setup_transfer(spi, NULL); - spi = m->spi; + if (status < 0) + goto msg_done; - /* Load defaults */ - status = orion_spi_setup_transfer(spi, NULL); + list_for_each_entry(t, &m->transfers, transfer_list) { + /* make sure buffer length is even when working in 16 + * bit mode*/ + if ((t->bits_per_word == 16) && (t->len & 1)) { + dev_err(&spi->dev, + "message rejected : " + "odd data length %d while in 16 bit mode\n", + t->len); + status = -EIO; + goto msg_done; + } - if (status < 0) + if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { + dev_err(&spi->dev, + "message rejected : " + "device min speed (%d Hz) exceeds " + "required transfer speed (%d Hz)\n", + orion_spi->min_speed, t->speed_hz); + status = -EIO; goto msg_done; + } - list_for_each_entry(t, &m->transfers, transfer_list) { - if (par_override || t->speed_hz || t->bits_per_word) { - par_override = 1; - status = orion_spi_setup_transfer(spi, t); - if (status < 0) - break; - if (!t->speed_hz && !t->bits_per_word) - par_override = 0; - } - - if (!cs_active) { - orion_spi_set_cs(orion_spi, 1); - cs_active = 1; - } - - if (t->len) - m->actual_length += - orion_spi_write_read(spi, t); - - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (t->cs_change) { - orion_spi_set_cs(orion_spi, 0); - cs_active = 0; - } + if (par_override || t->speed_hz || t->bits_per_word) { + par_override = 1; + status = orion_spi_setup_transfer(spi, t); + if (status < 0) + break; + if (!t->speed_hz && !t->bits_per_word) + par_override = 0; } -msg_done: - if (cs_active) - orion_spi_set_cs(orion_spi, 0); + if (!cs_active) { + orion_spi_set_cs(orion_spi, 1); + cs_active = 1; + } - m->status = status; - m->complete(m->context); + if (t->len) + m->actual_length += orion_spi_write_read(spi, t); - spin_lock_irq(&orion_spi->lock); + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (t->cs_change) { + orion_spi_set_cs(orion_spi, 0); + cs_active = 0; + } } - spin_unlock_irq(&orion_spi->lock); +msg_done: + if (cs_active) + orion_spi_set_cs(orion_spi, 0); + + m->status = status; + spi_finalize_current_message(master); + + return 0; } static int __init orion_spi_reset(struct orion_spi *orion_spi) @@ -376,75 +373,6 @@ static int orion_spi_setup(struct spi_device *spi) return 0; } -static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m) -{ - struct orion_spi *orion_spi; - struct spi_transfer *t = NULL; - unsigned long flags; - - m->actual_length = 0; - m->status = 0; - - /* reject invalid messages and transfers */ - if (list_empty(&m->transfers) || !m->complete) - return -EINVAL; - - orion_spi = spi_master_get_devdata(spi->master); - - list_for_each_entry(t, &m->transfers, transfer_list) { - unsigned int bits_per_word = spi->bits_per_word; - - if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { - dev_err(&spi->dev, - "message rejected : " - "invalid transfer data buffers\n"); - goto msg_rejected; - } - - if (t->bits_per_word) - bits_per_word = t->bits_per_word; - - if ((bits_per_word != 8) && (bits_per_word != 16)) { - dev_err(&spi->dev, - "message rejected : " - "invalid transfer bits_per_word (%d bits)\n", - bits_per_word); - goto msg_rejected; - } - /*make sure buffer length is even when working in 16 bit mode*/ - if ((t->bits_per_word == 16) && (t->len & 1)) { - dev_err(&spi->dev, - "message rejected : " - "odd data length (%d) while in 16 bit mode\n", - t->len); - goto msg_rejected; - } - - if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { - dev_err(&spi->dev, - "message rejected : " - "device min speed (%d Hz) exceeds " - "required transfer speed (%d Hz)\n", - orion_spi->min_speed, t->speed_hz); - goto msg_rejected; - } - } - - - spin_lock_irqsave(&orion_spi->lock, flags); - list_add_tail(&m->queue, &orion_spi->msg_queue); - queue_work(orion_spi_wq, &orion_spi->work); - spin_unlock_irqrestore(&orion_spi->lock, flags); - - return 0; -msg_rejected: - /* Message rejected and not queued */ - m->status = -EINVAL; - if (m->complete) - m->complete(m->context); - return -EINVAL; -} - static int __init orion_spi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -474,7 +402,7 @@ static int __init orion_spi_probe(struct platform_device *pdev) master->mode_bits = 0; master->setup = orion_spi_setup; - master->transfer = orion_spi_transfer; + master->transfer_one_message = orion_spi_transfer_one_message; master->num_chipselect = ORION_NUM_CHIPSELECTS; dev_set_drvdata(&pdev->dev, master); @@ -507,11 +435,6 @@ static int __init orion_spi_probe(struct platform_device *pdev) } spi->base = ioremap(r->start, SZ_1K); - INIT_WORK(&spi->work, orion_spi_work); - - spin_lock_init(&spi->lock); - INIT_LIST_HEAD(&spi->msg_queue); - if (orion_spi_reset(spi) < 0) goto out_rel_mem; @@ -536,14 +459,12 @@ out: static int __exit orion_spi_remove(struct platform_device *pdev) { struct spi_master *master; - struct orion_spi *spi; struct resource *r; + struct orion_spi *spi; master = dev_get_drvdata(&pdev->dev); spi = spi_master_get_devdata(master); - cancel_work_sync(&spi->work); - clk_disable_unprepare(spi->clk); clk_put(spi->clk); @@ -574,21 +495,13 @@ static struct platform_driver orion_spi_driver = { static int __init orion_spi_init(void) { - orion_spi_wq = create_singlethread_workqueue( - orion_spi_driver.driver.name); - if (orion_spi_wq == NULL) - return -ENOMEM; - return platform_driver_probe(&orion_spi_driver, orion_spi_probe); } module_init(orion_spi_init); static void __exit orion_spi_exit(void) { - flush_workqueue(orion_spi_wq); platform_driver_unregister(&orion_spi_driver); - - destroy_workqueue(orion_spi_wq); } module_exit(orion_spi_exit); diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 6abbe23c39b4..919464102d33 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1,7 +1,7 @@ /* * A driver for the ARM PL022 PrimeCell SSP/SPI bus master. * - * Copyright (C) 2008-2009 ST-Ericsson AB + * Copyright (C) 2008-2012 ST-Ericsson AB * Copyright (C) 2006 STMicroelectronics Pvt. Ltd. * * Author: Linus Walleij <linus.walleij@stericsson.com> @@ -40,6 +40,9 @@ #include <linux/dma-mapping.h> #include <linux/scatterlist.h> #include <linux/pm_runtime.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> /* * This macro is used to define some register default values. @@ -356,6 +359,8 @@ struct vendor_data { * @sgt_rx: scattertable for the RX transfer * @sgt_tx: scattertable for the TX transfer * @dummypage: a dummy page used for driving data on the bus with DMA + * @cur_cs: current chip select (gpio) + * @chipselects: list of chipselects (gpios) */ struct pl022 { struct amba_device *adev; @@ -363,6 +368,10 @@ struct pl022 { resource_size_t phybase; void __iomem *virtbase; struct clk *clk; + /* Two optional pin states - default & sleep */ + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_sleep; struct spi_master *master; struct pl022_ssp_controller *master_info; /* Message per-transfer pump */ @@ -389,6 +398,8 @@ struct pl022 { char *dummypage; bool dma_running; #endif + int cur_cs; + int *chipselects; }; /** @@ -433,6 +444,14 @@ static void null_cs_control(u32 command) pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); } +static void pl022_cs_control(struct pl022 *pl022, u32 command) +{ + if (gpio_is_valid(pl022->cur_cs)) + gpio_set_value(pl022->cur_cs, command); + else + pl022->cur_chip->cs_control(command); +} + /** * giveback - current spi_message is over, schedule next message and call * callback of this message. Assumes that caller already @@ -479,7 +498,7 @@ static void giveback(struct pl022 *pl022) if (next_msg && next_msg->spi != pl022->cur_msg->spi) next_msg = NULL; if (!next_msg || pl022->cur_msg->state == STATE_ERROR) - pl022->cur_chip->cs_control(SSP_CHIP_DESELECT); + pl022_cs_control(pl022, SSP_CHIP_DESELECT); else pl022->next_msg_cs_active = true; @@ -818,8 +837,7 @@ static void dma_callback(void *data) /* Update total bytes transferred */ msg->actual_length += pl022->cur_transfer->len; if (pl022->cur_transfer->cs_change) - pl022->cur_chip-> - cs_control(SSP_CHIP_DESELECT); + pl022_cs_control(pl022, SSP_CHIP_DESELECT); /* Move to next transfer */ msg->state = next_transfer(pl022); @@ -1252,8 +1270,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) /* Update total bytes transferred */ msg->actual_length += pl022->cur_transfer->len; if (pl022->cur_transfer->cs_change) - pl022->cur_chip-> - cs_control(SSP_CHIP_DESELECT); + pl022_cs_control(pl022, SSP_CHIP_DESELECT); /* Move to next transfer */ msg->state = next_transfer(pl022); tasklet_schedule(&pl022->pump_transfers); @@ -1338,7 +1355,7 @@ static void pump_transfers(unsigned long data) /* Reselect chip select only if cs_change was requested */ if (previous->cs_change) - pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + pl022_cs_control(pl022, SSP_CHIP_SELECT); } else { /* STATE_START */ message->state = STATE_RUNNING; @@ -1377,7 +1394,7 @@ static void do_interrupt_dma_transfer(struct pl022 *pl022) /* Enable target chip, if not already active */ if (!pl022->next_msg_cs_active) - pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + pl022_cs_control(pl022, SSP_CHIP_SELECT); if (set_up_next_transfer(pl022, pl022->cur_transfer)) { /* Error path */ @@ -1429,12 +1446,12 @@ static void do_polling_transfer(struct pl022 *pl022) if (previous->delay_usecs) udelay(previous->delay_usecs); if (previous->cs_change) - pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + pl022_cs_control(pl022, SSP_CHIP_SELECT); } else { /* STATE_START */ message->state = STATE_RUNNING; if (!pl022->next_msg_cs_active) - pl022->cur_chip->cs_control(SSP_CHIP_SELECT); + pl022_cs_control(pl022, SSP_CHIP_SELECT); } /* Configuration Changing Per Transfer */ @@ -1466,7 +1483,7 @@ static void do_polling_transfer(struct pl022 *pl022) /* Update total byte transferred */ message->actual_length += pl022->cur_transfer->len; if (pl022->cur_transfer->cs_change) - pl022->cur_chip->cs_control(SSP_CHIP_DESELECT); + pl022_cs_control(pl022, SSP_CHIP_DESELECT); /* Move to next transfer */ message->state = next_transfer(pl022); } @@ -1495,6 +1512,7 @@ static int pl022_transfer_one_message(struct spi_master *master, /* Setup the SPI using the per chip configuration */ pl022->cur_chip = spi_get_ctldata(msg->spi); + pl022->cur_cs = pl022->chipselects[msg->spi->chip_select]; restore_state(pl022); flush(pl022); @@ -1766,12 +1784,14 @@ static const struct pl022_config_chip pl022_default_chip_info = { static int pl022_setup(struct spi_device *spi) { struct pl022_config_chip const *chip_info; + struct pl022_config_chip chip_info_dt; struct chip_data *chip; 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; u32 tmp; + struct device_node *np = spi->dev.of_node; if (!spi->max_speed_hz) return -EINVAL; @@ -1794,10 +1814,32 @@ static int pl022_setup(struct spi_device *spi) chip_info = spi->controller_data; if (chip_info == NULL) { - chip_info = &pl022_default_chip_info; - /* spi_board_info.controller_data not is supplied */ - dev_dbg(&spi->dev, - "using default controller_data settings\n"); + if (np) { + chip_info_dt = pl022_default_chip_info; + + chip_info_dt.hierarchy = SSP_MASTER; + of_property_read_u32(np, "pl022,interface", + &chip_info_dt.iface); + of_property_read_u32(np, "pl022,com-mode", + &chip_info_dt.com_mode); + of_property_read_u32(np, "pl022,rx-level-trig", + &chip_info_dt.rx_lev_trig); + of_property_read_u32(np, "pl022,tx-level-trig", + &chip_info_dt.tx_lev_trig); + of_property_read_u32(np, "pl022,ctrl-len", + &chip_info_dt.ctrl_len); + of_property_read_u32(np, "pl022,wait-state", + &chip_info_dt.wait_state); + of_property_read_u32(np, "pl022,duplex", + &chip_info_dt.duplex); + + chip_info = &chip_info_dt; + } else { + chip_info = &pl022_default_chip_info; + /* spi_board_info.controller_data not is supplied */ + dev_dbg(&spi->dev, + "using default controller_data settings\n"); + } } else dev_dbg(&spi->dev, "using user supplied controller_data settings\n"); @@ -1840,8 +1882,9 @@ static int pl022_setup(struct spi_device *spi) chip->xfer_type = chip_info->com_mode; if (!chip_info->cs_control) { chip->cs_control = null_cs_control; - dev_warn(&spi->dev, - "chip select function is NULL for this chip\n"); + if (!gpio_is_valid(pl022->chipselects[spi->chip_select])) + dev_warn(&spi->dev, + "invalid chip select\n"); } else chip->cs_control = chip_info->cs_control; @@ -1986,6 +2029,34 @@ static void pl022_cleanup(struct spi_device *spi) kfree(chip); } +static struct pl022_ssp_controller * +pl022_platform_data_dt_get(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct pl022_ssp_controller *pd; + u32 tmp; + + if (!np) { + dev_err(dev, "no dt node defined\n"); + return NULL; + } + + pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL); + if (!pd) { + dev_err(dev, "cannot allocate platform data memory\n"); + return NULL; + } + + pd->bus_id = -1; + of_property_read_u32(np, "num-cs", &tmp); + pd->num_chipselect = tmp; + of_property_read_u32(np, "pl022,autosuspend-delay", + &pd->autosuspend_delay); + pd->rt = of_property_read_bool(np, "pl022,rt"); + + return pd; +} + static int __devinit pl022_probe(struct amba_device *adev, const struct amba_id *id) { @@ -1993,22 +2064,31 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) struct pl022_ssp_controller *platform_info = adev->dev.platform_data; struct spi_master *master; struct pl022 *pl022 = NULL; /*Data for this driver */ - int status = 0; + struct device_node *np = adev->dev.of_node; + int status = 0, i, num_cs; dev_info(&adev->dev, "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); - if (platform_info == NULL) { - dev_err(&adev->dev, "probe - no platform data supplied\n"); - status = -ENODEV; - goto err_no_pdata; + if (!platform_info && IS_ENABLED(CONFIG_OF)) + platform_info = pl022_platform_data_dt_get(dev); + + if (!platform_info) { + dev_err(dev, "probe: no platform data defined\n"); + return -ENODEV; + } + + if (platform_info->num_chipselect) { + num_cs = platform_info->num_chipselect; + } else { + dev_err(dev, "probe: no chip select defined\n"); + return -ENODEV; } /* Allocate master with space for data */ master = spi_alloc_master(dev, sizeof(struct pl022)); if (master == NULL) { dev_err(&adev->dev, "probe - cannot alloc SPI master\n"); - status = -ENOMEM; - goto err_no_master; + return -ENOMEM; } pl022 = spi_master_get_devdata(master); @@ -2016,19 +2096,71 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) pl022->master_info = platform_info; pl022->adev = adev; pl022->vendor = id->data; + pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int), + GFP_KERNEL); + + pl022->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(pl022->pinctrl)) { + status = PTR_ERR(pl022->pinctrl); + goto err_no_pinctrl; + } + + pl022->pins_default = pinctrl_lookup_state(pl022->pinctrl, + PINCTRL_STATE_DEFAULT); + /* enable pins to be muxed in and configured */ + if (!IS_ERR(pl022->pins_default)) { + status = pinctrl_select_state(pl022->pinctrl, + pl022->pins_default); + if (status) + dev_err(dev, "could not set default pins\n"); + } else + dev_err(dev, "could not get default pinstate\n"); + + pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl, + PINCTRL_STATE_SLEEP); + if (IS_ERR(pl022->pins_sleep)) + dev_dbg(dev, "could not get sleep pinstate\n"); /* * Bus Number Which has been Assigned to this SSP controller * on this board */ master->bus_num = platform_info->bus_id; - master->num_chipselect = platform_info->num_chipselect; + master->num_chipselect = num_cs; master->cleanup = pl022_cleanup; master->setup = pl022_setup; master->prepare_transfer_hardware = pl022_prepare_transfer_hardware; master->transfer_one_message = pl022_transfer_one_message; master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; master->rt = platform_info->rt; + master->dev.of_node = dev->of_node; + + if (platform_info->num_chipselect && platform_info->chipselects) { + for (i = 0; i < num_cs; i++) + pl022->chipselects[i] = platform_info->chipselects[i]; + } else if (IS_ENABLED(CONFIG_OF)) { + for (i = 0; i < num_cs; i++) { + int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); + + if (cs_gpio == -EPROBE_DEFER) { + status = -EPROBE_DEFER; + goto err_no_gpio; + } + + pl022->chipselects[i] = cs_gpio; + + if (gpio_is_valid(cs_gpio)) { + if (devm_gpio_request(dev, cs_gpio, "ssp-pl022")) + dev_err(&adev->dev, + "could not request %d gpio\n", + cs_gpio); + else if (gpio_direction_output(cs_gpio, 1)) + dev_err(&adev->dev, + "could set gpio %d as output\n", + cs_gpio); + } + } + } /* * Supports mode 0-3, loopback, and active low CS. Transfers are @@ -2045,7 +2177,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_ioregion; pl022->phybase = adev->res.start; - pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res)); + pl022->virtbase = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); if (pl022->virtbase == NULL) { status = -ENOMEM; goto err_no_ioremap; @@ -2055,7 +2188,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) pm_runtime_resume(dev); - pl022->clk = clk_get(&adev->dev, NULL); + pl022->clk = devm_clk_get(&adev->dev, NULL); if (IS_ERR(pl022->clk)) { status = PTR_ERR(pl022->clk); dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); @@ -2083,8 +2216,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) SSP_CR1(pl022->virtbase)); load_ssp_default_config(pl022); - status = request_irq(adev->irq[0], pl022_interrupt_handler, 0, "pl022", - pl022); + status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, + 0, "pl022", pl022); if (status < 0) { dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status); goto err_no_irq; @@ -2124,22 +2257,18 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) err_spi_register: if (platform_info->enable_dma) pl022_dma_remove(pl022); - - free_irq(adev->irq[0], pl022); 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); err_no_ioremap: amba_release_regions(adev); err_no_ioregion: + err_no_gpio: + err_no_pinctrl: spi_master_put(master); - err_no_master: - err_no_pdata: return status; } @@ -2161,20 +2290,55 @@ pl022_remove(struct amba_device *adev) if (pl022->master_info->enable_dma) pl022_dma_remove(pl022); - free_irq(adev->irq[0], pl022); clk_disable(pl022->clk); clk_unprepare(pl022->clk); - clk_put(pl022->clk); pm_runtime_disable(&adev->dev); - iounmap(pl022->virtbase); amba_release_regions(adev); tasklet_disable(&pl022->pump_transfers); spi_unregister_master(pl022->master); - spi_master_put(pl022->master); amba_set_drvdata(adev, NULL); return 0; } +#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME) +/* + * These two functions are used from both suspend/resume and + * the runtime counterparts to handle external resources like + * clocks, pins and regulators when going to sleep. + */ +static void pl022_suspend_resources(struct pl022 *pl022) +{ + int ret; + + clk_disable(pl022->clk); + + /* Optionally let pins go into sleep states */ + if (!IS_ERR(pl022->pins_sleep)) { + ret = pinctrl_select_state(pl022->pinctrl, + pl022->pins_sleep); + if (ret) + dev_err(&pl022->adev->dev, + "could not set pins to sleep state\n"); + } +} + +static void pl022_resume_resources(struct pl022 *pl022) +{ + int ret; + + /* Optionaly enable pins to be muxed in and configured */ + if (!IS_ERR(pl022->pins_default)) { + ret = pinctrl_select_state(pl022->pinctrl, + pl022->pins_default); + if (ret) + dev_err(&pl022->adev->dev, + "could not set default pins\n"); + } + + clk_enable(pl022->clk); +} +#endif + #ifdef CONFIG_SUSPEND static int pl022_suspend(struct device *dev) { @@ -2186,6 +2350,7 @@ static int pl022_suspend(struct device *dev) dev_warn(dev, "cannot suspend master\n"); return ret; } + pl022_suspend_resources(pl022); dev_dbg(dev, "suspended\n"); return 0; @@ -2196,6 +2361,8 @@ static int pl022_resume(struct device *dev) struct pl022 *pl022 = dev_get_drvdata(dev); int ret; + pl022_resume_resources(pl022); + /* Start the queue running */ ret = spi_master_resume(pl022->master); if (ret) @@ -2212,8 +2379,7 @@ static int pl022_runtime_suspend(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - clk_disable(pl022->clk); - + pl022_suspend_resources(pl022); return 0; } @@ -2221,8 +2387,7 @@ static int pl022_runtime_resume(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - clk_enable(pl022->clk); - + pl022_resume_resources(pl022); return 0; } #endif diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 8ee7d790ce49..a2a080b7f42b 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -611,6 +611,7 @@ static int __devinit s3c24xx_spi_probe(struct platform_device *pdev) if (!pdata->set_cs) { if (pdata->pin_cs < 0) { dev_err(&pdev->dev, "No chipselect pin\n"); + err = -EINVAL; goto err_register; } diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index d1c8441f638c..a2062b231a6b 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -976,7 +976,8 @@ err_msgq: spi_set_ctldata(spi, NULL); err_gpio_req: - kfree(cs); + if (spi->dev.of_node) + kfree(cs); return err; } @@ -1409,7 +1410,7 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int s3c64xx_spi_suspend(struct device *dev) { - struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct spi_master *master = dev_get_drvdata(dev); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); spi_master_suspend(master); @@ -1428,7 +1429,7 @@ static int s3c64xx_spi_suspend(struct device *dev) static int s3c64xx_spi_resume(struct device *dev) { - struct spi_master *master = spi_master_get(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_info *sci = sdd->cntrlr_info; @@ -1452,7 +1453,7 @@ static int s3c64xx_spi_resume(struct device *dev) #ifdef CONFIG_PM_RUNTIME static int s3c64xx_spi_runtime_suspend(struct device *dev) { - struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct spi_master *master = dev_get_drvdata(dev); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); clk_disable(sdd->clk); @@ -1463,7 +1464,7 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev) static int s3c64xx_spi_runtime_resume(struct device *dev) { - struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct spi_master *master = dev_get_drvdata(dev); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); clk_enable(sdd->src_clk); diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c new file mode 100644 index 000000000000..9eda21d739c6 --- /dev/null +++ b/drivers/spi/spi-sc18is602.c @@ -0,0 +1,364 @@ +/* + * NXP SC18IS602/603 SPI driver + * + * Copyright (C) Guenter Roeck <linux@roeck-us.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/platform_data/sc18is602.h> + +enum chips { sc18is602, sc18is602b, sc18is603 }; + +#define SC18IS602_BUFSIZ 200 +#define SC18IS602_CLOCK 7372000 + +#define SC18IS602_MODE_CPHA BIT(2) +#define SC18IS602_MODE_CPOL BIT(3) +#define SC18IS602_MODE_LSB_FIRST BIT(5) +#define SC18IS602_MODE_CLOCK_DIV_4 0x0 +#define SC18IS602_MODE_CLOCK_DIV_16 0x1 +#define SC18IS602_MODE_CLOCK_DIV_64 0x2 +#define SC18IS602_MODE_CLOCK_DIV_128 0x3 + +struct sc18is602 { + struct spi_master *master; + struct device *dev; + u8 ctrl; + u32 freq; + u32 speed; + + /* I2C data */ + struct i2c_client *client; + enum chips id; + u8 buffer[SC18IS602_BUFSIZ + 1]; + int tlen; /* Data queued for tx in buffer */ + int rindex; /* Receive data index in buffer */ +}; + +static int sc18is602_wait_ready(struct sc18is602 *hw, int len) +{ + int i, err; + int usecs = 1000000 * len / hw->speed + 1; + u8 dummy[1]; + + for (i = 0; i < 10; i++) { + err = i2c_master_recv(hw->client, dummy, 1); + if (err >= 0) + return 0; + usleep_range(usecs, usecs * 2); + } + return -ETIMEDOUT; +} + +static int sc18is602_txrx(struct sc18is602 *hw, struct spi_message *msg, + struct spi_transfer *t, bool do_transfer) +{ + unsigned int len = t->len; + int ret; + + if (hw->tlen == 0) { + /* First byte (I2C command) is chip select */ + hw->buffer[0] = 1 << msg->spi->chip_select; + hw->tlen = 1; + hw->rindex = 0; + } + /* + * We can not immediately send data to the chip, since each I2C message + * resembles a full SPI message (from CS active to CS inactive). + * Enqueue messages up to the first read or until do_transfer is true. + */ + if (t->tx_buf) { + memcpy(&hw->buffer[hw->tlen], t->tx_buf, len); + hw->tlen += len; + if (t->rx_buf) + do_transfer = true; + else + hw->rindex = hw->tlen - 1; + } else if (t->rx_buf) { + /* + * For receive-only transfers we still need to perform a dummy + * write to receive data from the SPI chip. + * Read data starts at the end of transmit data (minus 1 to + * account for CS). + */ + hw->rindex = hw->tlen - 1; + memset(&hw->buffer[hw->tlen], 0, len); + hw->tlen += len; + do_transfer = true; + } + + if (do_transfer && hw->tlen > 1) { + ret = sc18is602_wait_ready(hw, SC18IS602_BUFSIZ); + if (ret < 0) + return ret; + ret = i2c_master_send(hw->client, hw->buffer, hw->tlen); + if (ret < 0) + return ret; + if (ret != hw->tlen) + return -EIO; + + if (t->rx_buf) { + int rlen = hw->rindex + len; + + ret = sc18is602_wait_ready(hw, hw->tlen); + if (ret < 0) + return ret; + ret = i2c_master_recv(hw->client, hw->buffer, rlen); + if (ret < 0) + return ret; + if (ret != rlen) + return -EIO; + memcpy(t->rx_buf, &hw->buffer[hw->rindex], len); + } + hw->tlen = 0; + } + return len; +} + +static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode) +{ + u8 ctrl = 0; + int ret; + + if (mode & SPI_CPHA) + ctrl |= SC18IS602_MODE_CPHA; + if (mode & SPI_CPOL) + ctrl |= SC18IS602_MODE_CPOL; + if (mode & SPI_LSB_FIRST) + ctrl |= SC18IS602_MODE_LSB_FIRST; + + /* Find the closest clock speed */ + if (hz >= hw->freq / 4) { + ctrl |= SC18IS602_MODE_CLOCK_DIV_4; + hw->speed = hw->freq / 4; + } else if (hz >= hw->freq / 16) { + ctrl |= SC18IS602_MODE_CLOCK_DIV_16; + hw->speed = hw->freq / 16; + } else if (hz >= hw->freq / 64) { + ctrl |= SC18IS602_MODE_CLOCK_DIV_64; + hw->speed = hw->freq / 64; + } else { + ctrl |= SC18IS602_MODE_CLOCK_DIV_128; + hw->speed = hw->freq / 128; + } + + /* + * Don't do anything if the control value did not change. The initial + * value of 0xff for hw->ctrl ensures that the correct mode will be set + * with the first call to this function. + */ + if (ctrl == hw->ctrl) + return 0; + + ret = i2c_smbus_write_byte_data(hw->client, 0xf0, ctrl); + if (ret < 0) + return ret; + + hw->ctrl = ctrl; + + return 0; +} + +static int sc18is602_check_transfer(struct spi_device *spi, + struct spi_transfer *t, int tlen) +{ + int bpw; + uint32_t hz; + + if (t && t->len + tlen > SC18IS602_BUFSIZ) + return -EINVAL; + + bpw = spi->bits_per_word; + if (t && t->bits_per_word) + bpw = t->bits_per_word; + if (bpw != 8) + return -EINVAL; + + hz = spi->max_speed_hz; + if (t && t->speed_hz) + hz = t->speed_hz; + if (hz == 0) + return -EINVAL; + + return 0; +} + +static int sc18is602_transfer_one(struct spi_master *master, + struct spi_message *m) +{ + struct sc18is602 *hw = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + struct spi_transfer *t; + int status = 0; + + /* SC18IS602 does not support CS2 */ + if (hw->id == sc18is602 && spi->chip_select == 2) { + status = -ENXIO; + goto error; + } + + hw->tlen = 0; + list_for_each_entry(t, &m->transfers, transfer_list) { + u32 hz = t->speed_hz ? : spi->max_speed_hz; + bool do_transfer; + + status = sc18is602_check_transfer(spi, t, hw->tlen); + if (status < 0) + break; + + status = sc18is602_setup_transfer(hw, hz, spi->mode); + if (status < 0) + break; + + do_transfer = t->cs_change || list_is_last(&t->transfer_list, + &m->transfers); + + if (t->len) { + status = sc18is602_txrx(hw, m, t, do_transfer); + if (status < 0) + break; + m->actual_length += status; + } + status = 0; + + if (t->delay_usecs) + udelay(t->delay_usecs); + } +error: + m->status = status; + spi_finalize_current_message(master); + + return status; +} + +static int sc18is602_setup(struct spi_device *spi) +{ + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST)) + return -EINVAL; + + return sc18is602_check_transfer(spi, NULL, 0); +} + +static int sc18is602_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *np = dev->of_node; + struct sc18is602_platform_data *pdata = dev_get_platdata(dev); + struct sc18is602 *hw; + struct spi_master *master; + int error; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + return -EINVAL; + + master = spi_alloc_master(dev, sizeof(struct sc18is602)); + if (!master) + return -ENOMEM; + + hw = spi_master_get_devdata(master); + i2c_set_clientdata(client, hw); + + hw->master = master; + hw->client = client; + hw->dev = dev; + hw->ctrl = 0xff; + + hw->id = id->driver_data; + + switch (hw->id) { + case sc18is602: + case sc18is602b: + master->num_chipselect = 4; + hw->freq = SC18IS602_CLOCK; + break; + case sc18is603: + master->num_chipselect = 2; + if (pdata) { + hw->freq = pdata->clock_frequency; + } else { + const __be32 *val; + int len; + + val = of_get_property(np, "clock-frequency", &len); + if (val && len >= sizeof(__be32)) + hw->freq = be32_to_cpup(val); + } + if (!hw->freq) + hw->freq = SC18IS602_CLOCK; + break; + } + master->bus_num = client->adapter->nr; + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; + master->setup = sc18is602_setup; + master->transfer_one_message = sc18is602_transfer_one; + master->dev.of_node = np; + + error = spi_register_master(master); + if (error) + goto error_reg; + + return 0; + +error_reg: + spi_master_put(master); + return error; +} + +static int sc18is602_remove(struct i2c_client *client) +{ + struct sc18is602 *hw = i2c_get_clientdata(client); + struct spi_master *master = hw->master; + + spi_unregister_master(master); + + return 0; +} + +static const struct i2c_device_id sc18is602_id[] = { + { "sc18is602", sc18is602 }, + { "sc18is602b", sc18is602b }, + { "sc18is603", sc18is603 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sc18is602_id); + +static struct i2c_driver sc18is602_driver = { + .driver = { + .name = "sc18is602", + }, + .probe = sc18is602_probe, + .remove = sc18is602_remove, + .id_table = sc18is602_id, +}; + +module_i2c_driver(sc18is602_driver); + +MODULE_DESCRIPTION("SC18IC602/603 SPI Master Driver"); +MODULE_AUTHOR("Guenter Roeck"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 934138c7b3d3..796c077ef439 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -283,7 +283,7 @@ static int __devinit hspi_probe(struct platform_device *pdev) ret = spi_register_master(master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); - goto error2; + goto error1; } pm_runtime_enable(&pdev->dev); @@ -292,8 +292,6 @@ static int __devinit hspi_probe(struct platform_device *pdev) return 0; - error2: - devm_iounmap(hspi->dev, hspi->addr); error1: clk_put(clk); error0: @@ -310,7 +308,6 @@ static int __devexit hspi_remove(struct platform_device *pdev) clk_put(hspi->clk); spi_unregister_master(hspi->master); - devm_iounmap(hspi->dev, hspi->addr); return 0; } diff --git a/drivers/spi/spi-stmp.c b/drivers/spi/spi-stmp.c index 58e385285323..911e904b3c84 100644 --- a/drivers/spi/spi-stmp.c +++ b/drivers/spi/spi-stmp.c @@ -594,9 +594,7 @@ static int __devexit stmp_spi_remove(struct platform_device *dev) struct stmp_spi *ss; struct spi_master *master; - master = platform_get_drvdata(dev); - if (master == NULL) - goto out0; + master = spi_master_get(platform_get_drvdata(dev)); ss = spi_master_get_devdata(master); spi_unregister_master(master); @@ -609,8 +607,6 @@ static int __devexit stmp_spi_remove(struct platform_device *dev) destroy_workqueue(ss->workqueue); iounmap(ss->regs); spi_master_put(master); - platform_set_drvdata(dev, NULL); -out0: return 0; } diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c index ef52c1c6f5c5..e28445d8d27f 100644 --- a/drivers/spi/spi-tegra.c +++ b/drivers/spi/spi-tegra.c @@ -652,7 +652,7 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev) struct spi_tegra_data *tspi; struct resource *r; - master = dev_get_drvdata(&pdev->dev); + master = spi_master_get(dev_get_drvdata(&pdev->dev)); tspi = spi_master_get_devdata(master); spi_unregister_master(master); @@ -668,6 +668,8 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev) clk_put(tspi->clk); iounmap(tspi->base); + spi_master_put(master); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(r->start, resource_size(r)); diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index 0ce5c12aab55..24421024deaf 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -316,18 +316,7 @@ static struct spi_driver tle62x0_driver = { .remove = __devexit_p(tle62x0_remove), }; -static __init int tle62x0_init(void) -{ - return spi_register_driver(&tle62x0_driver); -} - -static __exit void tle62x0_exit(void) -{ - spi_unregister_driver(&tle62x0_driver); -} - -module_init(tle62x0_init); -module_exit(tle62x0_exit); +module_spi_driver(tle62x0_driver); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_DESCRIPTION("TLE62x0 SPI driver"); diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index cd56dcf46320..159dafd2f908 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1536,8 +1536,6 @@ static int __devexit pch_spi_pd_remove(struct platform_device *plat_dev) pci_iounmap(board_dat->pdev, data->io_remap_addr); spi_unregister_master(data->master); - spi_master_put(data->master); - platform_set_drvdata(plat_dev, NULL); return 0; } |