提交 d25e436c 编写于 作者: L Linus Torvalds

Merge tag 'spi-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi updates from Mark Brown:
 "There's quite a lot of small driver specific fixes and enhancements in
  this release but the main activity has been around the loopback and
  spidev test drivers which is good to see as it should hopefully help
  improve the quality of all the drivers as people start to make use of
  the new code:

   - Additional tests in the loopback test driver for vmalloc()
     compatibility and around delays together with fixes for existing
     tests.

   - Support for testing continuous data transfer for use in soak
     testing.

   - Device property support for board info platforms.

   - Support for registering empty sets of devices via board info
     (useful when writing code to enumerate hardware automatically)"

* tag 'spi-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (52 commits)
  spi: cadence: Allow for GPIO pins to be used as chipselects
  spi-imx: Implements handling of the SPI_READY mode flag.
  spi: tegra: fix spelling mistake: "trasfer" -> "transfer"
  spi: spi-ti-qspi: Use bounce buffer if read buffer is not DMA'ble
  spi: Add can_dma like interface for spi_flash_read
  spi: dw: Disable clock after unregistering the host
  spi: double time out tolerance
  spi: atmel: add deepest PM support to SAMA5D2
  spi: atmel: factorize reusable code for SPI controller init
  spi: orion: add LSB support
  spi: pl022: don't use uninitialized variable
  spi: loopback-test: fix spelling mistake: "minimam" -> "minimum"
  spi: dynamycally allocated message initialization
  spi: spi-ti-qspi: Remove unused dma_dev variable
  spi: omap2-mcspi: poll OMAP2_MCSPI_CHSTAT_RXS for PIO transfer
  spi: spi-ti-qspi: Use dma_engine wrapper for dma memcpy call
  spi: spidev_test: add option to continuously transfer data
  spi: loopback-test: fix potential integer overflow on multiple
  spi: sun6i: update max transfer size reported
  spi: pl022: Document property values
  ...
