diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-orion.c | 10 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx.c | 22 | ||||
-rw-r--r-- | drivers/spi/spi-rockchip.c | 79 | ||||
-rw-r--r-- | drivers/spi/spi-sh-msiof.c | 111 | ||||
-rw-r--r-- | drivers/spi/spi-sirf.c | 2 |
5 files changed, 151 insertions, 73 deletions
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index be2e87ee8b31..28fc9f161b9d 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -22,6 +22,7 @@ #include <linux/of_device.h> #include <linux/clk.h> #include <linux/sizes.h> +#include <linux/gpio.h> #include <asm/unaligned.h> #define DRIVER_NAME "orion_spi" @@ -320,12 +321,18 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) static void orion_spi_set_cs(struct spi_device *spi, bool enable) { struct orion_spi *orion_spi; + int cs; + + if (gpio_is_valid(spi->cs_gpio)) + cs = 0; + else + cs = spi->chip_select; orion_spi = spi_master_get_devdata(spi->master); orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK); orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, - ORION_SPI_CS(spi->chip_select)); + ORION_SPI_CS(cs)); /* Chip select logic is inverted from spi_set_cs */ if (!enable) @@ -606,6 +613,7 @@ static int orion_spi_probe(struct platform_device *pdev) master->setup = orion_spi_setup; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->auto_runtime_pm = true; + master->flags = SPI_MASTER_GPIO_SS; platform_set_drvdata(pdev, master); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 47b65d7c4072..38d053682892 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -151,6 +151,18 @@ static const struct lpss_config lpss_platforms[] = { .cs_sel_shift = 8, .cs_sel_mask = 3 << 8, }, + { /* LPSS_CNL_SSP */ + .offset = 0x200, + .reg_general = -1, + .reg_ssp = 0x20, + .reg_cs_ctrl = 0x24, + .reg_capabilities = 0xfc, + .rx_threshold = 1, + .tx_threshold_lo = 32, + .tx_threshold_hi = 56, + .cs_sel_shift = 8, + .cs_sel_mask = 3 << 8, + }, }; static inline const struct lpss_config @@ -167,6 +179,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data) case LPSS_BSW_SSP: case LPSS_SPT_SSP: case LPSS_BXT_SSP: + case LPSS_CNL_SSP: return true; default: return false; @@ -1275,6 +1288,7 @@ static int setup(struct spi_device *spi) case LPSS_BSW_SSP: case LPSS_SPT_SSP: case LPSS_BXT_SSP: + case LPSS_CNL_SSP: config = lpss_get_config(drv_data); tx_thres = config->tx_threshold_lo; tx_hi_thres = config->tx_threshold_hi; @@ -1470,6 +1484,14 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac6), LPSS_BXT_SSP }, + /* CNL-LP */ + { PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x9dfb), LPSS_CNL_SSP }, + /* CNL-H */ + { PCI_VDEVICE(INTEL, 0xa32a), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0xa32b), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0xa37b), LPSS_CNL_SSP }, { }, }; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index acf31f36b898..0b4a52b3e1dc 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -25,6 +25,11 @@ #define DRIVER_NAME "rockchip-spi" +#define ROCKCHIP_SPI_CLR_BITS(reg, bits) \ + writel_relaxed(readl_relaxed(reg) & ~(bits), reg) +#define ROCKCHIP_SPI_SET_BITS(reg, bits) \ + writel_relaxed(readl_relaxed(reg) | (bits), reg) + /* SPI register offsets */ #define ROCKCHIP_SPI_CTRLR0 0x0000 #define ROCKCHIP_SPI_CTRLR1 0x0004 @@ -149,6 +154,8 @@ */ #define ROCKCHIP_SPI_MAX_TRANLEN 0xffff +#define ROCKCHIP_SPI_MAX_CS_NUM 2 + enum rockchip_ssi_type { SSI_MOTO_SPI = 0, SSI_TI_SSP, @@ -193,6 +200,8 @@ struct rockchip_spi { /* protect state */ spinlock_t lock; + bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; + u32 use_dma; struct sg_table tx_sg; struct sg_table rx_sg; @@ -264,37 +273,29 @@ static inline u32 rx_max(struct rockchip_spi *rs) static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) { - u32 ser; struct spi_master *master = spi->master; struct rockchip_spi *rs = spi_master_get_devdata(master); + bool cs_asserted = !enable; - pm_runtime_get_sync(rs->dev); + /* Return immediately for no-op */ + if (cs_asserted == rs->cs_asserted[spi->chip_select]) + return; - ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK; + if (cs_asserted) { + /* Keep things powered as long as CS is asserted */ + pm_runtime_get_sync(rs->dev); - /* - * drivers/spi/spi.c: - * static void spi_set_cs(struct spi_device *spi, bool enable) - * { - * if (spi->mode & SPI_CS_HIGH) - * enable = !enable; - * - * if (spi->cs_gpio >= 0) - * gpio_set_value(spi->cs_gpio, !enable); - * else if (spi->master->set_cs) - * spi->master->set_cs(spi, !enable); - * } - * - * Note: enable(rockchip_spi_set_cs) = !enable(spi_set_cs) - */ - if (!enable) - ser |= 1 << spi->chip_select; - else - ser &= ~(1 << spi->chip_select); + ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, + BIT(spi->chip_select)); + } else { + ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, + BIT(spi->chip_select)); - writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER); + /* Drop reference from when we first asserted CS */ + pm_runtime_put(rs->dev); + } - pm_runtime_put_sync(rs->dev); + rs->cs_asserted[spi->chip_select] = cs_asserted; } static int rockchip_spi_prepare_message(struct spi_master *master, @@ -684,33 +685,33 @@ static int rockchip_spi_probe(struct platform_device *pdev) rs->regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(rs->regs)) { ret = PTR_ERR(rs->regs); - goto err_ioremap_resource; + goto err_put_master; } rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(rs->apb_pclk)) { dev_err(&pdev->dev, "Failed to get apb_pclk\n"); ret = PTR_ERR(rs->apb_pclk); - goto err_ioremap_resource; + goto err_put_master; } rs->spiclk = devm_clk_get(&pdev->dev, "spiclk"); if (IS_ERR(rs->spiclk)) { dev_err(&pdev->dev, "Failed to get spi_pclk\n"); ret = PTR_ERR(rs->spiclk); - goto err_ioremap_resource; + goto err_put_master; } ret = clk_prepare_enable(rs->apb_pclk); if (ret) { dev_err(&pdev->dev, "Failed to enable apb_pclk\n"); - goto err_ioremap_resource; + goto err_put_master; } ret = clk_prepare_enable(rs->spiclk); if (ret) { dev_err(&pdev->dev, "Failed to enable spi_clk\n"); - goto err_spiclk_enable; + goto err_disable_apbclk; } spi_enable_chip(rs, 0); @@ -728,7 +729,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) if (!rs->fifo_len) { dev_err(&pdev->dev, "Failed to get fifo length\n"); ret = -EINVAL; - goto err_get_fifo_len; + goto err_disable_spiclk; } spin_lock_init(&rs->lock); @@ -739,7 +740,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; master->bus_num = pdev->id; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; - master->num_chipselect = 2; + master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM; master->dev.of_node = pdev->dev.of_node; master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8); @@ -749,13 +750,14 @@ static int rockchip_spi_probe(struct platform_device *pdev) master->transfer_one = rockchip_spi_transfer_one; master->max_transfer_size = rockchip_spi_max_transfer_size; master->handle_err = rockchip_spi_handle_err; + master->flags = SPI_MASTER_GPIO_SS; rs->dma_tx.ch = dma_request_chan(rs->dev, "tx"); if (IS_ERR(rs->dma_tx.ch)) { /* Check tx to see if we need defer probing driver */ if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) { ret = -EPROBE_DEFER; - goto err_get_fifo_len; + goto err_disable_pm_runtime; } dev_warn(rs->dev, "Failed to request TX DMA channel\n"); rs->dma_tx.ch = NULL; @@ -786,23 +788,24 @@ static int rockchip_spi_probe(struct platform_device *pdev) ret = devm_spi_register_master(&pdev->dev, master); if (ret) { dev_err(&pdev->dev, "Failed to register master\n"); - goto err_register_master; + goto err_free_dma_rx; } return 0; -err_register_master: - pm_runtime_disable(&pdev->dev); +err_free_dma_rx: if (rs->dma_rx.ch) dma_release_channel(rs->dma_rx.ch); err_free_dma_tx: if (rs->dma_tx.ch) dma_release_channel(rs->dma_tx.ch); -err_get_fifo_len: +err_disable_pm_runtime: + pm_runtime_disable(&pdev->dev); +err_disable_spiclk: clk_disable_unprepare(rs->spiclk); -err_spiclk_enable: +err_disable_apbclk: clk_disable_unprepare(rs->apb_pclk); -err_ioremap_resource: +err_put_master: spi_master_put(master); return ret; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 2ce15ca97782..c304c7167866 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -2,7 +2,8 @@ * SuperH MSIOF SPI Master Interface * * Copyright (c) 2009 Magnus Damm - * Copyright (C) 2014 Glider bvba + * Copyright (C) 2014 Renesas Electronics Corporation + * Copyright (C) 2014-2017 Glider bvba * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -33,7 +34,6 @@ #include <asm/unaligned.h> - struct sh_msiof_chipdata { u16 tx_fifo_size; u16 rx_fifo_size; @@ -53,6 +53,7 @@ struct sh_msiof_spi_priv { void *rx_dma_page; dma_addr_t tx_dma_addr; dma_addr_t rx_dma_addr; + bool slave_aborted; }; #define TMDR1 0x00 /* Transmit Mode Register 1 */ @@ -337,7 +338,10 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); - sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); + if (spi_controller_is_slave(p->master)) + sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON); + else + sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); if (p->master->flags & SPI_MASTER_MUST_TX) { /* These bits are reserved if RX needs TX */ tmp &= ~0x0000ffff; @@ -564,17 +568,19 @@ static int sh_msiof_prepare_message(struct spi_master *master, static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) { - int ret; + bool slave = spi_controller_is_slave(p->master); + int ret = 0; /* setup clock and rx/tx signals */ - ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); + if (!slave) + ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); if (rx_buf && !ret) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); if (!ret) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); /* start by setting frame bit */ - if (!ret) + if (!ret && !slave) ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); return ret; @@ -582,20 +588,49 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf) { - int ret; + bool slave = spi_controller_is_slave(p->master); + int ret = 0; /* shut down frame, rx/tx and clock signals */ - ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); + if (!slave) + ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); if (!ret) ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); if (rx_buf && !ret) ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); - if (!ret) + if (!ret && !slave) ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); return ret; } +static int sh_msiof_slave_abort(struct spi_master *master) +{ + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); + + p->slave_aborted = true; + complete(&p->done); + return 0; +} + +static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p) +{ + if (spi_controller_is_slave(p->master)) { + if (wait_for_completion_interruptible(&p->done) || + p->slave_aborted) { + dev_dbg(&p->pdev->dev, "interrupted\n"); + return -EINTR; + } + } else { + if (!wait_for_completion_timeout(&p->done, HZ)) { + dev_err(&p->pdev->dev, "timeout\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int), @@ -628,6 +663,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, tx_fifo(p, tx_buf, words, fifo_shift); reinit_completion(&p->done); + p->slave_aborted = false; ret = sh_msiof_spi_start(p, rx_buf); if (ret) { @@ -636,11 +672,9 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, } /* wait for tx fifo to be emptied / rx fifo to be filled */ - if (!wait_for_completion_timeout(&p->done, HZ)) { - dev_err(&p->pdev->dev, "PIO timeout\n"); - ret = -ETIMEDOUT; + ret = sh_msiof_wait_for_completion(p); + if (ret) goto stop_reset; - } /* read rx fifo */ if (rx_buf) @@ -732,6 +766,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, sh_msiof_write(p, IER, ier_bits); reinit_completion(&p->done); + p->slave_aborted = false; /* Now start DMA */ if (rx) @@ -746,11 +781,9 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, } /* wait for tx fifo to be emptied / rx fifo to be filled */ - if (!wait_for_completion_timeout(&p->done, HZ)) { - dev_err(&p->pdev->dev, "DMA timeout\n"); - ret = -ETIMEDOUT; + ret = sh_msiof_wait_for_completion(p); + if (ret) goto stop_reset; - } /* clear status bits */ sh_msiof_reset_str(p); @@ -843,7 +876,8 @@ static int sh_msiof_transfer_one(struct spi_master *master, int ret; /* setup clocks (clock already enabled in chipselect()) */ - sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); + if (!spi_controller_is_slave(p->master)) + sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); while (master->dma_tx && len > 15) { /* @@ -998,8 +1032,12 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) if (!info) return NULL; + info->mode = of_property_read_bool(np, "spi-slave") ? MSIOF_SPI_SLAVE + : MSIOF_SPI_MASTER; + /* Parse the MSIOF properties */ - of_property_read_u32(np, "num-cs", &num_cs); + if (info->mode == MSIOF_SPI_MASTER) + of_property_read_u32(np, "num-cs", &num_cs); of_property_read_u32(np, "renesas,tx-fifo-size", &info->tx_fifo_override); of_property_read_u32(np, "renesas,rx-fifo-size", @@ -1159,34 +1197,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) struct spi_master *master; const struct sh_msiof_chipdata *chipdata; const struct of_device_id *of_id; + struct sh_msiof_spi_info *info; struct sh_msiof_spi_priv *p; int i; int ret; - master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv)); - if (master == NULL) - return -ENOMEM; - - p = spi_master_get_devdata(master); - - platform_set_drvdata(pdev, p); - p->master = master; - of_id = of_match_device(sh_msiof_match, &pdev->dev); if (of_id) { chipdata = of_id->data; - p->info = sh_msiof_spi_parse_dt(&pdev->dev); + info = sh_msiof_spi_parse_dt(&pdev->dev); } else { chipdata = (const void *)pdev->id_entry->driver_data; - p->info = dev_get_platdata(&pdev->dev); + info = dev_get_platdata(&pdev->dev); } - if (!p->info) { + if (!info) { dev_err(&pdev->dev, "failed to obtain device info\n"); - ret = -ENXIO; - goto err1; + return -ENXIO; } + if (info->mode == MSIOF_SPI_SLAVE) + master = spi_alloc_slave(&pdev->dev, + sizeof(struct sh_msiof_spi_priv)); + else + master = spi_alloc_master(&pdev->dev, + sizeof(struct sh_msiof_spi_priv)); + if (master == NULL) + return -ENOMEM; + + p = spi_master_get_devdata(master); + + platform_set_drvdata(pdev, p); + p->master = master; + p->info = info; + init_completion(&p->done); p->clk = devm_clk_get(&pdev->dev, NULL); @@ -1237,6 +1281,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->num_chipselect = p->info->num_chipselect; master->setup = sh_msiof_spi_setup; master->prepare_message = sh_msiof_prepare_message; + master->slave_abort = sh_msiof_slave_abort; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); master->auto_runtime_pm = true; master->transfer_one = sh_msiof_transfer_one; diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 7072276ad354..bbb1a275f718 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -1158,7 +1158,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) ret = spi_bitbang_start(&sspi->bitbang); if (ret) goto free_clk; - dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num); + dev_info(&pdev->dev, "registered, bus number = %d\n", master->bus_num); return 0; free_clk: |