diff options
Diffstat (limited to 'drivers/spi')
29 files changed, 1021 insertions, 361 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 4887f317ea58..8b9c2a38d1cc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -88,6 +88,17 @@ config SPI_BCM2835 is for the regular SPI controller. Slave mode operation is not also not supported. +config SPI_BCM2835AUX + tristate "BCM2835 SPI auxiliary controller" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on GPIOLIB + help + This selects a driver for the Broadcom BCM2835 SPI aux master. + + The BCM2835 contains two types of SPI master controller; the + "universal SPI master", and the regular SPI controller. + This driver is for the universal/auxiliary SPI controller. + config SPI_BFIN5XX tristate "SPI controller driver for ADI Blackfin5xx" depends on BLACKFIN && !BF60x @@ -125,7 +136,7 @@ config SPI_BCM53XX config SPI_BCM63XX tristate "Broadcom BCM63xx SPI controller" - depends on BCM63XX + depends on BCM63XX || COMPILE_TEST help Enable support for the SPI controller on the Broadcom BCM63xx SoCs. @@ -304,7 +315,7 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select REGMAP_MMIO - depends on SOC_VF610 || SOC_LS1021A || COMPILE_TEST + depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST help This enables support for the Freescale DSPI controller in master mode. VF610 platform uses the controller. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6a7f6f9d0d1c..31fb7fb2a0b6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o obj-$(CONFIG_SPI_ATH79) += spi-ath79.o obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o +obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index bf1f9b32c597..6165bf21d427 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -240,14 +240,9 @@ static int ath79_spi_probe(struct platform_device *pdev) sp->bitbang.flags = SPI_CS_HIGH; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - ret = -ENOENT; - goto err_put_master; - } - - sp->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (!sp->base) { - ret = -ENXIO; + sp->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(sp->base)) { + ret = PTR_ERR(sp->base); goto err_put_master; } diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 63318e2afba1..aebad36391c9 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -773,7 +773,8 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, *plen = len; - if (atmel_spi_dma_slave_config(as, &slave_config, 8)) + if (atmel_spi_dma_slave_config(as, &slave_config, + xfer->bits_per_word)) goto err_exit; /* Send both scatterlists */ @@ -871,14 +872,7 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as, * Calculate the lowest divider that satisfies the * constraint, assuming div32/fdiv/mbz == 0. */ - if (xfer->speed_hz) - scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz); - else - /* - * This can happend if max_speed is null. - * In this case, we set the lowest possible speed - */ - scbr = 0xff; + scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz); /* * If the resulting divider doesn't fit into the @@ -1300,14 +1294,12 @@ static int atmel_spi_one_transfer(struct spi_master *master, return -EINVAL; } - if (xfer->bits_per_word) { - asd = spi->controller_state; - bits = (asd->csr >> 4) & 0xf; - if (bits != xfer->bits_per_word - 8) { - dev_dbg(&spi->dev, + asd = spi->controller_state; + bits = (asd->csr >> 4) & 0xf; + if (bits != xfer->bits_per_word - 8) { + dev_dbg(&spi->dev, "you can't yet change bits_per_word in transfers\n"); - return -ENOPROTOOPT; - } + return -ENOPROTOOPT; } /* diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index f45e085c01a6..afd239d6dec1 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -233,13 +233,12 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) unsigned bpw, hz; u32 cfg, stat; - bpw = spi->bits_per_word; - hz = spi->max_speed_hz; if (t) { - if (t->bits_per_word) - bpw = t->bits_per_word; - if (t->speed_hz) - hz = t->speed_hz; + bpw = t->bits_per_word; + hz = t->speed_hz; + } else { + bpw = spi->bits_per_word; + hz = spi->max_speed_hz; } if (!hz) diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 3e8eeb23d4e9..cf04960cc3e6 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -777,7 +777,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) goto out_master_put; } - bs->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + bs->irq = platform_get_irq(pdev, 0); if (bs->irq <= 0) { dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq); err = bs->irq ? bs->irq : -ENODEV; @@ -786,6 +786,12 @@ static int bcm2835_spi_probe(struct platform_device *pdev) clk_prepare_enable(bs->clk); + bcm2835_dma_init(master, &pdev->dev); + + /* initialise the hardware with the default polarities */ + bcm2835_wr(bs, BCM2835_SPI_CS, + BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); + err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, dev_name(&pdev->dev), master); if (err) { @@ -793,12 +799,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev) goto out_clk_disable; } - bcm2835_dma_init(master, &pdev->dev); - - /* initialise the hardware with the default polarities */ - bcm2835_wr(bs, BCM2835_SPI_CS, - BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); - err = devm_spi_register_master(&pdev->dev, master); if (err) { dev_err(&pdev->dev, "could not register SPI master: %d\n", err); diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c new file mode 100644 index 000000000000..7de6f8472a81 --- /dev/null +++ b/drivers/spi/spi-bcm2835aux.c @@ -0,0 +1,512 @@ +/* + * Driver for Broadcom BCM2835 auxiliary SPI Controllers + * + * the driver does not rely on the native chipselects at all + * but only uses the gpio type chipselects + * + * Based on: spi-bcm2835.c + * + * Copyright (C) 2015 Martin Sperl + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <linux/spinlock.h> + +/* + * spi register defines + * + * note there is garbage in the "official" documentation, + * so some data is taken from the file: + * brcm_usrlib/dag/vmcsx/vcinclude/bcm2708_chip/aux_io.h + * inside of: + * http://www.broadcom.com/docs/support/videocore/Brcm_Android_ICS_Graphics_Stack.tar.gz + */ + +/* SPI register offsets */ +#define BCM2835_AUX_SPI_CNTL0 0x00 +#define BCM2835_AUX_SPI_CNTL1 0x04 +#define BCM2835_AUX_SPI_STAT 0x08 +#define BCM2835_AUX_SPI_PEEK 0x0C +#define BCM2835_AUX_SPI_IO 0x20 +#define BCM2835_AUX_SPI_TXHOLD 0x30 + +/* Bitfields in CNTL0 */ +#define BCM2835_AUX_SPI_CNTL0_SPEED 0xFFF00000 +#define BCM2835_AUX_SPI_CNTL0_SPEED_MAX 0xFFF +#define BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT 20 +#define BCM2835_AUX_SPI_CNTL0_CS 0x000E0000 +#define BCM2835_AUX_SPI_CNTL0_POSTINPUT 0x00010000 +#define BCM2835_AUX_SPI_CNTL0_VAR_CS 0x00008000 +#define BCM2835_AUX_SPI_CNTL0_VAR_WIDTH 0x00004000 +#define BCM2835_AUX_SPI_CNTL0_DOUTHOLD 0x00003000 +#define BCM2835_AUX_SPI_CNTL0_ENABLE 0x00000800 +#define BCM2835_AUX_SPI_CNTL0_CPHA_IN 0x00000400 +#define BCM2835_AUX_SPI_CNTL0_CLEARFIFO 0x00000200 +#define BCM2835_AUX_SPI_CNTL0_CPHA_OUT 0x00000100 +#define BCM2835_AUX_SPI_CNTL0_CPOL 0x00000080 +#define BCM2835_AUX_SPI_CNTL0_MSBF_OUT 0x00000040 +#define BCM2835_AUX_SPI_CNTL0_SHIFTLEN 0x0000003F + +/* Bitfields in CNTL1 */ +#define BCM2835_AUX_SPI_CNTL1_CSHIGH 0x00000700 +#define BCM2835_AUX_SPI_CNTL1_IDLE 0x00000080 +#define BCM2835_AUX_SPI_CNTL1_TXEMPTY 0x00000040 +#define BCM2835_AUX_SPI_CNTL1_MSBF_IN 0x00000002 +#define BCM2835_AUX_SPI_CNTL1_KEEP_IN 0x00000001 + +/* Bitfields in STAT */ +#define BCM2835_AUX_SPI_STAT_TX_LVL 0xFF000000 +#define BCM2835_AUX_SPI_STAT_RX_LVL 0x00FF0000 +#define BCM2835_AUX_SPI_STAT_TX_FULL 0x00000400 +#define BCM2835_AUX_SPI_STAT_TX_EMPTY 0x00000200 +#define BCM2835_AUX_SPI_STAT_RX_FULL 0x00000100 +#define BCM2835_AUX_SPI_STAT_RX_EMPTY 0x00000080 +#define BCM2835_AUX_SPI_STAT_BUSY 0x00000040 +#define BCM2835_AUX_SPI_STAT_BITCOUNT 0x0000003F + +/* timeout values */ +#define BCM2835_AUX_SPI_POLLING_LIMIT_US 30 +#define BCM2835_AUX_SPI_POLLING_JIFFIES 2 + +#define BCM2835_AUX_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ + | SPI_NO_CS) + +struct bcm2835aux_spi { + void __iomem *regs; + struct clk *clk; + int irq; + u32 cntl[2]; + const u8 *tx_buf; + u8 *rx_buf; + int tx_len; + int rx_len; + int pending; +}; + +static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned reg) +{ + return readl(bs->regs + reg); +} + +static inline void bcm2835aux_wr(struct bcm2835aux_spi *bs, unsigned reg, + u32 val) +{ + writel(val, bs->regs + reg); +} + +static inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs) +{ + u32 data; + int count = min(bs->rx_len, 3); + + data = bcm2835aux_rd(bs, BCM2835_AUX_SPI_IO); + if (bs->rx_buf) { + switch (count) { + case 4: + *bs->rx_buf++ = (data >> 24) & 0xff; + /* fallthrough */ + case 3: + *bs->rx_buf++ = (data >> 16) & 0xff; + /* fallthrough */ + case 2: + *bs->rx_buf++ = (data >> 8) & 0xff; + /* fallthrough */ + case 1: + *bs->rx_buf++ = (data >> 0) & 0xff; + /* fallthrough - no default */ + } + } + bs->rx_len -= count; + bs->pending -= count; +} + +static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs) +{ + u32 data; + u8 byte; + int count; + int i; + + /* gather up to 3 bytes to write to the FIFO */ + count = min(bs->tx_len, 3); + data = 0; + for (i = 0; i < count; i++) { + byte = bs->tx_buf ? *bs->tx_buf++ : 0; + data |= byte << (8 * (2 - i)); + } + + /* and set the variable bit-length */ + data |= (count * 8) << 24; + + /* and decrement length */ + bs->tx_len -= count; + bs->pending += count; + + /* write to the correct TX-register */ + if (bs->tx_len) + bcm2835aux_wr(bs, BCM2835_AUX_SPI_TXHOLD, data); + else + bcm2835aux_wr(bs, BCM2835_AUX_SPI_IO, data); +} + +static void bcm2835aux_spi_reset_hw(struct bcm2835aux_spi *bs) +{ + /* disable spi clearing fifo and interrupts */ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, 0); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, + BCM2835_AUX_SPI_CNTL0_CLEARFIFO); +} + +static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id) +{ + struct spi_master *master = dev_id; + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + irqreturn_t ret = IRQ_NONE; + + /* check if we have data to read */ + while (bs->rx_len && + (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & + BCM2835_AUX_SPI_STAT_RX_EMPTY))) { + bcm2835aux_rd_fifo(bs); + ret = IRQ_HANDLED; + } + + /* check if we have data to write */ + while (bs->tx_len && + (bs->pending < 12) && + (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & + BCM2835_AUX_SPI_STAT_TX_FULL))) { + bcm2835aux_wr_fifo(bs); + ret = IRQ_HANDLED; + } + + /* and check if we have reached "done" */ + while (bs->rx_len && + (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & + BCM2835_AUX_SPI_STAT_BUSY))) { + bcm2835aux_rd_fifo(bs); + ret = IRQ_HANDLED; + } + + /* and if rx_len is 0 then wake up completion and disable spi */ + if (!bs->rx_len) { + bcm2835aux_spi_reset_hw(bs); + complete(&master->xfer_completion); + } + + /* and return */ + return ret; +} + +static int __bcm2835aux_spi_transfer_one_irq(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + + /* enable interrupts */ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1] | + BCM2835_AUX_SPI_CNTL1_TXEMPTY | + BCM2835_AUX_SPI_CNTL1_IDLE); + + /* and wait for finish... */ + return 1; +} + +static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + + /* fill in registers and fifos before enabling interrupts */ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); + + /* fill in tx fifo with data before enabling interrupts */ + while ((bs->tx_len) && + (bs->pending < 12) && + (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & + BCM2835_AUX_SPI_STAT_TX_FULL))) { + bcm2835aux_wr_fifo(bs); + } + + /* now run the interrupt mode */ + return __bcm2835aux_spi_transfer_one_irq(master, spi, tfr); +} + +static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + unsigned long timeout; + u32 stat; + + /* configure spi */ + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); + bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); + + /* set the timeout */ + timeout = jiffies + BCM2835_AUX_SPI_POLLING_JIFFIES; + + /* loop until finished the transfer */ + while (bs->rx_len) { + /* read status */ + stat = bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT); + + /* fill in tx fifo with remaining data */ + if ((bs->tx_len) && (!(stat & BCM2835_AUX_SPI_STAT_TX_FULL))) { + bcm2835aux_wr_fifo(bs); + continue; + } + + /* read data from fifo for both cases */ + if (!(stat & BCM2835_AUX_SPI_STAT_RX_EMPTY)) { + bcm2835aux_rd_fifo(bs); + continue; + } + if (!(stat & BCM2835_AUX_SPI_STAT_BUSY)) { + bcm2835aux_rd_fifo(bs); + continue; + } + + /* there is still data pending to read check the timeout */ + if (bs->rx_len && time_after(jiffies, timeout)) { + dev_dbg_ratelimited(&spi->dev, + "timeout period reached: jiffies: %lu remaining tx/rx: %d/%d - falling back to interrupt mode\n", + jiffies - timeout, + bs->tx_len, bs->rx_len); + /* forward to interrupt handler */ + return __bcm2835aux_spi_transfer_one_irq(master, + spi, tfr); + } + } + + /* Transfer complete - reset SPI HW */ + bcm2835aux_spi_reset_hw(bs); + + /* and return without waiting for completion */ + return 0; +} + +static int bcm2835aux_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + unsigned long spi_hz, clk_hz, speed; + unsigned long spi_used_hz; + unsigned long long xfer_time_us; + + /* calculate the registers to handle + * + * note that we use the variable data mode, which + * is not optimal for longer transfers as we waste registers + * resulting (potentially) in more interrupts when transferring + * more than 12 bytes + */ + bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE | + BCM2835_AUX_SPI_CNTL0_VAR_WIDTH | + BCM2835_AUX_SPI_CNTL0_MSBF_OUT; + bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN; + + /* set clock */ + spi_hz = tfr->speed_hz; + clk_hz = clk_get_rate(bs->clk); + + if (spi_hz >= clk_hz / 2) { + speed = 0; + } else if (spi_hz) { + speed = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1; + if (speed > BCM2835_AUX_SPI_CNTL0_SPEED_MAX) + speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX; + } else { /* the slowest we can go */ + speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX; + } + bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT; + + spi_used_hz = clk_hz / (2 * (speed + 1)); + + /* handle all the modes */ + if (spi->mode & SPI_CPOL) + bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL; + if (spi->mode & SPI_CPHA) + bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT | + BCM2835_AUX_SPI_CNTL0_CPHA_IN; + + /* set transmit buffers and length */ + bs->tx_buf = tfr->tx_buf; + bs->rx_buf = tfr->rx_buf; + bs->tx_len = tfr->len; + bs->rx_len = tfr->len; + bs->pending = 0; + + /* calculate the estimated time in us the transfer runs + * note that there are are 2 idle clocks after each + * chunk getting transferred - in our case the chunk size + * is 3 bytes, so we approximate this by 9 bits/byte + */ + xfer_time_us = tfr->len * 9 * 1000000; + do_div(xfer_time_us, spi_used_hz); + + /* run in polling mode for short transfers */ + if (xfer_time_us < BCM2835_AUX_SPI_POLLING_LIMIT_US) + return bcm2835aux_spi_transfer_one_poll(master, spi, tfr); + + /* run in interrupt mode for all others */ + return bcm2835aux_spi_transfer_one_irq(master, spi, tfr); +} + +static void bcm2835aux_spi_handle_err(struct spi_master *master, + struct spi_message *msg) +{ + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + + bcm2835aux_spi_reset_hw(bs); +} + +static int bcm2835aux_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct bcm2835aux_spi *bs; + struct resource *res; + unsigned long clk_hz; + int err; + + master = spi_alloc_master(&pdev->dev, sizeof(*bs)); + if (!master) { + dev_err(&pdev->dev, "spi_alloc_master() failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, master); + master->mode_bits = BCM2835_AUX_SPI_MODE_BITS; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->num_chipselect = -1; + master->transfer_one = bcm2835aux_spi_transfer_one; + master->handle_err = bcm2835aux_spi_handle_err; + master->dev.of_node = pdev->dev.of_node; + + bs = spi_master_get_devdata(master); + + /* the main area */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + bs->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(bs->regs)) { + err = PTR_ERR(bs->regs); + goto out_master_put; + } + + bs->clk = devm_clk_get(&pdev->dev, NULL); + if ((!bs->clk) || (IS_ERR(bs->clk))) { + err = PTR_ERR(bs->clk); + dev_err(&pdev->dev, "could not get clk: %d\n", err); + goto out_master_put; + } + + bs->irq = platform_get_irq(pdev, 0); + if (bs->irq <= 0) { + dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq); + err = bs->irq ? bs->irq : -ENODEV; + goto out_master_put; + } + + /* this also enables the HW block */ + err = clk_prepare_enable(bs->clk); + if (err) { + dev_err(&pdev->dev, "could not prepare clock: %d\n", err); + goto out_master_put; + } + + /* just checking if the clock returns a sane value */ + clk_hz = clk_get_rate(bs->clk); + if (!clk_hz) { + dev_err(&pdev->dev, "clock returns 0 Hz\n"); + err = -ENODEV; + goto out_clk_disable; + } + + /* reset SPI-HW block */ + bcm2835aux_spi_reset_hw(bs); + + err = devm_request_irq(&pdev->dev, bs->irq, + bcm2835aux_spi_interrupt, + IRQF_SHARED, + dev_name(&pdev->dev), master); + if (err) { + dev_err(&pdev->dev, "could not request IRQ: %d\n", err); + goto out_clk_disable; + } + + err = devm_spi_register_master(&pdev->dev, master); + if (err) { + dev_err(&pdev->dev, "could not register SPI master: %d\n", err); + goto out_clk_disable; + } + + return 0; + +out_clk_disable: + clk_disable_unprepare(bs->clk); +out_master_put: + spi_master_put(master); + return err; +} + +static int bcm2835aux_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct bcm2835aux_spi *bs = spi_master_get_devdata(master); + + bcm2835aux_spi_reset_hw(bs); + + /* disable the HW block by releasing the clock */ + clk_disable_unprepare(bs->clk); + + return 0; +} + +static const struct of_device_id bcm2835aux_spi_match[] = { + { .compatible = "brcm,bcm2835-aux-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, bcm2835aux_spi_match); + +static struct platform_driver bcm2835aux_spi_driver = { + .driver = { + .name = "spi-bcm2835aux", + .of_match_table = bcm2835aux_spi_match, + }, + .probe = bcm2835aux_spi_probe, + .remove = bcm2835aux_spi_remove, +}; +module_platform_driver(bcm2835aux_spi_driver); + +MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2835 aux"); +MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c index 1520554978a3..cc3f938f0a6b 100644 --- a/drivers/spi/spi-bcm53xx.c +++ b/drivers/spi/spi-bcm53xx.c @@ -247,28 +247,19 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core) if (err) { spi_master_put(master); bcma_set_drvdata(core, NULL); - goto out; + return err; } /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */ spi_new_device(master, &bcm53xx_info); -out: - return err; -} - -static void bcm53xxspi_bcma_remove(struct bcma_device *core) -{ - struct bcm53xxspi *b53spi = bcma_get_drvdata(core); - - spi_unregister_master(b53spi->master); + return 0; } static struct bcma_driver bcm53xxspi_bcma_driver = { .name = KBUILD_MODNAME, .id_table = bcm53xxspi_bcma_tbl, .probe = bcm53xxspi_bcma_probe, - .remove = bcm53xxspi_bcma_remove, }; /************************************************** diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index e73e2b052c9c..06858e04ec59 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -27,10 +27,117 @@ #include <linux/err.h> #include <linux/pm_runtime.h> -#include <bcm63xx_dev_spi.h> +/* BCM 6338/6348 SPI core */ +#define SPI_6348_RSET_SIZE 64 +#define SPI_6348_CMD 0x00 /* 16-bits register */ +#define SPI_6348_INT_STATUS 0x02 +#define SPI_6348_INT_MASK_ST 0x03 +#define SPI_6348_INT_MASK 0x04 +#define SPI_6348_ST 0x05 +#define SPI_6348_CLK_CFG 0x06 +#define SPI_6348_FILL_BYTE 0x07 +#define SPI_6348_MSG_TAIL 0x09 +#define SPI_6348_RX_TAIL 0x0b +#define SPI_6348_MSG_CTL 0x40 /* 8-bits register */ +#define SPI_6348_MSG_CTL_WIDTH 8 +#define SPI_6348_MSG_DATA 0x41 +#define SPI_6348_MSG_DATA_SIZE 0x3f +#define SPI_6348_RX_DATA 0x80 +#define SPI_6348_RX_DATA_SIZE 0x3f + +/* BCM 3368/6358/6262/6368 SPI core */ +#define SPI_6358_RSET_SIZE 1804 +#define SPI_6358_MSG_CTL 0x00 /* 16-bits register */ +#define SPI_6358_MSG_CTL_WIDTH 16 +#define SPI_6358_MSG_DATA 0x02 +#define SPI_6358_MSG_DATA_SIZE 0x21e +#define SPI_6358_RX_DATA 0x400 +#define SPI_6358_RX_DATA_SIZE 0x220 +#define SPI_6358_CMD 0x700 /* 16-bits register */ +#define SPI_6358_INT_STATUS 0x702 +#define SPI_6358_INT_MASK_ST 0x703 +#define SPI_6358_INT_MASK 0x704 +#define SPI_6358_ST 0x705 +#define SPI_6358_CLK_CFG 0x706 +#define SPI_6358_FILL_BYTE 0x707 +#define SPI_6358_MSG_TAIL 0x709 +#define SPI_6358_RX_TAIL 0x70B + +/* Shared SPI definitions */ + +/* Message configuration */ +#define SPI_FD_RW 0x00 +#define SPI_HD_W 0x01 +#define SPI_HD_R 0x02 +#define SPI_BYTE_CNT_SHIFT 0 +#define SPI_6348_MSG_TYPE_SHIFT 6 +#define SPI_6358_MSG_TYPE_SHIFT 14 + +/* Command */ +#define SPI_CMD_NOOP 0x00 +#define SPI_CMD_SOFT_RESET 0x01 +#define SPI_CMD_HARD_RESET 0x02 +#define SPI_CMD_START_IMMEDIATE 0x03 +#define SPI_CMD_COMMAND_SHIFT 0 +#define SPI_CMD_COMMAND_MASK 0x000f +#define SPI_CMD_DEVICE_ID_SHIFT 4 +#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT 8 +#define SPI_CMD_ONE_BYTE_SHIFT 11 +#define SPI_CMD_ONE_WIRE_SHIFT 12 +#define SPI_DEV_ID_0 0 +#define SPI_DEV_ID_1 1 +#define SPI_DEV_ID_2 2 +#define SPI_DEV_ID_3 3 + +/* Interrupt mask */ +#define SPI_INTR_CMD_DONE 0x01 +#define SPI_INTR_RX_OVERFLOW 0x02 +#define SPI_INTR_TX_UNDERFLOW 0x04 +#define SPI_INTR_TX_OVERFLOW 0x08 +#define SPI_INTR_RX_UNDERFLOW 0x10 +#define SPI_INTR_CLEAR_ALL 0x1f + +/* Status */ +#define SPI_RX_EMPTY 0x02 +#define SPI_CMD_BUSY 0x04 +#define SPI_SERIAL_BUSY 0x08 + +/* Clock configuration */ +#define SPI_CLK_20MHZ 0x00 +#define SPI_CLK_0_391MHZ 0x01 +#define SPI_CLK_0_781MHZ 0x02 /* default */ +#define SPI_CLK_1_563MHZ 0x03 +#define SPI_CLK_3_125MHZ 0x04 +#define SPI_CLK_6_250MHZ 0x05 +#define SPI_CLK_12_50MHZ 0x06 +#define SPI_CLK_MASK 0x07 +#define SPI_SSOFFTIME_MASK 0x38 +#define SPI_SSOFFTIME_SHIFT 3 +#define SPI_BYTE_SWAP 0x80 + +enum bcm63xx_regs_spi { + SPI_CMD, + SPI_INT_STATUS, + SPI_INT_MASK_ST, + SPI_INT_MASK, + SPI_ST, + SPI_CLK_CFG, + SPI_FILL_BYTE, + SPI_MSG_TAIL, + SPI_RX_TAIL, + SPI_MSG_CTL, + SPI_MSG_DATA, + SPI_RX_DATA, + SPI_MSG_TYPE_SHIFT, + SPI_MSG_CTL_WIDTH, + SPI_MSG_DATA_SIZE, +}; #define BCM63XX_SPI_MAX_PREPEND 15 +#define BCM63XX_SPI_MAX_CS 8 +#define BCM63XX_SPI_BUS_NUM 0 + struct bcm63xx_spi { struct completion done; @@ -38,6 +145,7 @@ struct bcm63xx_spi { int irq; /* Platform data */ + const unsigned long *reg_offsets; unsigned fifo_size; unsigned int msg_type_shift; unsigned int msg_ctl_width; @@ -51,27 +159,35 @@ struct bcm63xx_spi { }; static inline u8 bcm_spi_readb(struct bcm63xx_spi *bs, - unsigned int offset) + unsigned int offset) { - return bcm_readb(bs->regs + bcm63xx_spireg(offset)); + return readb(bs->regs + bs->reg_offsets[offset]); } static inline u16 bcm_spi_readw(struct bcm63xx_spi *bs, unsigned int offset) { - return bcm_readw(bs->regs + bcm63xx_spireg(offset)); +#ifdef CONFIG_CPU_BIG_ENDIAN + return ioread16be(bs->regs + bs->reg_offsets[offset]); +#else + return readw(bs->regs + bs->reg_offsets[offset]); +#endif } static inline void bcm_spi_writeb(struct bcm63xx_spi *bs, u8 value, unsigned int offset) { - bcm_writeb(value, bs->regs + bcm63xx_spireg(offset)); + writeb(value, bs->regs + bs->reg_offsets[offset]); } static inline void bcm_spi_writew(struct bcm63xx_spi *bs, u16 value, unsigned int offset) { - bcm_writew(value, bs->regs + bcm63xx_spireg(offset)); +#ifdef CONFIG_CPU_BIG_ENDIAN + iowrite16be(value, bs->regs + bs->reg_offsets[offset]); +#else + writew(value, bs->regs + bs->reg_offsets[offset]); +#endif } static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = { @@ -122,7 +238,6 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first, struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); u16 msg_ctl; u16 cmd; - u8 rx_tail; unsigned int i, timeout = 0, prepend_len = 0, len = 0; struct spi_transfer *t = first; bool do_rx = false; @@ -314,18 +429,71 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static const unsigned long bcm6348_spi_reg_offsets[] = { + [SPI_CMD] = SPI_6348_CMD, + [SPI_INT_STATUS] = SPI_6348_INT_STATUS, + [SPI_INT_MASK_ST] = SPI_6348_INT_MASK_ST, + [SPI_INT_MASK] = SPI_6348_INT_MASK, + [SPI_ST] = SPI_6348_ST, + [SPI_CLK_CFG] = SPI_6348_CLK_CFG, + [SPI_FILL_BYTE] = SPI_6348_FILL_BYTE, + [SPI_MSG_TAIL] = SPI_6348_MSG_TAIL, + [SPI_RX_TAIL] = SPI_6348_RX_TAIL, + [SPI_MSG_CTL] = SPI_6348_MSG_CTL, + [SPI_MSG_DATA] = SPI_6348_MSG_DATA, + [SPI_RX_DATA] = SPI_6348_RX_DATA, + [SPI_MSG_TYPE_SHIFT] = SPI_6348_MSG_TYPE_SHIFT, + [SPI_MSG_CTL_WIDTH] = SPI_6348_MSG_CTL_WIDTH, + [SPI_MSG_DATA_SIZE] = SPI_6348_MSG_DATA_SIZE, +}; + +static const unsigned long bcm6358_spi_reg_offsets[] = { + [SPI_CMD] = SPI_6358_CMD, + [SPI_INT_STATUS] = SPI_6358_INT_STATUS, + [SPI_INT_MASK_ST] = SPI_6358_INT_MASK_ST, + [SPI_INT_MASK] = SPI_6358_INT_MASK, + [SPI_ST] = SPI_6358_ST, + [SPI_CLK_CFG] = SPI_6358_CLK_CFG, + [SPI_FILL_BYTE] = SPI_6358_FILL_BYTE, + [SPI_MSG_TAIL] = SPI_6358_MSG_TAIL, + [SPI_RX_TAIL] = SPI_6358_RX_TAIL, + [SPI_MSG_CTL] = SPI_6358_MSG_CTL, + [SPI_MSG_DATA] = SPI_6358_MSG_DATA, + [SPI_RX_DATA] = SPI_6358_RX_DATA, + [SPI_MSG_TYPE_SHIFT] = SPI_6358_MSG_TYPE_SHIFT, + [SPI_MSG_CTL_WIDTH] = SPI_6358_MSG_CTL_WIDTH, + [SPI_MSG_DATA_SIZE] = SPI_6358_MSG_DATA_SIZE, +}; + +static const struct platform_device_id bcm63xx_spi_dev_match[] = { + { + .name = "bcm6348-spi", + .driver_data = (unsigned long)bcm6348_spi_reg_offsets, + }, + { + .name = "bcm6358-spi", + .driver_data = (unsigned long)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; - struct bcm63xx_spi_pdata *pdata = dev_get_platdata(&pdev->dev); int irq; struct spi_master *master; struct clk *clk; struct bcm63xx_spi *bs; int ret; + if (!pdev->id_entry->driver_data) + return -EINVAL; + + bcm63xx_spireg = (const unsigned long *)pdev->id_entry->driver_data; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "no irq\n"); @@ -359,7 +527,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) bs->irq = irq; bs->clk = clk; - bs->fifo_size = pdata->fifo_size; + bs->reg_offsets = bcm63xx_spireg; + bs->fifo_size = bs->reg_offsets[SPI_MSG_DATA_SIZE]; ret = devm_request_irq(&pdev->dev, irq, bcm63xx_spi_interrupt, 0, pdev->name, master); @@ -368,26 +537,16 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) goto out_err; } - master->bus_num = pdata->bus_num; - master->num_chipselect = pdata->num_chipselect; + master->bus_num = BCM63XX_SPI_BUS_NUM; + master->num_chipselect = BCM63XX_SPI_MAX_CS; master->transfer_one_message = bcm63xx_spi_transfer_one; master->mode_bits = MODEBITS; master->bits_per_word_mask = SPI_BPW_MASK(8); master->auto_runtime_pm = true; - bs->msg_type_shift = pdata->msg_type_shift; - bs->msg_ctl_width = pdata->msg_ctl_width; - bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA)); - bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA)); - - switch (bs->msg_ctl_width) { - case 8: - case 16: - break; - default: - dev_err(dev, "unsupported MSG_CTL width: %d\n", - bs->msg_ctl_width); - goto out_err; - } + bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT]; + bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH]; + bs->tx_io = (u8 *)(bs->regs + bs->reg_offsets[SPI_MSG_DATA]); + bs->rx_io = (const u8 *)(bs->regs + bs->reg_offsets[SPI_RX_DATA]); /* Initialize hardware */ ret = clk_prepare_enable(bs->clk); @@ -467,6 +626,7 @@ static struct platform_driver bcm63xx_spi_driver = { .name = "bcm63xx-spi", .pm = &bcm63xx_spi_pm_ops, }, + .id_table = bcm63xx_spi_dev_match, .probe = bcm63xx_spi_probe, .remove = bcm63xx_spi_remove, }; diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c index a78693189f45..6c967555a56a 100644 --- a/drivers/spi/spi-bfin-sport.c +++ b/drivers/spi/spi-bfin-sport.c @@ -352,10 +352,7 @@ bfin_sport_spi_pump_transfers(unsigned long data) transfer = drv_data->cur_transfer; chip = drv_data->cur_chip; - if (transfer->speed_hz) - transfer_speed = bfin_sport_hz_to_spi_baud(transfer->speed_hz); - else - transfer_speed = chip->baud; + transfer_speed = bfin_sport_hz_to_spi_baud(transfer->speed_hz); bfin_write(&drv_data->regs->tclkdiv, transfer_speed); SSYNC(); diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c index a3d65b4f4944..1e91325bf39c 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -661,11 +661,7 @@ static void bfin_spi_pump_transfers(unsigned long data) message->state = RUNNING_STATE; dma_config = 0; - /* Speed setup (surely valid because already checked) */ - if (transfer->speed_hz) - bfin_write(&drv_data->regs->baud, hz_to_spi_baud(transfer->speed_hz)); - else - bfin_write(&drv_data->regs->baud, chip->baud); + bfin_write(&drv_data->regs->baud, hz_to_spi_baud(transfer->speed_hz)); bfin_write(&drv_data->regs->stat, BIT_STAT_CLR); bfin_spi_cs_active(drv_data, chip); diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 840a4984d365..3aa9e6e3dac8 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -24,6 +24,8 @@ #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> +#define SPI_BITBANG_CS_DELAY 100 + /*----------------------------------------------------------------------*/ @@ -180,7 +182,6 @@ int spi_bitbang_setup(struct spi_device *spi) { struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang *bitbang; - unsigned long flags; bitbang = spi_master_get_devdata(spi->master); @@ -210,12 +211,12 @@ int spi_bitbang_setup(struct spi_device *spi) */ /* deselect chip (low or high) */ - spin_lock_irqsave(&bitbang->lock, flags); + mutex_lock(&bitbang->lock); if (!bitbang->busy) { bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ndelay(cs->nsecs); } - spin_unlock_irqrestore(&bitbang->lock, flags); + mutex_unlock(&bitbang->lock); return 0; } @@ -255,122 +256,39 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) static int spi_bitbang_prepare_hardware(struct spi_master *spi) { struct spi_bitbang *bitbang; - unsigned long flags; bitbang = spi_master_get_devdata(spi); - spin_lock_irqsave(&bitbang->lock, flags); + mutex_lock(&bitbang->lock); bitbang->busy = 1; - spin_unlock_irqrestore(&bitbang->lock, flags); + mutex_unlock(&bitbang->lock); return 0; } static int spi_bitbang_transfer_one(struct spi_master *master, - struct spi_message *m) + struct spi_device *spi, + struct spi_transfer *transfer) { - struct spi_bitbang *bitbang; - unsigned nsecs; - struct spi_transfer *t = NULL; - unsigned cs_change; - int status; - int do_setup = -1; - struct spi_device *spi = m->spi; - - bitbang = spi_master_get_devdata(master); - - /* FIXME this is made-up ... the correct value is known to - * word-at-a-time bitbang code, and presumably chipselect() - * should enforce these requirements too? - */ - nsecs = 100; - - cs_change = 1; - status = 0; - - list_for_each_entry(t, &m->transfers, transfer_list) { - - /* override speed or wordsize? */ - if (t->speed_hz || t->bits_per_word) - do_setup = 1; - - /* init (-1) or override (1) transfer params */ - if (do_setup != 0) { - if (bitbang->setup_transfer) { - status = bitbang->setup_transfer(spi, t); - if (status < 0) - break; - } - if (do_setup == -1) - do_setup = 0; - } - - /* set up default clock polarity, and activate chip; - * this implicitly updates clock and spi modes as - * previously recorded for this device via setup(). - * (and also deselects any other chip that might be - * selected ...) - */ - if (cs_change) { - bitbang->chipselect(spi, BITBANG_CS_ACTIVE); - ndelay(nsecs); - } - cs_change = t->cs_change; - if (!t->tx_buf && !t->rx_buf && t->len) { - status = -EINVAL; - break; - } - - /* transfer data. the lower level code handles any - * new dma mappings it needs. our caller always gave - * us dma-safe buffers. - */ - if (t->len) { - /* REVISIT dma API still needs a designated - * DMA_ADDR_INVALID; ~0 might be better. - */ - if (!m->is_dma_mapped) - t->rx_dma = t->tx_dma = 0; - status = bitbang->txrx_bufs(spi, t); - } - if (status > 0) - m->actual_length += status; - if (status != t->len) { - /* always report some kind of error */ - if (status >= 0) - status = -EREMOTEIO; - break; - } - status = 0; + struct spi_bitbang *bitbang = spi_master_get_devdata(master); + int status = 0; - /* protocol tweaks before next transfer */ - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (cs_change && - !list_is_last(&t->transfer_list, &m->transfers)) { - /* sometimes a short mid-message deselect of the chip - * may be needed to terminate a mode or command - */ - ndelay(nsecs); - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } + if (bitbang->setup_transfer) { + status = bitbang->setup_transfer(spi, transfer); + if (status < 0) + goto out; } - m->status = status; + if (transfer->len) + status = bitbang->txrx_bufs(spi, transfer); - /* normally deactivate chipselect ... unless no error and - * cs_change has hinted that the next message will probably - * be for this chip too. - */ - if (!(status == 0 && cs_change)) { - ndelay(nsecs); - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } + if (status == transfer->len) + status = 0; + else if (status >= 0) + status = -EREMOTEIO; - spi_finalize_current_message(master); +out: + spi_finalize_current_transfer(master); return status; } @@ -378,17 +296,32 @@ static int spi_bitbang_transfer_one(struct spi_master *master, static int spi_bitbang_unprepare_hardware(struct spi_master *spi) { struct spi_bitbang *bitbang; - unsigned long flags; bitbang = spi_master_get_devdata(spi); - spin_lock_irqsave(&bitbang->lock, flags); + mutex_lock(&bitbang->lock); bitbang->busy = 0; - spin_unlock_irqrestore(&bitbang->lock, flags); + mutex_unlock(&bitbang->lock); return 0; } +static void spi_bitbang_set_cs(struct spi_device *spi, bool enable) +{ + struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master); + + /* SPI core provides CS high / low, but bitbang driver + * expects CS active + * spi device driver takes care of handling SPI_CS_HIGH + */ + enable = (!!(spi->mode & SPI_CS_HIGH) == enable); + + ndelay(SPI_BITBANG_CS_DELAY); + bitbang->chipselect(spi, enable ? BITBANG_CS_ACTIVE : + BITBANG_CS_INACTIVE); + ndelay(SPI_BITBANG_CS_DELAY); +} + /*----------------------------------------------------------------------*/ /** @@ -427,7 +360,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) if (!master || !bitbang->chipselect) return -EINVAL; - spin_lock_init(&bitbang->lock); + mutex_init(&bitbang->lock); if (!master->mode_bits) master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; @@ -437,7 +370,8 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) master->prepare_transfer_hardware = spi_bitbang_prepare_hardware; master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware; - master->transfer_one_message = spi_bitbang_transfer_one; + master->transfer_one = spi_bitbang_transfer_one; + master->set_cs = spi_bitbang_set_cs; if (!bitbang->txrx_bufs) { bitbang->use_dma = 0; diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 688956ff5095..23f6fffd75e1 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -420,19 +420,20 @@ static int mcfqspi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; platform_set_drvdata(pdev, master); + pm_runtime_enable(&pdev->dev); status = devm_spi_register_master(&pdev->dev, master); if (status) { dev_dbg(&pdev->dev, "spi_register_master failed\n"); goto fail2; } - pm_runtime_enable(&pdev->dev); dev_info(&pdev->dev, "Coldfire QSPI bus driver\n"); return 0; fail2: + pm_runtime_disable(&pdev->dev); mcfqspi_cs_teardown(mcfqspi); fail1: clk_disable(mcfqspi->clk); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index a85d863d4a44..7d3af3eacf57 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -215,18 +215,10 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) struct davinci_spi_config *spicfg = spi->controller_data; u8 chip_sel = spi->chip_select; u16 spidat1 = CS_DEFAULT; - bool gpio_chipsel = false; - int gpio; dspi = spi_master_get_devdata(spi->master); pdata = &dspi->pdata; - if (spi->cs_gpio >= 0) { - /* SPI core parse and update master->cs_gpio */ - gpio_chipsel = true; - gpio = spi->cs_gpio; - } - /* program delay transfers if tx_delay is non zero */ if (spicfg->wdelay) spidat1 |= SPIDAT1_WDEL; @@ -235,11 +227,12 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) * Board specific chip select logic decides the polarity and cs * line for the controller */ - if (gpio_chipsel) { + if (spi->cs_gpio >= 0) { if (value == BITBANG_CS_ACTIVE) - gpio_set_value(gpio, spi->mode & SPI_CS_HIGH); + gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH); else - gpio_set_value(gpio, !(spi->mode & SPI_CS_HIGH)); + gpio_set_value(spi->cs_gpio, + !(spi->mode & SPI_CS_HIGH)); } else { if (value == BITBANG_CS_ACTIVE) { spidat1 |= SPIDAT1_CSHOLD_MASK; diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 7edede6e024b..a6d7029a85ac 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -19,6 +19,7 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_platform.h> +#include <linux/property.h> #include "spi-dw.h" @@ -74,13 +75,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) dws->max_freq = clk_get_rate(dwsmmio->clk); - of_property_read_u32(pdev->dev.of_node, "reg-io-width", - &dws->reg_io_width); + device_property_read_u32(&pdev->dev, "reg-io-width", &dws->reg_io_width); num_cs = 4; - if (pdev->dev.of_node) - of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); + device_property_read_u32(&pdev->dev, "num-cs", &num_cs); dws->num_cs = num_cs; diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 6d331e0db331..332ccb0539a7 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -23,11 +23,6 @@ #define DRIVER_NAME "dw_spi_pci" -struct dw_spi_pci { - struct pci_dev *pdev; - struct dw_spi dws; -}; - struct spi_pci_desc { int (*setup)(struct dw_spi *); u16 num_cs; @@ -48,7 +43,6 @@ static struct spi_pci_desc spi_pci_mid_desc_2 = { static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct dw_spi_pci *dwpci; struct dw_spi *dws; struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data; int pci_bar = 0; @@ -58,14 +52,10 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - dwpci = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_pci), - GFP_KERNEL); - if (!dwpci) + dws = devm_kzalloc(&pdev->dev, sizeof(*dws), GFP_KERNEL); + if (!dws) return -ENOMEM; - dwpci->pdev = pdev; - dws = &dwpci->dws; - /* Get basic io resource and map it */ dws->paddr = pci_resource_start(pdev, pci_bar); @@ -74,7 +64,6 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; dws->regs = pcim_iomap_table(pdev)[pci_bar]; - dws->irq = pdev->irq; /* @@ -99,7 +88,7 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; /* PCI hook and SPI hook use the same drv data */ - pci_set_drvdata(pdev, dwpci); + pci_set_drvdata(pdev, dws); dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", pdev->vendor, pdev->device); @@ -109,26 +98,26 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static void spi_pci_remove(struct pci_dev *pdev) { - struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); + struct dw_spi *dws = pci_get_drvdata(pdev); - dw_spi_remove_host(&dwpci->dws); + dw_spi_remove_host(dws); } #ifdef CONFIG_PM_SLEEP static int spi_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); + struct dw_spi *dws = pci_get_drvdata(pdev); - return dw_spi_suspend_host(&dwpci->dws); + return dw_spi_suspend_host(dws); } static int spi_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); + struct dw_spi *dws = pci_get_drvdata(pdev); - return dw_spi_resume_host(&dwpci->dws); + return dw_spi_resume_host(dws); } #endif diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 4fbfcdc5cb24..882cd6618cd5 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -30,19 +30,13 @@ /* Slave spi_dev related */ struct chip_data { - u16 cr0; u8 cs; /* chip select pin */ - u8 n_bytes; /* current is a 1/2/4 byte op */ u8 tmode; /* TR/TO/RO/EEPROM */ u8 type; /* SPI/SSP/MicroWire */ u8 poll_mode; /* 1 means use poll mode */ - u32 dma_width; - u32 rx_threshold; - u32 tx_threshold; u8 enable_dma; - u8 bits_per_word; u16 clk_div; /* baud rate divider */ u32 speed_hz; /* baud rate */ void (*cs_control)(u32 command); @@ -289,14 +283,11 @@ static int dw_spi_transfer_one(struct spi_master *master, struct chip_data *chip = spi_get_ctldata(spi); u8 imask = 0; u16 txlevel = 0; - u16 clk_div = 0; - u32 speed = 0; - u32 cr0 = 0; + u16 clk_div; + u32 cr0; int ret; dws->dma_mapped = 0; - dws->n_bytes = chip->n_bytes; - dws->dma_width = chip->dma_width; dws->tx = (void *)transfer->tx_buf; dws->tx_end = dws->tx + transfer->len; @@ -306,37 +297,30 @@ static int dw_spi_transfer_one(struct spi_master *master, spi_enable_chip(dws, 0); - cr0 = chip->cr0; - /* Handle per transfer options for bpw and speed */ - if (transfer->speed_hz) { - speed = chip->speed_hz; - - if ((transfer->speed_hz != speed) || !chip->clk_div) { - speed = transfer->speed_hz; - - /* clk_div doesn't support odd number */ - clk_div = (dws->max_freq / speed + 1) & 0xfffe; + if (transfer->speed_hz != chip->speed_hz) { + /* clk_div doesn't support odd number */ + clk_div = (dws->max_freq / transfer->speed_hz + 1) & 0xfffe; - chip->speed_hz = speed; - chip->clk_div = clk_div; + chip->speed_hz = transfer->speed_hz; + chip->clk_div = clk_div; - spi_set_clk(dws, chip->clk_div); - } + spi_set_clk(dws, chip->clk_div); } - if (transfer->bits_per_word) { - if (transfer->bits_per_word == 8) { - dws->n_bytes = 1; - dws->dma_width = 1; - } else if (transfer->bits_per_word == 16) { - dws->n_bytes = 2; - dws->dma_width = 2; - } - cr0 = (transfer->bits_per_word - 1) - | (chip->type << SPI_FRF_OFFSET) - | (spi->mode << SPI_MODE_OFFSET) - | (chip->tmode << SPI_TMOD_OFFSET); + if (transfer->bits_per_word == 8) { + dws->n_bytes = 1; + dws->dma_width = 1; + } else if (transfer->bits_per_word == 16) { + dws->n_bytes = 2; + dws->dma_width = 2; + } else { + return -EINVAL; } + /* Default SPI mode is SCPOL = 0, SCPH = 0 */ + cr0 = (transfer->bits_per_word - 1) + | (chip->type << SPI_FRF_OFFSET) + | (spi->mode << SPI_MODE_OFFSET) + | (chip->tmode << SPI_TMOD_OFFSET); /* * Adjust transfer mode if necessary. Requires platform dependent @@ -439,34 +423,9 @@ static int dw_spi_setup(struct spi_device *spi) chip->poll_mode = chip_info->poll_mode; chip->type = chip_info->type; - - chip->rx_threshold = 0; - chip->tx_threshold = 0; - } - - if (spi->bits_per_word == 8) { - chip->n_bytes = 1; - chip->dma_width = 1; - } else if (spi->bits_per_word == 16) { - chip->n_bytes = 2; - chip->dma_width = 2; - } - chip->bits_per_word = spi->bits_per_word; - - if (!spi->max_speed_hz) { - dev_err(&spi->dev, "No max speed HZ parameter\n"); - return -EINVAL; } chip->tmode = 0; /* Tx & Rx */ - /* Default SPI mode is SCPOL = 0, SCPH = 0 */ - chip->cr0 = (chip->bits_per_word - 1) - | (chip->type << SPI_FRF_OFFSET) - | (spi->mode << SPI_MODE_OFFSET) - | (chip->tmode << SPI_TMOD_OFFSET); - - if (spi->mode & SPI_LOOP) - chip->cr0 |= 1 << SPI_SRL_OFFSET; if (gpio_is_valid(spi->cs_gpio)) { ret = gpio_direction_output(spi->cs_gpio, @@ -524,13 +483,12 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->master = master; dws->type = SSI_MOTO_SPI; dws->dma_inited = 0; - dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60); + dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num); - ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED, - dws->name, master); + ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master); if (ret < 0) { - dev_err(&master->dev, "can not get IRQ\n"); + dev_err(dev, "can not get IRQ\n"); goto err_free_master; } @@ -573,6 +531,7 @@ err_dma_exit: if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); spi_enable_chip(dws, 0); + free_irq(dws->irq, master); err_free_master: spi_master_put(master); return ret; @@ -581,28 +540,27 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host); void dw_spi_remove_host(struct dw_spi *dws) { - if (!dws) - return; dw_spi_debugfs_remove(dws); if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); - spi_enable_chip(dws, 0); - /* Disable clk */ - spi_set_clk(dws, 0); + + spi_shutdown_chip(dws); + + free_irq(dws->irq, dws->master); } EXPORT_SYMBOL_GPL(dw_spi_remove_host); int dw_spi_suspend_host(struct dw_spi *dws) { - int ret = 0; + int ret; ret = spi_master_suspend(dws->master); if (ret) return ret; - spi_enable_chip(dws, 0); - spi_set_clk(dws, 0); - return ret; + + spi_shutdown_chip(dws); + return 0; } EXPORT_SYMBOL_GPL(dw_spi_suspend_host); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index b75ed327d5a2..35589a270468 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -225,6 +225,12 @@ static inline void spi_reset_chip(struct dw_spi *dws) spi_enable_chip(dws, 1); } +static inline void spi_shutdown_chip(struct dw_spi *dws) +{ + spi_enable_chip(dws, 0); + spi_set_clk(dws, 0); +} + /* * Each SPI slave device to work with dw_api controller should * has such a structure claiming its working mode (poll or PIO/DMA), diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 86bcdd68c1fe..59a11437db70 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -409,9 +409,6 @@ static int dspi_transfer_one_message(struct spi_master *master, SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF); regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val); - if (transfer->speed_hz) - regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), - dspi->cur_chip->ctar_val); trans_mode = dspi->devtype_data->trans_mode; switch (trans_mode) { diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index f9deb84e4e55..0e5723ab47f0 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -336,13 +336,20 @@ 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); + else + cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(config->cs); if (config->mode & SPI_CPOL) { cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs); cfg |= MX51_ECSPI_CONFIG_SCLKCTL(config->cs); + } else { + 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); + else + cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(config->cs); writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG); diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 1e75341689a6..c3ec46cd9f91 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -302,11 +302,9 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master, cs_change = 1; status = 0; list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->bits_per_word || t->speed_hz) { - status = mpc512x_psc_spi_transfer_setup(spi, t); - if (status < 0) - break; - } + status = mpc512x_psc_spi_transfer_setup(spi, t); + if (status < 0) + break; if (cs_change) mpc512x_psc_spi_activate_cs(spi); diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 76656a77ec12..b5911282a611 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -207,8 +207,7 @@ static int tiny_spi_of_probe(struct platform_device *pdev) struct tiny_spi *hw = platform_get_drvdata(pdev); struct device_node *np = pdev->dev.of_node; unsigned int i; - const __be32 *val; - int len; + u32 val; if (!np) return 0; @@ -226,13 +225,10 @@ static int tiny_spi_of_probe(struct platform_device *pdev) return -ENODEV; } hw->bitbang.master->dev.of_node = pdev->dev.of_node; - val = of_get_property(pdev->dev.of_node, - "clock-frequency", &len); - if (val && len >= sizeof(__be32)) - hw->freq = be32_to_cpup(val); - val = of_get_property(pdev->dev.of_node, "baud-width", &len); - if (val && len >= sizeof(__be32)) - hw->baudwidth = be32_to_cpup(val); + if (!of_property_read_u32(np, "clock-frequency", &val)) + hw->freq = val; + if (!of_property_read_u32(np, "baud-width", &val)) + hw->baudwidth = val; return 0; } #else /* !CONFIG_OF */ diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index e99d6a93d394..07e4ce8273df 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -65,7 +65,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, cpha = mode & SPI_CPHA; cpol = mode & SPI_CPOL; - speed_hz = xfer->speed_hz ? : spi->max_speed_hz; + speed_hz = xfer->speed_hz; clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 3d09e0b69b73..1f8903d356e5 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1217,6 +1217,33 @@ out: return status; } +static int omap2_mcspi_prepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + struct omap2_mcspi_regs *ctx = &mcspi->ctx; + struct omap2_mcspi_cs *cs; + + /* Only a single channel can have the FORCE bit enabled + * in its chconf0 register. + * Scan all channels and disable them except the current one. + * A FORCE can remain from a last transfer having cs_change enabled + */ + list_for_each_entry(cs, &ctx->cs, node) { + if (msg->spi->controller_state == cs) + continue; + + if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) { + cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; + writel_relaxed(cs->chconf0, + cs->base + OMAP2_MCSPI_CHCONF0); + readl_relaxed(cs->base + OMAP2_MCSPI_CHCONF0); + } + } + + return 0; +} + static int omap2_mcspi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *t) { @@ -1344,6 +1371,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->setup = omap2_mcspi_setup; master->auto_runtime_pm = true; + master->prepare_message = omap2_mcspi_prepare_message; master->transfer_one = omap2_mcspi_transfer_one; master->set_cs = omap2_mcspi_set_cs; master->cleanup = omap2_mcspi_cleanup; diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 54fb984a3e17..dd3d0a218d8b 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -210,12 +210,12 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t) if (in_8(&hw->regs->cdm) != cdm) out_8(&hw->regs->cdm, cdm); - spin_lock(&hw->bitbang.lock); + mutex_lock(&hw->bitbang.lock); if (!hw->bitbang.busy) { hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); /* Need to ndelay here? */ } - spin_unlock(&hw->bitbang.lock); + mutex_unlock(&hw->bitbang.lock); return 0; } diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index f36bc320a807..4e7d1bfed7e6 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -198,12 +198,12 @@ static int s3c24xx_spi_setup(struct spi_device *spi) if (ret) return ret; - spin_lock(&hw->bitbang.lock); + mutex_lock(&hw->bitbang.lock); if (!hw->bitbang.busy) { hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); /* need to ndelay for 0.5 clocktick ? */ } - spin_unlock(&hw->bitbang.lock); + mutex_unlock(&hw->bitbang.lock); return 0; } diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index aa6d284131e0..81b84858cfee 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -410,11 +410,10 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, mutex_unlock(&qspi->list_lock); + ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); m->status = status; spi_finalize_current_message(master); - ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); - return status; } diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index a339c1e9997a..3009121173cd 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -270,6 +270,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) while (remaining_words) { int n_words, tx_words, rx_words; + u32 sr; n_words = min(remaining_words, xspi->buffer_size); @@ -284,24 +285,33 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) if (use_irq) { xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); wait_for_completion(&xspi->done); - } else - while (!(xspi->read_fn(xspi->regs + XSPI_SR_OFFSET) & - XSPI_SR_TX_EMPTY_MASK)) - ; - - /* A transmit has just completed. Process received data and - * check for more data to transmit. Always inhibit the - * transmitter while the Isr refills the transmit register/FIFO, - * or make sure it is stopped if we're done. - */ - if (use_irq) + /* A transmit has just completed. Process received data + * and check for more data to transmit. Always inhibit + * the transmitter while the Isr refills the transmit + * register/FIFO, or make sure it is stopped if we're + * done. + */ xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, - xspi->regs + XSPI_CR_OFFSET); + xspi->regs + XSPI_CR_OFFSET); + sr = XSPI_SR_TX_EMPTY_MASK; + } else + sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); /* Read out all the data from the Rx FIFO */ rx_words = n_words; - while (rx_words--) - xilinx_spi_rx(xspi); + while (rx_words) { + if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) { + xilinx_spi_rx(xspi); + rx_words--; + continue; + } + + sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); + if (!(sr & XSPI_SR_RX_EMPTY_MASK)) { + xilinx_spi_rx(xspi); + rx_words--; + } + } remaining_words -= n_words; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a5f53de813d3..f9e92f535cbb 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -123,6 +123,28 @@ SPI_STATISTICS_SHOW(bytes, "%llu"); SPI_STATISTICS_SHOW(bytes_rx, "%llu"); SPI_STATISTICS_SHOW(bytes_tx, "%llu"); +#define SPI_STATISTICS_TRANSFER_BYTES_HISTO(index, number) \ + SPI_STATISTICS_SHOW_NAME(transfer_bytes_histo##index, \ + "transfer_bytes_histo_" number, \ + transfer_bytes_histo[index], "%lu") +SPI_STATISTICS_TRANSFER_BYTES_HISTO(0, "0-1"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(1, "2-3"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(2, "4-7"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(3, "8-15"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(4, "16-31"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(5, "32-63"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(6, "64-127"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(7, "128-255"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(8, "256-511"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(9, "512-1023"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(10, "1024-2047"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(11, "2048-4095"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(12, "4096-8191"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(13, "8192-16383"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(14, "16384-32767"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(15, "32768-65535"); +SPI_STATISTICS_TRANSFER_BYTES_HISTO(16, "65536+"); + static struct attribute *spi_dev_attrs[] = { &dev_attr_modalias.attr, NULL, @@ -143,6 +165,23 @@ static struct attribute *spi_device_statistics_attrs[] = { &dev_attr_spi_device_bytes.attr, &dev_attr_spi_device_bytes_rx.attr, &dev_attr_spi_device_bytes_tx.attr, + &dev_attr_spi_device_transfer_bytes_histo0.attr, + &dev_attr_spi_device_transfer_bytes_histo1.attr, + &dev_attr_spi_device_transfer_bytes_histo2.attr, + &dev_attr_spi_device_transfer_bytes_histo3.attr, + &dev_attr_spi_device_transfer_bytes_histo4.attr, + &dev_attr_spi_device_transfer_bytes_histo5.attr, + &dev_attr_spi_device_transfer_bytes_histo6.attr, + &dev_attr_spi_device_transfer_bytes_histo7.attr, + &dev_attr_spi_device_transfer_bytes_histo8.attr, + &dev_attr_spi_device_transfer_bytes_histo9.attr, + &dev_attr_spi_device_transfer_bytes_histo10.attr, + &dev_attr_spi_device_transfer_bytes_histo11.attr, + &dev_attr_spi_device_transfer_bytes_histo12.attr, + &dev_attr_spi_device_transfer_bytes_histo13.attr, + &dev_attr_spi_device_transfer_bytes_histo14.attr, + &dev_attr_spi_device_transfer_bytes_histo15.attr, + &dev_attr_spi_device_transfer_bytes_histo16.attr, NULL, }; @@ -168,6 +207,23 @@ static struct attribute *spi_master_statistics_attrs[] = { &dev_attr_spi_master_bytes.attr, &dev_attr_spi_master_bytes_rx.attr, &dev_attr_spi_master_bytes_tx.attr, + &dev_attr_spi_master_transfer_bytes_histo0.attr, + &dev_attr_spi_master_transfer_bytes_histo1.attr, + &dev_attr_spi_master_transfer_bytes_histo2.attr, + &dev_attr_spi_master_transfer_bytes_histo3.attr, + &dev_attr_spi_master_transfer_bytes_histo4.attr, + &dev_attr_spi_master_transfer_bytes_histo5.attr, + &dev_attr_spi_master_transfer_bytes_histo6.attr, + &dev_attr_spi_master_transfer_bytes_histo7.attr, + &dev_attr_spi_master_transfer_bytes_histo8.attr, + &dev_attr_spi_master_transfer_bytes_histo9.attr, + &dev_attr_spi_master_transfer_bytes_histo10.attr, + &dev_attr_spi_master_transfer_bytes_histo11.attr, + &dev_attr_spi_master_transfer_bytes_histo12.attr, + &dev_attr_spi_master_transfer_bytes_histo13.attr, + &dev_attr_spi_master_transfer_bytes_histo14.attr, + &dev_attr_spi_master_transfer_bytes_histo15.attr, + &dev_attr_spi_master_transfer_bytes_histo16.attr, NULL, }; @@ -186,10 +242,15 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats, struct spi_master *master) { unsigned long flags; + int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1; + + if (l2len < 0) + l2len = 0; spin_lock_irqsave(&stats->lock, flags); stats->transfers++; + stats->transfer_bytes_histo[l2len]++; stats->bytes += xfer->len; if ((xfer->tx_buf) && @@ -270,15 +331,24 @@ EXPORT_SYMBOL_GPL(spi_bus_type); static int spi_drv_probe(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); + struct spi_device *spi = to_spi_device(dev); int ret; ret = of_clk_set_defaults(dev->of_node, false); if (ret) return ret; + if (dev->of_node) { + spi->irq = of_irq_get(dev->of_node, 0); + if (spi->irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (spi->irq < 0) + spi->irq = 0; + } + ret = dev_pm_domain_attach(dev, true); if (ret != -EPROBE_DEFER) { - ret = sdrv->probe(to_spi_device(dev)); + ret = sdrv->probe(spi); if (ret) dev_pm_domain_detach(dev, true); } @@ -308,6 +378,8 @@ static void spi_drv_shutdown(struct device *dev) * spi_register_driver - register a SPI driver * @sdrv: the driver to register * Context: can sleep + * + * Return: zero on success, else a negative error code. */ int spi_register_driver(struct spi_driver *sdrv) { @@ -359,7 +431,7 @@ static DEFINE_MUTEX(board_lock); * needs to discard the spi_device without adding it, then it should * call spi_dev_put() on it. * - * Returns a pointer to the new device, or NULL. + * Return: a pointer to the new device, or NULL. */ struct spi_device *spi_alloc_device(struct spi_master *master) { @@ -418,7 +490,7 @@ static int spi_dev_check(struct device *dev, void *data) * Companion function to spi_alloc_device. Devices allocated with * spi_alloc_device can be added onto the spi bus with this function. * - * Returns 0 on success; negative errno on failure + * Return: 0 on success; negative errno on failure */ int spi_add_device(struct spi_device *spi) { @@ -491,7 +563,7 @@ EXPORT_SYMBOL_GPL(spi_add_device); * this is exported so that for example a USB or parport based adapter * driver could add devices (which it would learn about out-of-band). * - * Returns the new device, or NULL. + * Return: the new device, or NULL. */ struct spi_device *spi_new_device(struct spi_master *master, struct spi_board_info *chip) @@ -563,6 +635,8 @@ static void spi_match_master_to_boardinfo(struct spi_master *master, * * The board info passed can safely be __initdata ... but be careful of * any embedded pointers (platform_data, etc), they're copied as-is. + * + * Return: zero on success, else a negative error code. */ int spi_register_board_info(struct spi_board_info const *info, unsigned n) { @@ -597,7 +671,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable) if (spi->mode & SPI_CS_HIGH) enable = !enable; - if (spi->cs_gpio >= 0) + if (gpio_is_valid(spi->cs_gpio)) gpio_set_value(spi->cs_gpio, !enable); else if (spi->master->set_cs) spi->master->set_cs(spi, !enable); @@ -1140,6 +1214,8 @@ static int spi_init_queue(struct spi_master *master) * * If there are more messages in the queue, the next message is returned from * this call. + * + * Return: the next message in the queue, else NULL if the queue is empty. */ struct spi_message *spi_get_next_queued_message(struct spi_master *master) { @@ -1303,6 +1379,8 @@ static int __spi_queued_transfer(struct spi_device *spi, * spi_queued_transfer - transfer function for queued transfers * @spi: spi device which is requesting transfer * @msg: spi message which is to handled is queued to driver queue + * + * Return: zero on success, else a negative error code. */ static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) { @@ -1433,9 +1511,6 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc) } spi->max_speed_hz = value; - /* IRQ */ - spi->irq = irq_of_parse_and_map(nc, 0); - /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.of_node = nc; @@ -1605,12 +1680,13 @@ static struct class spi_master_class = { * only ones directly touching chip registers. It's how they allocate * an spi_master structure, prior to calling spi_register_master(). * - * This must be called from context that can sleep. It returns the SPI - * master structure on success, else NULL. + * This must be called from context that can sleep. * * The caller is responsible for assigning the bus number and initializing * the master's methods before calling spi_register_master(); and (after errors * adding the device) calling spi_master_put() to prevent a memory leak. + * + * Return: the SPI master structure on success, else NULL. */ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) { @@ -1694,6 +1770,8 @@ static int of_spi_register_master(struct spi_master *master) * success, else a negative error code (dropping the master's refcount). * After a successful return, the caller is responsible for calling * spi_unregister_master(). + * + * Return: zero on success, else a negative error code. */ int spi_register_master(struct spi_master *master) { @@ -1787,6 +1865,8 @@ static void devm_spi_unregister(struct device *dev, void *res) * * Register a SPI device as with spi_register_master() which will * automatically be unregister + * + * Return: zero on success, else a negative error code. */ int devm_spi_register_master(struct device *dev, struct spi_master *master) { @@ -1892,6 +1972,8 @@ static int __spi_master_match(struct device *dev, const void *data) * arch init time. It returns a refcounted pointer to the relevant * spi_master (which the caller must release), or NULL if there is * no such master registered. + * + * Return: the SPI master structure on success, else NULL. */ struct spi_master *spi_busnum_to_master(u16 bus_num) { @@ -1945,11 +2027,13 @@ static int __spi_validate_bits_per_word(struct spi_master *master, u8 bits_per_w * that the underlying controller or its driver does not support. For * example, not all hardware supports wire transfers using nine bit words, * LSB-first wire encoding, or active-high chipselects. + * + * Return: zero on success, else a negative error code. */ int spi_setup(struct spi_device *spi) { unsigned bad_bits, ugly_bits; - int status = 0; + int status; /* check mode to prevent that DUAL and QUAD set at the same time */ @@ -1986,17 +2070,18 @@ int spi_setup(struct spi_device *spi) if (!spi->bits_per_word) spi->bits_per_word = 8; - if (__spi_validate_bits_per_word(spi->master, spi->bits_per_word)) - return -EINVAL; + status = __spi_validate_bits_per_word(spi->master, spi->bits_per_word); + if (status) + return status; if (!spi->max_speed_hz) spi->max_speed_hz = spi->master->max_speed_hz; - spi_set_cs(spi, false); - if (spi->master->setup) status = spi->master->setup(spi); + spi_set_cs(spi, false); + dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n", (int) (spi->mode & (SPI_CPOL | SPI_CPHA)), (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", @@ -2162,6 +2247,8 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) * no other spi_message queued to that device will be processed. * (This rule applies equally to all the synchronous transfer calls, * which are wrappers around this core asynchronous primitive.) + * + * Return: zero on success, else a negative error code. */ int spi_async(struct spi_device *spi, struct spi_message *message) { @@ -2214,6 +2301,8 @@ EXPORT_SYMBOL_GPL(spi_async); * no other spi_message queued to that device will be processed. * (This rule applies equally to all the synchronous transfer calls, * which are wrappers around this core asynchronous primitive.) + * + * Return: zero on success, else a negative error code. */ int spi_async_locked(struct spi_device *spi, struct spi_message *message) { @@ -2329,7 +2418,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, * Also, the caller is guaranteeing that the memory associated with the * message will not be freed before this call returns. * - * It returns zero on success, else a negative error code. + * Return: zero on success, else a negative error code. */ int spi_sync(struct spi_device *spi, struct spi_message *message) { @@ -2351,7 +2440,7 @@ EXPORT_SYMBOL_GPL(spi_sync); * SPI bus. It has to be preceded by a spi_bus_lock call. The SPI bus must * be released by a spi_bus_unlock call when the exclusive access is over. * - * It returns zero on success, else a negative error code. + * Return: zero on success, else a negative error code. */ int spi_sync_locked(struct spi_device *spi, struct spi_message *message) { @@ -2372,7 +2461,7 @@ EXPORT_SYMBOL_GPL(spi_sync_locked); * exclusive access is over. Data transfer must be done by spi_sync_locked * and spi_async_locked calls when the SPI bus lock is held. * - * It returns zero on success, else a negative error code. + * Return: always zero. */ int spi_bus_lock(struct spi_master *master) { @@ -2401,7 +2490,7 @@ EXPORT_SYMBOL_GPL(spi_bus_lock); * This call releases an SPI bus lock previously obtained by an spi_bus_lock * call. * - * It returns zero on success, else a negative error code. + * Return: always zero. */ int spi_bus_unlock(struct spi_master *master) { @@ -2436,6 +2525,8 @@ static u8 *buf; * portable code should never use this for more than 32 bytes. * Performance-sensitive or bulk transfer code should instead use * spi_{async,sync}() calls with dma-safe buffers. + * + * Return: zero on success, else a negative error code. */ int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, |