......@@ -23,6 +23,12 @@ See the clock consumer binding,
Obsolete properties:
- fsl,spi-num-chipselects : Contains the number of the chipselect
Optional properties:
- fsl,spi-rdy-drctl: Integer, representing the value of DRCTL, the register
controlling the SPI_READY handling. Note that to enable the DRCTL consideration,
the SPI_READY mode-flag needs to be set too.
Valid values are: 0 (disabled), 1 (edge-triggered burst) and 2 (level-triggered burst).
Example:
ecspi@70010000 {
......@@ -35,4 +41,5 @@ ecspi@70010000 {
<&gpio3 25 0>; /* GPIO3_25 */
dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
dma-names = "rx", "tx";
fsl,spi-rdy-drctl = <1>;
};
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>;
};
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>;
};
......@@ -30,7 +30,10 @@ contain the following properties.
0: SPI
1: Texas Instruments Synchronous Serial Frame Format
2: Microwire (Half Duplex)
- pl022,com-mode : polling, interrupt or dma
- pl022,com-mode : specifies the transfer mode:
0: interrupt mode
1: polling mode (default mode if property not present)
2: DMA mode
- pl022,rx-level-trig : Rx FIFO watermark level
- pl022,tx-level-trig : Tx FIFO watermark level
- pl022,ctrl-len : Microwire interface: Control length
......@@ -56,9 +59,7 @@ Example:
spi-max-frequency = <12000000>;
spi-cpol;
spi-cpha;
pl022,hierarchy = <0>;
pl022,interface = <0>;
pl022,slave-tx-disable;
pl022,com-mode = <0x2>;
pl022,rx-level-trig = <0>;
pl022,tx-level-trig = <0>;
......@@ -67,4 +68,3 @@ Example:
pl022,duplex = <0>;
};
};
......@@ -169,6 +169,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
#ifdef CONFIG_ARM64
{ "APMC0D0F", APD_ADDR(xgene_i2c_desc) },
{ "BRCM900D", APD_ADDR(vulcan_spi_desc) },
{ "CAV900D", APD_ADDR(vulcan_spi_desc) },
#endif
{ }
};
......
......@@ -715,7 +715,7 @@ config SPI_XILINX
config SPI_XLP
tristate "Netlogic XLP SPI controller driver"
depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST
depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST
help
Enable support for the SPI controller on the Netlogic XLP SoCs.
Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX
......
......@@ -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)
......
......@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
#include <linux/mutex.h>
#include <linux/of.h>
#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,
......
......@@ -26,6 +26,7 @@
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
/* 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)
return -EINVAL;
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;
}
bcm63xx_spireg = (const unsigned long *)pdev->id_entry->driver_data;
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;
}
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,
......
......@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
......@@ -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;
......
......@@ -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;
......
......@@ -115,8 +115,8 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
{
struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
clk_disable_unprepare(dwsmmio->clk);
dw_spi_remove_host(&dwsmmio->dws);
clk_disable_unprepare(dwsmmio->clk);
return 0;
}
......
......@@ -1002,7 +1002,8 @@ static int dspi_probe(struct platform_device *pdev)
if (IS_ERR(dspi->regmap)) {
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
PTR_ERR(dspi->regmap));
return PTR_ERR(dspi->regmap);
ret = PTR_ERR(dspi->regmap);
goto out_master_put;
}
dspi_init(dspi);
......
......@@ -814,7 +814,7 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
struct device_node *np = ofdev->dev.of_node;
struct spi_master *master;
struct resource mem;
int irq, type;
int irq = 0, type;
int ret = -ENOMEM;
ret = of_mpc8xxx_spi_probe(ofdev);
......@@ -847,6 +847,7 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
return 0;
err:
irq_dispose_mapping(irq);
if (type == TYPE_FSL)
of_fsl_spi_free_chipselects(dev);
return ret;
......
......@@ -95,6 +95,7 @@ struct spi_imx_data {
unsigned int spi_bus_clk;
unsigned int bytes_per_word;
unsigned int spi_drctl;
unsigned int count;
void (*tx)(struct spi_imx_data *);
......@@ -246,6 +247,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_CTRL_XCH (1 << 2)
#define MX51_ECSPI_CTRL_SMC (1 << 3)
#define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4)
#define MX51_ECSPI_CTRL_DRCTL(drctl) ((drctl) << 16)
#define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8
#define MX51_ECSPI_CTRL_PREDIV_OFFSET 12
#define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18)
......@@ -355,6 +357,12 @@ static int mx51_ecspi_config(struct spi_device *spi,
*/
ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
/*
* Enable SPI_RDY handling (falling edge/level triggered).
*/
if (spi->mode & SPI_READY)
ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl);
/* set clock speed */
ctrl |= mx51_ecspi_clkdiv(spi_imx, config->speed_hz, &clk);
spi_imx->spi_bus_clk = clk;
......@@ -1173,7 +1181,7 @@ static int spi_imx_probe(struct platform_device *pdev)
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
int i, ret, irq;
int i, ret, irq, spi_drctl;
if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
......@@ -1181,6 +1189,12 @@ static int spi_imx_probe(struct platform_device *pdev)
}
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
ret = of_property_read_u32(np, "fsl,spi-rdy-drctl", &spi_drctl);
if ((ret < 0) || (spi_drctl >= 0x3)) {
/* '11' is reserved */
spi_drctl = 0;
}
if (!master)
return -ENOMEM;
......@@ -1216,7 +1230,9 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx))
spi_imx->bitbang.master->mode_bits |= SPI_LOOP;
spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY;
spi_imx->spi_drctl = spi_drctl;
init_completion(&spi_imx->xfer_done);
......
此差异已折叠。
......@@ -20,11 +20,13 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/list_sort.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/printk.h>
#include <linux/vmalloc.h>
#include <linux/spi/spi.h>
#include "spi-test.h"
......@@ -55,6 +57,18 @@ module_param(run_only_test, int, 0);
MODULE_PARM_DESC(run_only_test,
"only run the test with this number (0-based !)");
/* use vmalloc'ed buffers */
int use_vmalloc;
module_param(use_vmalloc, int, 0644);
MODULE_PARM_DESC(use_vmalloc,
"use vmalloc'ed buffers instead of kmalloc'ed");
/* check rx ranges */
int check_ranges = 1;
module_param(check_ranges, int, 0644);
MODULE_PARM_DESC(check_ranges,
"checks rx_buffer pattern are valid");
/* the actual tests to execute */
static struct spi_test spi_tests[] = {
{
......@@ -63,9 +77,9 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_rx_align = ITERATE_ALIGN,
.transfer_count = 1,
.transfers = {
{
.len = 1,
.tx_buf = TX(0),
.rx_buf = RX(0),
},
......@@ -77,9 +91,9 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_rx_align = ITERATE_ALIGN,
.transfer_count = 1,
.transfers = {
{
.len = 1,
.tx_buf = TX(PAGE_SIZE - 4),
.rx_buf = RX(PAGE_SIZE - 4),
},
......@@ -90,9 +104,9 @@ static struct spi_test spi_tests[] = {
.fill_option = FILL_COUNT_8,
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.transfer_count = 1,
.transfers = {
{
.len = 1,
.tx_buf = TX(0),
},
},
......@@ -102,9 +116,9 @@ static struct spi_test spi_tests[] = {
.fill_option = FILL_COUNT_8,
.iterate_len = { ITERATE_MAX_LEN },
.iterate_rx_align = ITERATE_ALIGN,
.transfer_count = 1,
.transfers = {
{
.len = 1,
.rx_buf = RX(0),
},
},
......@@ -115,13 +129,12 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(0) | BIT(1),
.transfer_count = 2,
.transfers = {
{
.len = 1,
.tx_buf = TX(0),
},
{
.len = 1,
/* this is why we cant use ITERATE_MAX_LEN */
.tx_buf = TX(SPI_TEST_MAX_SIZE_HALF),
},
......@@ -132,10 +145,10 @@ static struct spi_test spi_tests[] = {
.fill_option = FILL_COUNT_8,
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(1),
.iterate_transfer_mask = BIT(0),
.transfer_count = 2,
.transfers = {
{
.len = 1,
.tx_buf = TX(64),
},
{
......@@ -149,14 +162,14 @@ static struct spi_test spi_tests[] = {
.fill_option = FILL_COUNT_8,
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(0),
.iterate_transfer_mask = BIT(1),
.transfer_count = 2,
.transfers = {
{
.len = 16,
.tx_buf = TX(0),
},
{
.len = 1,
.tx_buf = TX(64),
},
},
......@@ -167,13 +180,12 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(0) | BIT(1),
.transfer_count = 2,
.transfers = {
{
.len = 1,
.tx_buf = TX(0),
},
{
.len = 1,
.rx_buf = RX(0),
},
},
......@@ -184,9 +196,9 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(0),
.transfer_count = 2,
.transfers = {
{
.len = 1,
.tx_buf = TX(0),
},
{
......@@ -201,13 +213,13 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(1),
.transfer_count = 2,
.transfers = {
{
.len = 1,
.tx_buf = TX(0),
},
{
.len = 1,
.rx_buf = RX(0),
},
},
......@@ -218,14 +230,13 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(0) | BIT(1),
.transfer_count = 2,
.transfers = {
{
.len = 1,
.tx_buf = TX(0),
.rx_buf = RX(0),
},
{
.len = 1,
/* making sure we align without overwrite
* the reason we can not use ITERATE_MAX_LEN
*/
......@@ -240,9 +251,9 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(0),
.transfer_count = 2,
.transfers = {
{
.len = 1,
/* making sure we align without overwrite */
.tx_buf = TX(1024),
.rx_buf = RX(1024),
......@@ -261,6 +272,7 @@ static struct spi_test spi_tests[] = {
.iterate_len = { ITERATE_MAX_LEN },
.iterate_tx_align = ITERATE_ALIGN,
.iterate_transfer_mask = BIT(1),
.transfer_count = 2,
.transfers = {
{
.len = 1,
......@@ -268,13 +280,31 @@ static struct spi_test spi_tests[] = {
.rx_buf = RX(0),
},
{
.len = 1,
/* making sure we align without overwrite */
.tx_buf = TX(1024),
.rx_buf = RX(1024),
},
},
},
{
.description = "two tx+rx transfers - delay after transfer",
.fill_option = FILL_COUNT_8,
.iterate_len = { ITERATE_MAX_LEN },
.iterate_transfer_mask = BIT(0) | BIT(1),
.transfer_count = 2,
.transfers = {
{
.tx_buf = TX(0),
.rx_buf = RX(0),
.delay_usecs = 1000,
},
{
.tx_buf = TX(0),
.rx_buf = RX(0),
.delay_usecs = 1000,
},
},
},
{ /* end of tests sequence */ }
};
......@@ -482,6 +512,36 @@ static int spi_check_rx_ranges(struct spi_device *spi,
return ret;
}
static int spi_test_check_elapsed_time(struct spi_device *spi,
struct spi_test *test)
{
int i;
unsigned long long estimated_time = 0;
unsigned long long delay_usecs = 0;
for (i = 0; i < test->transfer_count; i++) {
struct spi_transfer *xfer = test->transfers + i;
unsigned long long nbits = (unsigned long long)BITS_PER_BYTE *
xfer->len;
delay_usecs += xfer->delay_usecs;
if (!xfer->speed_hz)
continue;
estimated_time += div_u64(nbits * NSEC_PER_SEC, xfer->speed_hz);
}
estimated_time += delay_usecs * NSEC_PER_USEC;
if (test->elapsed_time < estimated_time) {
dev_err(&spi->dev,
"elapsed time %lld ns is shorter than minimum estimated time %lld ns\n",
test->elapsed_time, estimated_time);
return -EINVAL;
}
return 0;
}
static int spi_test_check_loopback_result(struct spi_device *spi,
struct spi_message *msg,
void *tx, void *rx)
......@@ -492,9 +552,11 @@ static int spi_test_check_loopback_result(struct spi_device *spi,
int ret;
/* checks rx_buffer pattern are valid with loopback or without */
ret = spi_check_rx_ranges(spi, msg, rx);
if (ret)
return ret;
if (check_ranges) {
ret = spi_check_rx_ranges(spi, msg, rx);
if (ret)
return ret;
}
/* if we run without loopback, then return now */
if (!loopback)
......@@ -503,11 +565,11 @@ static int spi_test_check_loopback_result(struct spi_device *spi,
/* if applicable to transfer check that rx_buf is equal to tx_buf */
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
/* if there is no rx, then no check is needed */
if (!xfer->rx_buf)
if (!xfer->len || !xfer->rx_buf)
continue;
/* so depending on tx_buf we need to handle things */
if (xfer->tx_buf) {
for (i = 1; i < xfer->len; i++) {
for (i = 0; i < xfer->len; i++) {
txb = ((u8 *)xfer->tx_buf)[i];
rxb = ((u8 *)xfer->rx_buf)[i];
if (txb != rxb)
......@@ -745,15 +807,6 @@ static int spi_test_run_iter(struct spi_device *spi,
/* copy the test template to test */
memcpy(&test, testtemplate, sizeof(test));
/* set up test->transfers to the correct count */
if (!test.transfer_count) {
for (i = 0;
(i < SPI_TEST_MAX_TRANSFERS) && test.transfers[i].len;
i++) {
test.transfer_count++;
}
}
/* if iterate_transfer_mask is not set,
* then set it to first transfer only
*/
......@@ -799,8 +852,7 @@ static int spi_test_run_iter(struct spi_device *spi,
/* only when bit in transfer mask is set */
if (!(test.iterate_transfer_mask & BIT(i)))
continue;
if (len)
test.transfers[i].len = len;
test.transfers[i].len = len;
if (test.transfers[i].tx_buf)
test.transfers[i].tx_buf += tx_off;
if (test.transfers[i].tx_buf)
......@@ -830,12 +882,16 @@ int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test,
/* only if we do not simulate */
if (!simulate_only) {
ktime_t start;
/* dump the complete message before and after the transfer */
if (dump_messages == 3)
spi_test_dump_message(spi, msg, true);
start = ktime_get();
/* run spi message */
ret = spi_sync(spi, msg);
test->elapsed_time = ktime_to_ns(ktime_sub(ktime_get(), start));
if (ret == -ETIMEDOUT) {
dev_info(&spi->dev,
"spi-message timed out - reruning...\n");
......@@ -861,6 +917,10 @@ int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test,
/* run rx-buffer tests */
ret = spi_test_check_loopback_result(spi, msg, tx, rx);
if (ret)
goto exit;
ret = spi_test_check_elapsed_time(spi, test);
}
/* if requested or on error dump message (including data) */
......@@ -910,15 +970,6 @@ int spi_test_run_test(struct spi_device *spi, const struct spi_test *test,
/* iterate over all the iterable values using macros
* (to make it a bit more readable...
*/
#define FOR_EACH_ITERATE(var, defaultvalue) \
for (idx_##var = -1, var = defaultvalue; \
((idx_##var < 0) || \
( \
(idx_##var < SPI_TEST_MAX_ITERATE) && \
(var = test->iterate_##var[idx_##var]) \
) \
); \
idx_##var++)
#define FOR_EACH_ALIGNMENT(var) \
for (var = 0; \
var < (test->iterate_##var ? \
......@@ -928,7 +979,8 @@ int spi_test_run_test(struct spi_device *spi, const struct spi_test *test,
1); \
var++)
FOR_EACH_ITERATE(len, 0) {
for (idx_len = 0; idx_len < SPI_TEST_MAX_ITERATE &&
(len = test->iterate_len[idx_len]) != -1; idx_len++) {
FOR_EACH_ALIGNMENT(tx_align) {
FOR_EACH_ALIGNMENT(rx_align) {
/* and run the iteration */
......@@ -965,13 +1017,19 @@ int spi_test_run_tests(struct spi_device *spi,
/* allocate rx/tx buffers of 128kB size without devm
* in the hope that is on a page boundary
*/
rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
if (use_vmalloc)
rx = vmalloc(SPI_TEST_MAX_SIZE_PLUS);
else
rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
if (!rx) {
ret = -ENOMEM;
goto out;
}
tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
if (use_vmalloc)
tx = vmalloc(SPI_TEST_MAX_SIZE_PLUS);
else
tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
if (!tx) {
ret = -ENOMEM;
goto out;
......@@ -999,8 +1057,8 @@ int spi_test_run_tests(struct spi_device *spi,
}
out:
kfree(rx);
kfree(tx);
kvfree(rx);
kvfree(tx);
return ret;
}
EXPORT_SYMBOL_GPL(spi_test_run_tests);
......@@ -454,6 +454,8 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
int elements = 0;
int word_len, element_count;
struct omap2_mcspi_cs *cs = spi->controller_state;
void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
count = xfer->len;
......@@ -549,8 +551,8 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
if (l & OMAP2_MCSPI_CHCONF_TURBO) {
elements--;
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
& OMAP2_MCSPI_CHSTAT_RXS)) {
if (!mcspi_wait_for_reg_bit(chstat_reg,
OMAP2_MCSPI_CHSTAT_RXS)) {
u32 w;
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
......@@ -568,8 +570,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
return count;
}
}
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
& OMAP2_MCSPI_CHSTAT_RXS)) {
if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) {
u32 w;
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
......
......@@ -39,6 +39,8 @@
#define ORION_SPI_IF_CTRL_REG 0x00
#define ORION_SPI_IF_CONFIG_REG 0x04
#define ORION_SPI_IF_RXLSBF BIT(14)
#define ORION_SPI_IF_TXLSBF BIT(13)
#define ORION_SPI_DATA_OUT_REG 0x08
#define ORION_SPI_DATA_IN_REG 0x0c
#define ORION_SPI_INT_CAUSE_REG 0x10
......@@ -234,6 +236,11 @@ orion_spi_mode_set(struct spi_device *spi)
reg |= ORION_SPI_MODE_CPOL;
if (spi->mode & SPI_CPHA)
reg |= ORION_SPI_MODE_CPHA;
if (spi->mode & SPI_LSB_FIRST)
reg |= ORION_SPI_IF_RXLSBF | ORION_SPI_IF_TXLSBF;
else
reg &= ~(ORION_SPI_IF_RXLSBF | ORION_SPI_IF_TXLSBF);
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
}
......@@ -591,8 +598,8 @@ static int orion_spi_probe(struct platform_device *pdev)
master->bus_num = cell_index;
}
/* we support only mode 0, and no options */
master->mode_bits = SPI_CPHA | SPI_CPOL;
/* we support all 4 SPI modes and LSB first option */
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
master->set_cs = orion_spi_set_cs;
master->transfer_one = orion_spi_transfer_one;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
......
......@@ -2074,7 +2074,7 @@ pl022_platform_data_dt_get(struct device *dev)
{
struct device_node *np = dev->of_node;
struct pl022_ssp_controller *pd;
u32 tmp;
u32 tmp = 0;
if (!np) {
dev_err(dev, "no dt node defined\n");
......
......@@ -21,6 +21,7 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/sc18is602.h>
#include <linux/gpio/consumer.h>
......@@ -271,7 +272,10 @@ static int sc18is602_probe(struct i2c_client *client,
hw->dev = dev;
hw->ctrl = 0xff;
hw->id = id->driver_data;
if (client->dev.of_node)
hw->id = (enum chips)of_device_get_match_data(&client->dev);
else
hw->id = id->driver_data;
switch (hw->id) {
case sc18is602:
......@@ -323,9 +327,27 @@ static const struct i2c_device_id sc18is602_id[] = {
};
MODULE_DEVICE_TABLE(i2c, sc18is602_id);
static const struct of_device_id sc18is602_of_match[] = {
{
.compatible = "nxp,sc18is602",
.data = (void *)sc18is602
},
{
.compatible = "nxp,sc18is602b",
.data = (void *)sc18is602b
},
{
.compatible = "nxp,sc18is603",
.data = (void *)sc18is603
},
{ },
};
MODULE_DEVICE_TABLE(of, sc18is602_of_match);
static struct i2c_driver sc18is602_driver = {
.driver = {
.name = "sc18is602",
.of_match_table = of_match_ptr(sc18is602_of_match),
},
.probe = sc18is602_probe,
.id_table = sc18is602_id,
......
......@@ -46,13 +46,19 @@
#define SUN6I_TFR_CTL_XCH BIT(31)
#define SUN6I_INT_CTL_REG 0x10
#define SUN6I_INT_CTL_RF_RDY BIT(0)
#define SUN6I_INT_CTL_TF_ERQ BIT(4)
#define SUN6I_INT_CTL_RF_OVF BIT(8)
#define SUN6I_INT_CTL_TC BIT(12)
#define SUN6I_INT_STA_REG 0x14
#define SUN6I_FIFO_CTL_REG 0x18
#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK 0xff
#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS 0
#define SUN6I_FIFO_CTL_RF_RST BIT(15)
#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK 0xff
#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS 16
#define SUN6I_FIFO_CTL_TF_RST BIT(31)
#define SUN6I_FIFO_STA_REG 0x1c
......@@ -68,14 +74,16 @@
#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
#define SUN6I_CLK_CTL_DRS BIT(12)
#define SUN6I_MAX_XFER_SIZE 0xffffff
#define SUN6I_BURST_CNT_REG 0x30
#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff)
#define SUN6I_BURST_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
#define SUN6I_XMIT_CNT_REG 0x34
#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
#define SUN6I_XMIT_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
#define SUN6I_BURST_CTL_CNT_REG 0x38
#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff)
#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
#define SUN6I_TXDATA_REG 0x200
#define SUN6I_RXDATA_REG 0x300
......@@ -105,6 +113,31 @@ static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
writel(value, sspi->base_addr + reg);
}
static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
{
u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
}
static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask)
{
u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
reg |= mask;
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
}
static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask)
{
u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
reg &= ~mask;
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
}
static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
{
u32 reg, cnt;
......@@ -127,10 +160,13 @@ static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
{
u32 cnt;
u8 byte;
if (len > sspi->len)
len = sspi->len;
/* See how much data we can fit */
cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
len = min3(len, (int)cnt, sspi->len);
while (len--) {
byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
......@@ -158,9 +194,7 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
{
struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
return sspi->fifo_depth - 1;
return SUN6I_MAX_XFER_SIZE - 1;
}
static int sun6i_spi_transfer_one(struct spi_master *master,
......@@ -170,12 +204,12 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
struct sun6i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, timeout;
unsigned int start, end, tx_time;
unsigned int trig_level;
unsigned int tx_len = 0;
int ret = 0;
u32 reg;
/* We don't support transfer larger than the FIFO */
if (tfr->len > sspi->fifo_depth)
if (tfr->len > SUN6I_MAX_XFER_SIZE)
return -EINVAL;
reinit_completion(&sspi->done);
......@@ -190,6 +224,17 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
/*
* Setup FIFO interrupt trigger level
* Here we choose 3/4 of the full fifo depth, as it's the hardcoded
* value used in old generation of Allwinner SPI controller.
* (See spi-sun4i.c)
*/
trig_level = sspi->fifo_depth / 4 * 3;
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
(trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
(trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
/*
* Setup the transfer control register: Chip Select,
* polarities, etc.
......@@ -274,6 +319,10 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
/* Enable the interrupts */
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
SUN6I_INT_CTL_RF_RDY);
if (tx_len > sspi->fifo_depth)
sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
/* Start the transfer */
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
......@@ -293,8 +342,6 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
goto out;
}
sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
out:
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
......@@ -309,10 +356,33 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
/* Transfer complete */
if (status & SUN6I_INT_CTL_TC) {
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
complete(&sspi->done);
return IRQ_HANDLED;
}
/* Receive FIFO 3/4 full */
if (status & SUN6I_INT_CTL_RF_RDY) {
sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
/* Only clear the interrupt _after_ draining the FIFO */
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY);
return IRQ_HANDLED;
}
/* Transmit FIFO 3/4 empty */
if (status & SUN6I_INT_CTL_TF_ERQ) {
sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
if (!sspi->len)
/* nothing left to transmit */
sun6i_spi_disable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
/* Only clear the interrupt _after_ re-seeding the FIFO */
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TF_ERQ);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
......
......@@ -837,7 +837,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
SPI_DMA_TIMEOUT);
if (WARN_ON(ret == 0)) {
dev_err(tspi->dev,
"spi trasfer timeout, err %d\n", ret);
"spi transfer timeout, err %d\n", ret);
ret = -EIO;
goto complete_xfer;
}
......
......@@ -341,7 +341,7 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master,
SPI_DMA_TIMEOUT);
if (WARN_ON(ret == 0)) {
dev_err(tsd->dev,
"spi trasfer timeout, err %d\n", ret);
"spi transfer timeout, err %d\n", ret);
ret = -EIO;
goto exit;
}
......
......@@ -824,7 +824,7 @@ static int tegra_slink_transfer_one(struct spi_master *master,
SLINK_DMA_TIMEOUT);
if (WARN_ON(ret == 0)) {
dev_err(tspi->dev,
"spi trasfer timeout, err %d\n", ret);
"spi transfer timeout, err %d\n", ret);
return -EIO;
}
......
......@@ -48,9 +48,8 @@
*
* @msg: a template @spi_message usedfor the default settings
* @transfers: array of @spi_transfers that are part of the
* resulting spi_message. The first transfer with len == 0
* signifies the end of the list
* @transfer_count: normally computed number of transfers with len > 0
* resulting spi_message.
* @transfer_count: number of transfers
*
* @run_test: run a specific spi_test - this allows to override
* the default implementation of @spi_test_run_transfer
......@@ -62,8 +61,7 @@
* @expected_return: the expected return code - in some cases we want to
* test also for error conditions
*
* @iterate_len: list of length to iterate on (in addition to the
* explicitly set @spi_transfer.len)
* @iterate_len: list of length to iterate on
* @iterate_tx_align: change the alignment of @spi_transfer.tx_buf
* for all values in the below range if set.
* the ranges are:
......@@ -77,6 +75,7 @@
* @fill_option: define the way how tx_buf is filled
* @fill_pattern: fill pattern to apply to the tx_buf
* (used in some of the @fill_options)
* @elapsed_time: elapsed time in nanoseconds
*/
struct spi_test {
......@@ -89,7 +88,7 @@ struct spi_test {
int (*execute_msg)(struct spi_device *spi, struct spi_test *test,
void *tx, void *rx);
int expected_return;
/* iterate over all the non-zero values */
/* iterate over all values, terminated by a -1 */
int iterate_len[SPI_TEST_MAX_ITERATE];
int iterate_tx_align;
int iterate_rx_align;
......@@ -110,6 +109,7 @@ struct spi_test {
#define FILL_TRANSFER_BYTE_32 11 /* fill with the transfer byte - 32 bit */
#define FILL_TRANSFER_NUM 16 /* fill with the transfer number */
u32 fill_pattern;
unsigned long long elapsed_time;
};
/* default implementation for @spi_test.run_test */
......@@ -126,11 +126,12 @@ int spi_test_execute_msg(struct spi_device *spi,
int spi_test_run_tests(struct spi_device *spi,
struct spi_test *tests);
/* some of the default @spi_transfer.len to test */
#define ITERATE_LEN 2, 3, 7, 11, 16, 31, 32, 64, 97, 128, 251, 256, \
#define ITERATE_LEN_LIST 0, 1, 2, 3, 7, 11, 16, 31, 32, 64, 97, 128, 251, 256, \
1021, 1024, 1031, 4093, PAGE_SIZE, 4099, 65536, 65537
#define ITERATE_MAX_LEN ITERATE_LEN, SPI_TEST_MAX_SIZE - 1, SPI_TEST_MAX_SIZE
/* some of the default @spi_transfer.len to test, terminated by a -1 */
#define ITERATE_LEN ITERATE_LEN_LIST, -1
#define ITERATE_MAX_LEN ITERATE_LEN_LIST, (SPI_TEST_MAX_SIZE - 1), \
SPI_TEST_MAX_SIZE, -1
/* the default alignment to test */
#define ITERATE_ALIGN sizeof(int)
......@@ -33,6 +33,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
#include <linux/spi/spi.h>
......@@ -57,6 +58,8 @@ struct ti_qspi {
struct ti_qspi_regs ctx_reg;
dma_addr_t mmap_phys_base;
dma_addr_t rx_bb_dma_addr;
void *rx_bb_addr;
struct dma_chan *rx_chan;
u32 spi_max_frequency;
......@@ -126,6 +129,8 @@ struct ti_qspi {
#define QSPI_SETUP_ADDR_SHIFT 8
#define QSPI_SETUP_DUMMY_SHIFT 10
#define QSPI_DMA_BUFFER_SIZE SZ_64K
static inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
unsigned long reg)
{
......@@ -395,14 +400,12 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst,
dma_addr_t dma_src, size_t len)
{
struct dma_chan *chan = qspi->rx_chan;
struct dma_device *dma_dev = chan->device;
dma_cookie_t cookie;
enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
struct dma_async_tx_descriptor *tx;
int ret;
tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src,
len, flags);
tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags);
if (!tx) {
dev_err(qspi->dev, "device_prep_dma_memcpy error\n");
return -EIO;
......@@ -431,6 +434,35 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst,
return 0;
}
static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi,
struct spi_flash_read_message *msg)
{
size_t readsize = msg->len;
void *to = msg->buf;
dma_addr_t dma_src = qspi->mmap_phys_base + msg->from;
int ret = 0;
/*
* Use bounce buffer as FS like jffs2, ubifs may pass
* buffers that does not belong to kernel lowmem region.
*/
while (readsize != 0) {
size_t xfer_len = min_t(size_t, QSPI_DMA_BUFFER_SIZE,
readsize);
ret = ti_qspi_dma_xfer(qspi, qspi->rx_bb_dma_addr,
dma_src, xfer_len);
if (ret != 0)
return ret;
memcpy(to, qspi->rx_bb_addr, xfer_len);
readsize -= xfer_len;
dma_src += xfer_len;
to += xfer_len;
}
return ret;
}
static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg,
loff_t from)
{
......@@ -498,6 +530,12 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi,
QSPI_SPI_SETUP_REG(spi->chip_select));
}
static bool ti_qspi_spi_flash_can_dma(struct spi_device *spi,
struct spi_flash_read_message *msg)
{
return virt_addr_valid(msg->buf);
}
static int ti_qspi_spi_flash_read(struct spi_device *spi,
struct spi_flash_read_message *msg)
{
......@@ -511,15 +549,12 @@ static int ti_qspi_spi_flash_read(struct spi_device *spi,
ti_qspi_setup_mmap_read(spi, msg);
if (qspi->rx_chan) {
if (msg->cur_msg_mapped) {
if (msg->cur_msg_mapped)
ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from);
if (ret)
goto err_unlock;
} else {
dev_err(qspi->dev, "Invalid address for DMA\n");
ret = -EIO;
else
ret = ti_qspi_dma_bounce_buffer(qspi, msg);
if (ret)
goto err_unlock;
}
} else {
memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len);
}
......@@ -725,6 +760,17 @@ static int ti_qspi_probe(struct platform_device *pdev)
ret = 0;
goto no_dma;
}
qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev,
QSPI_DMA_BUFFER_SIZE,
&qspi->rx_bb_dma_addr,
GFP_KERNEL | GFP_DMA);
if (!qspi->rx_bb_addr) {
dev_err(qspi->dev,
"dma_alloc_coherent failed, using PIO mode\n");
dma_release_channel(qspi->rx_chan);
goto no_dma;
}
master->spi_flash_can_dma = ti_qspi_spi_flash_can_dma;
master->dma_rx = qspi->rx_chan;
init_completion(&qspi->transfer_complete);
if (res_mmap)
......@@ -765,6 +811,10 @@ static int ti_qspi_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (qspi->rx_bb_addr)
dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE,
qspi->rx_bb_addr,
qspi->rx_bb_dma_addr);
if (qspi->rx_chan)
dma_release_channel(qspi->rx_chan);
......
......@@ -442,6 +442,7 @@ static int xlp_spi_probe(struct platform_device *pdev)
#ifdef CONFIG_ACPI
static const struct acpi_device_id xlp_spi_acpi_match[] = {
{ "BRCM900D", 0 },
{ "CAV900D", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match);
......
......@@ -31,6 +31,7 @@
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
#include <linux/property.h>
#include <linux/export.h>
#include <linux/sched/rt.h>
#include <uapi/linux/sched/types.h>
......@@ -600,13 +601,28 @@ struct spi_device *spi_new_device(struct spi_master *master,
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
status = spi_add_device(proxy);
if (status < 0) {
spi_dev_put(proxy);
return NULL;
if (chip->properties) {
status = device_add_properties(&proxy->dev, chip->properties);
if (status) {
dev_err(&master->dev,
"failed to add properties to '%s': %d\n",
chip->modalias, status);
goto err_dev_put;
}
}
status = spi_add_device(proxy);
if (status < 0)
goto err_remove_props;
return proxy;
err_remove_props:
if (chip->properties)
device_remove_properties(&proxy->dev);
err_dev_put:
spi_dev_put(proxy);
return NULL;
}
EXPORT_SYMBOL_GPL(spi_new_device);
......@@ -664,6 +680,7 @@ 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.
* Device properties are deep-copied though.
*
* Return: zero on success, else a negative error code.
*/
......@@ -673,7 +690,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
int i;
if (!n)
return -EINVAL;
return 0;
bi = kcalloc(n, sizeof(*bi), GFP_KERNEL);
if (!bi)
......@@ -683,6 +700,13 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
struct spi_master *master;
memcpy(&bi->board_info, info, sizeof(*info));
if (info->properties) {
bi->board_info.properties =
property_entries_dup(info->properties);
if (IS_ERR(bi->board_info.properties))
return PTR_ERR(bi->board_info.properties);
}
mutex_lock(&board_lock);
list_add_tail(&bi->list, &board_list);
list_for_each_entry(master, &spi_master_list, list)
......@@ -1015,7 +1039,7 @@ static int spi_transfer_one_message(struct spi_master *master,
ret = 0;
ms = 8LL * 1000LL * xfer->len;
do_div(ms, xfer->speed_hz);
ms += ms + 100; /* some tolerance */
ms += ms + 200; /* some tolerance */
if (ms > UINT_MAX)
ms = UINT_MAX;
......@@ -2830,7 +2854,7 @@ int spi_flash_read(struct spi_device *spi,
mutex_lock(&master->bus_lock_mutex);
mutex_lock(&master->io_mutex);
if (master->dma_rx) {
if (master->dma_rx && master->spi_flash_can_dma(spi, msg)) {
rx_dev = master->dma_rx->device->dev;
ret = spi_map_buf(master, rx_dev, &msg->rx_sg,
msg->buf, msg->len,
......
......@@ -697,6 +697,7 @@ static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rohm,dh2228fv" },
{ .compatible = "lineartechnology,ltc2488" },
{ .compatible = "ge,achc" },
{ .compatible = "semtech,sx1301" },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
......
......@@ -23,6 +23,7 @@
#include <linux/scatterlist.h>
struct dma_chan;
struct property_entry;
struct spi_master;
struct spi_transfer;
struct spi_flash_read_message;
......@@ -375,6 +376,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @unprepare_message: undo any work done by prepare_message().
* @spi_flash_read: to support spi-controller hardwares that provide
* accelerated interface to read from flash devices.
* @spi_flash_can_dma: analogous to can_dma() interface, but for
* controllers implementing spi_flash_read.
* @flash_read_supported: spi device supports flash read
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
* number. Any individual value may be -ENOENT for CS lines that
......@@ -538,6 +541,8 @@ struct spi_master {
struct spi_message *message);
int (*spi_flash_read)(struct spi_device *spi,
struct spi_flash_read_message *msg);
bool (*spi_flash_can_dma)(struct spi_device *spi,
struct spi_flash_read_message *msg);
bool (*flash_read_supported)(struct spi_device *spi);
/*
......@@ -891,7 +896,7 @@ static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags
unsigned i;
struct spi_transfer *t = (struct spi_transfer *)(m + 1);
INIT_LIST_HEAD(&m->transfers);
spi_message_init_no_memset(m);
for (i = 0; i < ntrans; i++, t++)
spi_message_add_tail(t, m);
}
......@@ -1209,6 +1214,7 @@ int spi_flash_read(struct spi_device *spi,
* @modalias: Initializes spi_device.modalias; identifies the driver.
* @platform_data: Initializes spi_device.platform_data; the particular
* data stored there is driver-specific.
* @properties: Additional device properties for the device.
* @controller_data: Initializes spi_device.controller_data; some
* controllers need hints about hardware setup, e.g. for DMA.
* @irq: Initializes spi_device.irq; depends on how the board is wired.
......@@ -1241,10 +1247,12 @@ struct spi_board_info {
*
* platform_data goes to spi_device.dev.platform_data,
* controller_data goes to spi_device.controller_data,
* device properties are copied and attached to spi_device,
* irq is copied too
*/
char modalias[SPI_NAME_SIZE];
const void *platform_data;
const struct property_entry *properties;
void *controller_data;
int irq;
......
......@@ -18,6 +18,7 @@
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>
......@@ -40,6 +41,9 @@ static char *output_file;
static uint32_t speed = 500000;
static uint16_t delay;
static int verbose;
static int transfer_size;
static int iterations;
static int interval = 5; /* interval in seconds for showing transfer rate */
uint8_t default_tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
......@@ -156,13 +160,13 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
close(out_fd);
}
if (verbose || !output_file)
if (verbose)
hex_dump(rx, len, 32, "RX");
}
static void print_usage(const char *prog)
{
printf("Usage: %s [-DsbdlHOLC3]\n", prog);
printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog);
puts(" -D --device device to use (default /dev/spidev1.1)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
......@@ -180,7 +184,9 @@ static void print_usage(const char *prog)
" -N --no-cs no chip select\n"
" -R --ready slave pulls low to pause\n"
" -2 --dual dual transfer\n"
" -4 --quad quad transfer\n");
" -4 --quad quad transfer\n"
" -S --size transfer size\n"
" -I --iter iterations\n");
exit(1);
}
......@@ -205,11 +211,13 @@ static void parse_opts(int argc, char *argv[])
{ "dual", 0, 0, '2' },
{ "verbose", 0, 0, 'v' },
{ "quad", 0, 0, '4' },
{ "size", 1, 0, 'S' },
{ "iter", 1, 0, 'I' },
{ NULL, 0, 0, 0 },
};
int c;
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v",
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:vS:I:",
lopts, NULL);
if (c == -1)
......@@ -270,6 +278,12 @@ static void parse_opts(int argc, char *argv[])
case '4':
mode |= SPI_TX_QUAD;
break;
case 'S':
transfer_size = atoi(optarg);
break;
case 'I':
iterations = atoi(optarg);
break;
default:
print_usage(argv[0]);
break;
......@@ -336,6 +350,57 @@ static void transfer_file(int fd, char *filename)
close(tx_fd);
}
static uint64_t _read_count;
static uint64_t _write_count;
static void show_transfer_rate(void)
{
static uint64_t prev_read_count, prev_write_count;
double rx_rate, tx_rate;
rx_rate = ((_read_count - prev_read_count) * 8) / (interval*1000.0);
tx_rate = ((_write_count - prev_write_count) * 8) / (interval*1000.0);
printf("rate: tx %.1fkbps, rx %.1fkbps\n", rx_rate, tx_rate);
prev_read_count = _read_count;
prev_write_count = _write_count;
}
static void transfer_buf(int fd, int len)
{
uint8_t *tx;
uint8_t *rx;
int i;
tx = malloc(len);
if (!tx)
pabort("can't allocate tx buffer");
for (i = 0; i < len; i++)
tx[i] = random();
rx = malloc(len);
if (!rx)
pabort("can't allocate rx buffer");
transfer(fd, tx, rx, len);
_write_count += len;
_read_count += len;
if (mode & SPI_LOOP) {
if (memcmp(tx, rx, len)) {
fprintf(stderr, "transfer error !\n");
hex_dump(tx, len, 32, "TX");
hex_dump(rx, len, 32, "RX");
exit(1);
}
}
free(rx);
free(tx);
}
int main(int argc, char *argv[])
{
int ret = 0;
......@@ -391,7 +456,25 @@ int main(int argc, char *argv[])
transfer_escaped_string(fd, input_tx);
else if (input_file)
transfer_file(fd, input_file);
else
else if (transfer_size) {
struct timespec last_stat;
clock_gettime(CLOCK_MONOTONIC, &last_stat);
while (iterations-- > 0) {
struct timespec current;
transfer_buf(fd, transfer_size);
clock_gettime(CLOCK_MONOTONIC, &current);
if (current.tv_sec - last_stat.tv_sec > interval) {
show_transfer_rate();
last_stat = current;
}
}
printf("total: tx %.1fKB, rx %.1fKB\n",
_write_count/1024.0, _read_count/1024.0);
} else
transfer(fd, default_tx, default_rx, sizeof(default_tx));
close(fd);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册