diff --git a/Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt b/Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt new file mode 100644 index 000000000000..37b29ee13860 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt @@ -0,0 +1,33 @@ +Binding for Broadcom BCM6328 High Speed SPI controller + +Required properties: +- compatible: must contain of "brcm,bcm6328-hsspi". +- reg: Base address and size of the controllers memory area. +- interrupts: Interrupt for the SPI block. +- clocks: phandles of the SPI clock and the PLL clock. +- clock-names: must be "hsspi", "pll". +- #address-cells: <1>, as required by generic SPI binding. +- #size-cells: <0>, also as required by generic SPI binding. + +Optional properties: +- num-cs: some controllers have less than 8 cs signals. Defaults to 8 + if absent. + +Child nodes as per the generic SPI binding. + +Example: + + spi@10001000 { + compatible = "brcm,bcm6328-hsspi"; + reg = <0x10001000 0x600>; + + interrupts = <29>; + + clocks = <&clkctl 9>, <&hsspi_pll>; + clock-names = "hsspi", "pll"; + + num-cs = <2>; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/spi/spi-bcm63xx.txt b/Documentation/devicetree/bindings/spi/spi-bcm63xx.txt new file mode 100644 index 000000000000..1c16f6692613 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-bcm63xx.txt @@ -0,0 +1,33 @@ +Binding for Broadcom BCM6348/BCM6358 SPI controller + +Required properties: +- compatible: must contain one of "brcm,bcm6348-spi", "brcm,bcm6358-spi". +- reg: Base address and size of the controllers memory area. +- interrupts: Interrupt for the SPI block. +- clocks: phandle of the SPI clock. +- clock-names: has to be "spi". +- #address-cells: <1>, as required by generic SPI binding. +- #size-cells: <0>, also as required by generic SPI binding. + +Optional properties: +- num-cs: some controllers have less than 8 cs signals. Defaults to 8 + if absent. + +Child nodes as per the generic SPI binding. + +Example: + + spi@10000800 { + compatible = "brcm,bcm6368-spi", "brcm,bcm6358-spi"; + reg = <0x10000800 0x70c>; + + interrupts = <1>; + + clocks = <&clkctl 9>; + clock-names = "spi"; + + num-cs = <5>; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 0e7712bac3b6..1eb83c9613d5 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1464,6 +1464,25 @@ static int atmel_spi_gpio_cs(struct platform_device *pdev) return 0; } +static void atmel_spi_init(struct atmel_spi *as) +{ + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ + if (as->caps.has_wdrbt) { + spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) + | SPI_BIT(MSTR)); + } else { + spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); + } + + if (as->use_pdc) + spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); + spi_writel(as, CR, SPI_BIT(SPIEN)); + + if (as->fifo_size) + spi_writel(as, CR, SPI_BIT(FIFOEN)); +} + static int atmel_spi_probe(struct platform_device *pdev) { struct resource *regs; @@ -1572,26 +1591,14 @@ static int atmel_spi_probe(struct platform_device *pdev) as->spi_clk = clk_get_rate(clk); - spi_writel(as, CR, SPI_BIT(SWRST)); - spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ - if (as->caps.has_wdrbt) { - spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) - | SPI_BIT(MSTR)); - } else { - spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); - } - - if (as->use_pdc) - spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); - spi_writel(as, CR, SPI_BIT(SPIEN)); - as->fifo_size = 0; if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", &as->fifo_size)) { dev_info(&pdev->dev, "Using FIFO (%u data)\n", as->fifo_size); - spi_writel(as, CR, SPI_BIT(FIFOEN)); } + atmel_spi_init(as); + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -1695,8 +1702,17 @@ static int atmel_spi_suspend(struct device *dev) static int atmel_spi_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); + struct atmel_spi *as = spi_master_get_devdata(master); int ret; + ret = clk_prepare_enable(as->clk); + if (ret) + return ret; + + atmel_spi_init(as); + + clk_disable_unprepare(as->clk); + if (!pm_runtime_suspended(dev)) { ret = atmel_spi_runtime_resume(dev); if (ret) diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 55789f7cda92..5514cd02e93a 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -19,6 +19,7 @@ #include #include #include +#include #define HSSPI_GLOBAL_CTRL_REG 0x0 #define GLOBAL_CTRL_CS_POLARITY_SHIFT 0 @@ -91,6 +92,7 @@ #define HSSPI_MAX_SYNC_CLOCK 30000000 +#define HSSPI_SPI_MAX_CS 8 #define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */ struct bcm63xx_hsspi { @@ -332,7 +334,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct clk *clk; int irq, ret; - u32 reg, rate; + u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -351,8 +353,16 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) return PTR_ERR(clk); rate = clk_get_rate(clk); - if (!rate) - return -EINVAL; + if (!rate) { + struct clk *pll_clk = devm_clk_get(dev, "pll"); + + if (IS_ERR(pll_clk)) + return PTR_ERR(pll_clk); + + rate = clk_get_rate(pll_clk); + if (!rate) + return -EINVAL; + } ret = clk_prepare_enable(clk); if (ret) @@ -374,8 +384,17 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) mutex_init(&bs->bus_mutex); init_completion(&bs->done); - master->bus_num = HSSPI_BUS_NUM; - master->num_chipselect = 8; + master->dev.of_node = dev->of_node; + if (!dev->of_node) + master->bus_num = HSSPI_BUS_NUM; + + of_property_read_u32(dev->of_node, "num-cs", &num_cs); + if (num_cs > 8) { + dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n", + num_cs); + num_cs = HSSPI_SPI_MAX_CS; + } + master->num_chipselect = num_cs; master->setup = bcm63xx_hsspi_setup; master->transfer_one_message = bcm63xx_hsspi_transfer_one; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | @@ -461,10 +480,16 @@ static int bcm63xx_hsspi_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume); +static const struct of_device_id bcm63xx_hsspi_of_match[] = { + { .compatible = "brcm,bcm6328-hsspi", }, + { }, +}; + static struct platform_driver bcm63xx_hsspi_driver = { .driver = { .name = "bcm63xx-hsspi", .pm = &bcm63xx_hsspi_pm_ops, + .of_match_table = bcm63xx_hsspi_of_match, }, .probe = bcm63xx_hsspi_probe, .remove = bcm63xx_hsspi_remove, diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index fee747030ee6..247f71b02235 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -26,6 +26,7 @@ #include #include #include +#include /* BCM 6338/6348 SPI core */ #define SPI_6348_RSET_SIZE 64 @@ -428,6 +429,13 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static size_t bcm63xx_spi_max_length(struct spi_device *spi) +{ + struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); + + return bs->fifo_size; +} + static const unsigned long bcm6348_spi_reg_offsets[] = { [SPI_CMD] = SPI_6348_CMD, [SPI_INT_STATUS] = SPI_6348_INT_STATUS, @@ -477,21 +485,48 @@ static const struct platform_device_id bcm63xx_spi_dev_match[] = { }, }; +static const struct of_device_id bcm63xx_spi_of_match[] = { + { .compatible = "brcm,bcm6348-spi", .data = &bcm6348_spi_reg_offsets }, + { .compatible = "brcm,bcm6358-spi", .data = &bcm6358_spi_reg_offsets }, + { }, +}; + static int bcm63xx_spi_probe(struct platform_device *pdev) { struct resource *r; const unsigned long *bcm63xx_spireg; struct device *dev = &pdev->dev; - int irq; + int irq, bus_num; struct spi_master *master; struct clk *clk; struct bcm63xx_spi *bs; int ret; + u32 num_cs = BCM63XX_SPI_MAX_CS; - if (!pdev->id_entry->driver_data) + if (dev->of_node) { + const struct of_device_id *match; + + match = of_match_node(bcm63xx_spi_of_match, dev->of_node); + if (!match) + return -EINVAL; + bcm63xx_spireg = match->data; + + of_property_read_u32(dev->of_node, "num-cs", &num_cs); + if (num_cs > BCM63XX_SPI_MAX_CS) { + dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n", + num_cs); + num_cs = BCM63XX_SPI_MAX_CS; + } + + bus_num = -1; + } else if (pdev->id_entry->driver_data) { + const struct platform_device_id *match = pdev->id_entry; + + bcm63xx_spireg = (const unsigned long *)match->driver_data; + bus_num = BCM63XX_SPI_BUS_NUM; + } else { return -EINVAL; - - bcm63xx_spireg = (const unsigned long *)pdev->id_entry->driver_data; + } irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -536,11 +571,14 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) goto out_err; } - master->bus_num = BCM63XX_SPI_BUS_NUM; - master->num_chipselect = BCM63XX_SPI_MAX_CS; + master->dev.of_node = dev->of_node; + master->bus_num = bus_num; + master->num_chipselect = num_cs; master->transfer_one_message = bcm63xx_spi_transfer_one; master->mode_bits = MODEBITS; master->bits_per_word_mask = SPI_BPW_MASK(8); + master->max_transfer_size = bcm63xx_spi_max_length; + master->max_message_size = bcm63xx_spi_max_length; master->auto_runtime_pm = true; bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT]; bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH]; @@ -624,6 +662,7 @@ static struct platform_driver bcm63xx_spi_driver = { .driver = { .name = "bcm63xx-spi", .pm = &bcm63xx_spi_pm_ops, + .of_match_table = bcm63xx_spi_of_match, }, .id_table = bcm63xx_spi_dev_match, .probe = bcm63xx_spi_probe, diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 1c57ce64abba..f0b5c7b91f37 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -127,6 +128,10 @@ struct cdns_spi { u32 is_decoded_cs; }; +struct cdns_spi_device_data { + bool gpio_requested; +}; + /* Macros for the SPI controller read/write */ static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) { @@ -456,6 +461,64 @@ static int cdns_unprepare_transfer_hardware(struct spi_master *master) return 0; } +static int cdns_spi_setup(struct spi_device *spi) +{ + + int ret = -EINVAL; + struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); + + /* this is a pin managed by the controller, leave it alone */ + if (spi->cs_gpio == -ENOENT) + return 0; + + /* this seems to be the first time we're here */ + if (!cdns_spi_data) { + cdns_spi_data = kzalloc(sizeof(*cdns_spi_data), GFP_KERNEL); + if (!cdns_spi_data) + return -ENOMEM; + cdns_spi_data->gpio_requested = false; + spi_set_ctldata(spi, cdns_spi_data); + } + + /* if we haven't done so, grab the gpio */ + if (!cdns_spi_data->gpio_requested && gpio_is_valid(spi->cs_gpio)) { + ret = gpio_request_one(spi->cs_gpio, + (spi->mode & SPI_CS_HIGH) ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + dev_name(&spi->dev)); + if (ret) + dev_err(&spi->dev, "can't request chipselect gpio %d\n", + spi->cs_gpio); + else + cdns_spi_data->gpio_requested = true; + } else { + if (gpio_is_valid(spi->cs_gpio)) { + int mode = ((spi->mode & SPI_CS_HIGH) ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH); + + ret = gpio_direction_output(spi->cs_gpio, mode); + if (ret) + dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", + spi->cs_gpio, ret); + } + } + + return ret; +} + +static void cdns_spi_cleanup(struct spi_device *spi) +{ + struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); + + if (cdns_spi_data) { + if (cdns_spi_data->gpio_requested) + gpio_free(spi->cs_gpio); + kfree(cdns_spi_data); + spi_set_ctldata(spi, NULL); + } + +} + /** * cdns_spi_probe - Probe method for the SPI driver * @pdev: Pointer to the platform_device structure @@ -555,6 +618,8 @@ static int cdns_spi_probe(struct platform_device *pdev) master->transfer_one = cdns_transfer_one; master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware; master->set_cs = cdns_spi_chipselect; + master->setup = cdns_spi_setup; + master->cleanup = cdns_spi_cleanup; master->auto_runtime_pm = true; master->mode_bits = SPI_CPOL | SPI_CPHA; diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 02fb96797ac8..595acdcfc7d0 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -109,6 +109,8 @@ #define SPIDEF 0x4c #define SPIFMT0 0x50 +#define DMA_MIN_BYTES 16 + /* SPI Controller driver's private data. */ struct davinci_spi { struct spi_bitbang bitbang; @@ -389,6 +391,7 @@ static int davinci_spi_of_setup(struct spi_device *spi) { struct davinci_spi_config *spicfg = spi->controller_data; struct device_node *np = spi->dev.of_node; + struct davinci_spi *dspi = spi_master_get_devdata(spi->master); u32 prop; if (spicfg == NULL && np) { @@ -400,6 +403,9 @@ static int davinci_spi_of_setup(struct spi_device *spi) if (!of_property_read_u32(np, "ti,spi-wdelay", &prop)) spicfg->wdelay = (u8)prop; spi->controller_data = spicfg; + + if (dspi->dma_rx && dspi->dma_tx) + spicfg->io_type = SPI_IO_TYPE_DMA; } return 0; @@ -467,6 +473,22 @@ static void davinci_spi_cleanup(struct spi_device *spi) kfree(spicfg); } +static bool davinci_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct davinci_spi_config *spicfg = spi->controller_data; + bool can_dma = false; + + if (spicfg) + can_dma = (spicfg->io_type == SPI_IO_TYPE_DMA) && + (xfer->len >= DMA_MIN_BYTES) && + !is_vmalloc_addr(xfer->rx_buf) && + !is_vmalloc_addr(xfer->tx_buf); + + return can_dma; +} + static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) { struct device *sdev = dspi->bitbang.master->dev.parent; @@ -581,8 +603,6 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) struct davinci_spi_config *spicfg; struct davinci_spi_platform_data *pdata; unsigned uninitialized_var(rx_buf_count); - void *dummy_buf = NULL; - struct scatterlist sg_rx, sg_tx; dspi = spi_master_get_devdata(spi->master); pdata = &dspi->pdata; @@ -605,10 +625,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) reinit_completion(&dspi->done); - if (spicfg->io_type == SPI_IO_TYPE_INTR) - set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT); - - if (spicfg->io_type != SPI_IO_TYPE_DMA) { + if (!davinci_spi_can_dma(spi->master, spi, t)) { + if (spicfg->io_type != SPI_IO_TYPE_POLL) + set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT); /* start the transfer */ dspi->wcount--; tx_data = dspi->get_tx(dspi); @@ -630,51 +649,28 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) }; struct dma_async_tx_descriptor *rxdesc; struct dma_async_tx_descriptor *txdesc; - void *buf; - - dummy_buf = kzalloc(t->len, GFP_KERNEL); - if (!dummy_buf) - goto err_alloc_dummy_buf; dmaengine_slave_config(dspi->dma_rx, &dma_rx_conf); dmaengine_slave_config(dspi->dma_tx, &dma_tx_conf); - sg_init_table(&sg_rx, 1); - if (!t->rx_buf) - buf = dummy_buf; - else - buf = t->rx_buf; - t->rx_dma = dma_map_single(&spi->dev, buf, - t->len, DMA_FROM_DEVICE); - if (dma_mapping_error(&spi->dev, !t->rx_dma)) { - ret = -EFAULT; - goto err_rx_map; - } - sg_dma_address(&sg_rx) = t->rx_dma; - sg_dma_len(&sg_rx) = t->len; - - sg_init_table(&sg_tx, 1); - if (!t->tx_buf) - buf = dummy_buf; - else - buf = (void *)t->tx_buf; - t->tx_dma = dma_map_single(&spi->dev, buf, - t->len, DMA_TO_DEVICE); - if (dma_mapping_error(&spi->dev, t->tx_dma)) { - ret = -EFAULT; - goto err_tx_map; - } - sg_dma_address(&sg_tx) = t->tx_dma; - sg_dma_len(&sg_tx) = t->len; - rxdesc = dmaengine_prep_slave_sg(dspi->dma_rx, - &sg_rx, 1, DMA_DEV_TO_MEM, + t->rx_sg.sgl, t->rx_sg.nents, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!rxdesc) goto err_desc; + if (!t->tx_buf) { + /* To avoid errors when doing rx-only transfers with + * many SG entries (> 20), use the rx buffer as the + * dummy tx buffer so that dma reloads are done at the + * same time for rx and tx. + */ + t->tx_sg.sgl = t->rx_sg.sgl; + t->tx_sg.nents = t->rx_sg.nents; + } + txdesc = dmaengine_prep_slave_sg(dspi->dma_tx, - &sg_tx, 1, DMA_MEM_TO_DEV, + t->tx_sg.sgl, t->tx_sg.nents, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) goto err_desc; @@ -710,16 +706,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) } clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL); - if (spicfg->io_type == SPI_IO_TYPE_DMA) { + if (davinci_spi_can_dma(spi->master, spi, t)) clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN); - dma_unmap_single(&spi->dev, t->rx_dma, - t->len, DMA_FROM_DEVICE); - dma_unmap_single(&spi->dev, t->tx_dma, - t->len, DMA_TO_DEVICE); - kfree(dummy_buf); - } - clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK); @@ -742,12 +731,6 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) return t->len; err_desc: - dma_unmap_single(&spi->dev, t->tx_dma, t->len, DMA_TO_DEVICE); -err_tx_map: - dma_unmap_single(&spi->dev, t->rx_dma, t->len, DMA_FROM_DEVICE); -err_rx_map: - kfree(dummy_buf); -err_alloc_dummy_buf: return ret; } @@ -988,8 +971,10 @@ static int davinci_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = pdata->num_chipselect; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); + master->flags = SPI_MASTER_MUST_RX; master->setup = davinci_spi_setup; master->cleanup = davinci_spi_cleanup; + master->can_dma = davinci_spi_can_dma; dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;