mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
spi: Updates for v4.12
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).
-----BEGIN PGP SIGNATURE-----
iQFHBAABCAAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAlkJ81ETHGJyb29uaWVA
a2VybmVsLm9yZwAKCRAk1otyXVSH0HQZB/9IO6RQmdIU8A2s0xBaXOI64uE9ajFQ
aPcwtWwpsAyxSHYtDbsPrcVuLTaJm3q+ldNJt7stYTkRG7R5W6bx+oiJOx1VdkbY
QJiUQUYNpAj5H0EIPocTFct8Yq+SfVtEeEwAuEnu/DouTXLPSoxoQ0dua+iyesxL
ZF6T+/zyRyj+zoijHGbYQEDs6jKuZudtMzQAFoJEalr3ywEDyBMUghXbkfk1qJd4
9XD1Vr4wFUYJ/7yPdwzfhG8u8FHmIBob3L2w6MPvNB961lnaQUCxuRKy3cJZrQM8
fn3WJAzrnsA6SOTM+rskWhWh4j0t26XgY/xCsEdiE+XGIh6Sd1RPQuJM
=e4MH
-----END PGP SIGNATURE-----
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
...
This commit is contained in:
commit
d25e436c4b
32 changed files with 964 additions and 410 deletions
|
|
@ -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>;
|
||||
};
|
||||
|
|
|
|||
33
Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt
Normal file
33
Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
Binding for Broadcom BCM6328 High Speed SPI controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must contain of "brcm,bcm6328-hsspi".
|
||||
- reg: Base address and size of the controllers memory area.
|
||||
- interrupts: Interrupt for the SPI block.
|
||||
- clocks: phandles of the SPI clock and the PLL clock.
|
||||
- clock-names: must be "hsspi", "pll".
|
||||
- #address-cells: <1>, as required by generic SPI binding.
|
||||
- #size-cells: <0>, also as required by generic SPI binding.
|
||||
|
||||
Optional properties:
|
||||
- num-cs: some controllers have less than 8 cs signals. Defaults to 8
|
||||
if absent.
|
||||
|
||||
Child nodes as per the generic SPI binding.
|
||||
|
||||
Example:
|
||||
|
||||
spi@10001000 {
|
||||
compatible = "brcm,bcm6328-hsspi";
|
||||
reg = <0x10001000 0x600>;
|
||||
|
||||
interrupts = <29>;
|
||||
|
||||
clocks = <&clkctl 9>, <&hsspi_pll>;
|
||||
clock-names = "hsspi", "pll";
|
||||
|
||||
num-cs = <2>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
33
Documentation/devicetree/bindings/spi/spi-bcm63xx.txt
Normal file
33
Documentation/devicetree/bindings/spi/spi-bcm63xx.txt
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
Binding for Broadcom BCM6348/BCM6358 SPI controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must contain one of "brcm,bcm6348-spi", "brcm,bcm6358-spi".
|
||||
- reg: Base address and size of the controllers memory area.
|
||||
- interrupts: Interrupt for the SPI block.
|
||||
- clocks: phandle of the SPI clock.
|
||||
- clock-names: has to be "spi".
|
||||
- #address-cells: <1>, as required by generic SPI binding.
|
||||
- #size-cells: <0>, also as required by generic SPI binding.
|
||||
|
||||
Optional properties:
|
||||
- num-cs: some controllers have less than 8 cs signals. Defaults to 8
|
||||
if absent.
|
||||
|
||||
Child nodes as per the generic SPI binding.
|
||||
|
||||
Example:
|
||||
|
||||
spi@10000800 {
|
||||
compatible = "brcm,bcm6368-spi", "brcm,bcm6358-spi";
|
||||
reg = <0x10000800 0x70c>;
|
||||
|
||||
interrupts = <1>;
|
||||
|
||||
clocks = <&clkctl 9>;
|
||||
clock-names = "spi";
|
||||
|
||||
num-cs = <5>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
|
@ -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)
|
||||
if (dev->of_node) {
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(bcm63xx_spi_of_match, dev->of_node);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
bcm63xx_spireg = match->data;
|
||||
|
||||
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
|
||||
if (num_cs > BCM63XX_SPI_MAX_CS) {
|
||||
dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
|
||||
num_cs);
|
||||
num_cs = BCM63XX_SPI_MAX_CS;
|
||||
}
|
||||
|
||||
bus_num = -1;
|
||||
} else if (pdev->id_entry->driver_data) {
|
||||
const struct platform_device_id *match = pdev->id_entry;
|
||||
|
||||
bcm63xx_spireg = (const unsigned long *)match->driver_data;
|
||||
bus_num = BCM63XX_SPI_BUS_NUM;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
|
||||
bcm63xx_spireg = (const unsigned long *)pdev->id_entry->driver_data;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
|
|
@ -536,11 +571,14 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
master->bus_num = BCM63XX_SPI_BUS_NUM;
|
||||
master->num_chipselect = BCM63XX_SPI_MAX_CS;
|
||||
master->dev.of_node = dev->of_node;
|
||||
master->bus_num = bus_num;
|
||||
master->num_chipselect = num_cs;
|
||||
master->transfer_one_message = bcm63xx_spi_transfer_one;
|
||||
master->mode_bits = MODEBITS;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||
master->max_transfer_size = bcm63xx_spi_max_length;
|
||||
master->max_message_size = bcm63xx_spi_max_length;
|
||||
master->auto_runtime_pm = true;
|
||||
bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT];
|
||||
bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH];
|
||||
|
|
@ -624,6 +662,7 @@ static struct platform_driver bcm63xx_spi_driver = {
|
|||
.driver = {
|
||||
.name = "bcm63xx-spi",
|
||||
.pm = &bcm63xx_spi_pm_ops,
|
||||
.of_match_table = bcm63xx_spi_of_match,
|
||||
},
|
||||
.id_table = bcm63xx_spi_dev_match,
|
||||
.probe = bcm63xx_spi_probe,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,136 +26,140 @@
|
|||
#include <lantiq_soc.h>
|
||||
#endif
|
||||
|
||||
#define SPI_RX_IRQ_NAME "spi_rx"
|
||||
#define SPI_TX_IRQ_NAME "spi_tx"
|
||||
#define SPI_ERR_IRQ_NAME "spi_err"
|
||||
#define SPI_FRM_IRQ_NAME "spi_frm"
|
||||
#define LTQ_SPI_RX_IRQ_NAME "spi_rx"
|
||||
#define LTQ_SPI_TX_IRQ_NAME "spi_tx"
|
||||
#define LTQ_SPI_ERR_IRQ_NAME "spi_err"
|
||||
#define LTQ_SPI_FRM_IRQ_NAME "spi_frm"
|
||||
|
||||
#define SPI_CLC 0x00
|
||||
#define SPI_PISEL 0x04
|
||||
#define SPI_ID 0x08
|
||||
#define SPI_CON 0x10
|
||||
#define SPI_STAT 0x14
|
||||
#define SPI_WHBSTATE 0x18
|
||||
#define SPI_TB 0x20
|
||||
#define SPI_RB 0x24
|
||||
#define SPI_RXFCON 0x30
|
||||
#define SPI_TXFCON 0x34
|
||||
#define SPI_FSTAT 0x38
|
||||
#define SPI_BRT 0x40
|
||||
#define SPI_BRSTAT 0x44
|
||||
#define SPI_SFCON 0x60
|
||||
#define SPI_SFSTAT 0x64
|
||||
#define SPI_GPOCON 0x70
|
||||
#define SPI_GPOSTAT 0x74
|
||||
#define SPI_FPGO 0x78
|
||||
#define SPI_RXREQ 0x80
|
||||
#define SPI_RXCNT 0x84
|
||||
#define SPI_DMACON 0xec
|
||||
#define SPI_IRNEN 0xf4
|
||||
#define SPI_IRNICR 0xf8
|
||||
#define SPI_IRNCR 0xfc
|
||||
#define LTQ_SPI_CLC 0x00
|
||||
#define LTQ_SPI_PISEL 0x04
|
||||
#define LTQ_SPI_ID 0x08
|
||||
#define LTQ_SPI_CON 0x10
|
||||
#define LTQ_SPI_STAT 0x14
|
||||
#define LTQ_SPI_WHBSTATE 0x18
|
||||
#define LTQ_SPI_TB 0x20
|
||||
#define LTQ_SPI_RB 0x24
|
||||
#define LTQ_SPI_RXFCON 0x30
|
||||
#define LTQ_SPI_TXFCON 0x34
|
||||
#define LTQ_SPI_FSTAT 0x38
|
||||
#define LTQ_SPI_BRT 0x40
|
||||
#define LTQ_SPI_BRSTAT 0x44
|
||||
#define LTQ_SPI_SFCON 0x60
|
||||
#define LTQ_SPI_SFSTAT 0x64
|
||||
#define LTQ_SPI_GPOCON 0x70
|
||||
#define LTQ_SPI_GPOSTAT 0x74
|
||||
#define LTQ_SPI_FPGO 0x78
|
||||
#define LTQ_SPI_RXREQ 0x80
|
||||
#define LTQ_SPI_RXCNT 0x84
|
||||
#define LTQ_SPI_DMACON 0xec
|
||||
#define LTQ_SPI_IRNEN 0xf4
|
||||
#define LTQ_SPI_IRNICR 0xf8
|
||||
#define LTQ_SPI_IRNCR 0xfc
|
||||
|
||||
#define SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */
|
||||
#define SPI_CLC_SMC_M (0xFF << SPI_CLC_SMC_S)
|
||||
#define SPI_CLC_RMC_S 8 /* Clock divider for normal run mode */
|
||||
#define SPI_CLC_RMC_M (0xFF << SPI_CLC_RMC_S)
|
||||
#define SPI_CLC_DISS BIT(1) /* Disable status bit */
|
||||
#define SPI_CLC_DISR BIT(0) /* Disable request bit */
|
||||
#define LTQ_SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */
|
||||
#define LTQ_SPI_CLC_SMC_M (0xFF << LTQ_SPI_CLC_SMC_S)
|
||||
#define LTQ_SPI_CLC_RMC_S 8 /* Clock divider for normal run mode */
|
||||
#define LTQ_SPI_CLC_RMC_M (0xFF << LTQ_SPI_CLC_RMC_S)
|
||||
#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */
|
||||
#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */
|
||||
|
||||
#define SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */
|
||||
#define SPI_ID_TXFS_M (0x3F << SPI_ID_TXFS_S)
|
||||
#define SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */
|
||||
#define SPI_ID_RXFS_M (0x3F << SPI_ID_RXFS_S)
|
||||
#define SPI_ID_MOD_S 8 /* Module ID */
|
||||
#define SPI_ID_MOD_M (0xff << SPI_ID_MOD_S)
|
||||
#define SPI_ID_CFG_S 5 /* DMA interface support */
|
||||
#define SPI_ID_CFG_M (1 << SPI_ID_CFG_S)
|
||||
#define SPI_ID_REV_M 0x1F /* Hardware revision number */
|
||||
#define LTQ_SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */
|
||||
#define LTQ_SPI_ID_TXFS_M (0x3F << LTQ_SPI_ID_TXFS_S)
|
||||
#define LTQ_SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */
|
||||
#define LTQ_SPI_ID_RXFS_M (0x3F << LTQ_SPI_ID_RXFS_S)
|
||||
#define LTQ_SPI_ID_MOD_S 8 /* Module ID */
|
||||
#define LTQ_SPI_ID_MOD_M (0xff << LTQ_SPI_ID_MOD_S)
|
||||
#define LTQ_SPI_ID_CFG_S 5 /* DMA interface support */
|
||||
#define LTQ_SPI_ID_CFG_M (1 << LTQ_SPI_ID_CFG_S)
|
||||
#define LTQ_SPI_ID_REV_M 0x1F /* Hardware revision number */
|
||||
|
||||
#define SPI_CON_BM_S 16 /* Data width selection */
|
||||
#define SPI_CON_BM_M (0x1F << SPI_CON_BM_S)
|
||||
#define SPI_CON_EM BIT(24) /* Echo mode */
|
||||
#define SPI_CON_IDLE BIT(23) /* Idle bit value */
|
||||
#define SPI_CON_ENBV BIT(22) /* Enable byte valid control */
|
||||
#define SPI_CON_RUEN BIT(12) /* Receive underflow error enable */
|
||||
#define SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */
|
||||
#define SPI_CON_AEN BIT(10) /* Abort error enable */
|
||||
#define SPI_CON_REN BIT(9) /* Receive overflow error enable */
|
||||
#define SPI_CON_TEN BIT(8) /* Transmit overflow error enable */
|
||||
#define SPI_CON_LB BIT(7) /* Loopback control */
|
||||
#define SPI_CON_PO BIT(6) /* Clock polarity control */
|
||||
#define SPI_CON_PH BIT(5) /* Clock phase control */
|
||||
#define SPI_CON_HB BIT(4) /* Heading control */
|
||||
#define SPI_CON_RXOFF BIT(1) /* Switch receiver off */
|
||||
#define SPI_CON_TXOFF BIT(0) /* Switch transmitter off */
|
||||
#define LTQ_SPI_CON_BM_S 16 /* Data width selection */
|
||||
#define LTQ_SPI_CON_BM_M (0x1F << LTQ_SPI_CON_BM_S)
|
||||
#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */
|
||||
#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */
|
||||
#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */
|
||||
#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */
|
||||
#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */
|
||||
#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */
|
||||
#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */
|
||||
#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */
|
||||
#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */
|
||||
#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */
|
||||
#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */
|
||||
#define LTQ_SPI_CON_HB BIT(4) /* Heading control */
|
||||
#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */
|
||||
#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */
|
||||
|
||||
#define SPI_STAT_RXBV_S 28
|
||||
#define SPI_STAT_RXBV_M (0x7 << SPI_STAT_RXBV_S)
|
||||
#define SPI_STAT_BSY BIT(13) /* Busy flag */
|
||||
#define SPI_STAT_RUE BIT(12) /* Receive underflow error flag */
|
||||
#define SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */
|
||||
#define SPI_STAT_AE BIT(10) /* Abort error flag */
|
||||
#define SPI_STAT_RE BIT(9) /* Receive error flag */
|
||||
#define SPI_STAT_TE BIT(8) /* Transmit error flag */
|
||||
#define SPI_STAT_ME BIT(7) /* Mode error flag */
|
||||
#define SPI_STAT_MS BIT(1) /* Master/slave select bit */
|
||||
#define SPI_STAT_EN BIT(0) /* Enable bit */
|
||||
#define SPI_STAT_ERRORS (SPI_STAT_ME | SPI_STAT_TE | SPI_STAT_RE | \
|
||||
SPI_STAT_AE | SPI_STAT_TUE | SPI_STAT_RUE)
|
||||
#define LTQ_SPI_STAT_RXBV_S 28
|
||||
#define LTQ_SPI_STAT_RXBV_M (0x7 << LTQ_SPI_STAT_RXBV_S)
|
||||
#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */
|
||||
#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */
|
||||
#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */
|
||||
#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */
|
||||
#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */
|
||||
#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */
|
||||
#define LTQ_SPI_STAT_ME BIT(7) /* Mode error flag */
|
||||
#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */
|
||||
#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */
|
||||
#define LTQ_SPI_STAT_ERRORS (LTQ_SPI_STAT_ME | LTQ_SPI_STAT_TE | \
|
||||
LTQ_SPI_STAT_RE | LTQ_SPI_STAT_AE | \
|
||||
LTQ_SPI_STAT_TUE | LTQ_SPI_STAT_RUE)
|
||||
|
||||
#define SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */
|
||||
#define SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */
|
||||
#define SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */
|
||||
#define SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */
|
||||
#define SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */
|
||||
#define SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */
|
||||
#define SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */
|
||||
#define SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */
|
||||
#define SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */
|
||||
#define SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */
|
||||
#define SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */
|
||||
#define SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */
|
||||
#define SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */
|
||||
#define SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */
|
||||
#define SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */
|
||||
#define SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */
|
||||
#define SPI_WHBSTATE_CLR_ERRORS (SPI_WHBSTATE_CLRRUE | SPI_WHBSTATE_CLRME | \
|
||||
SPI_WHBSTATE_CLRTE | SPI_WHBSTATE_CLRRE | \
|
||||
SPI_WHBSTATE_CLRAE | SPI_WHBSTATE_CLRTUE)
|
||||
#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */
|
||||
#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */
|
||||
#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */
|
||||
#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */
|
||||
#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */
|
||||
#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */
|
||||
#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */
|
||||
#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */
|
||||
#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */
|
||||
#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */
|
||||
#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */
|
||||
#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */
|
||||
#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */
|
||||
#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */
|
||||
#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */
|
||||
#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */
|
||||
#define LTQ_SPI_WHBSTATE_CLR_ERRORS (LTQ_SPI_WHBSTATE_CLRRUE | \
|
||||
LTQ_SPI_WHBSTATE_CLRME | \
|
||||
LTQ_SPI_WHBSTATE_CLRTE | \
|
||||
LTQ_SPI_WHBSTATE_CLRRE | \
|
||||
LTQ_SPI_WHBSTATE_CLRAE | \
|
||||
LTQ_SPI_WHBSTATE_CLRTUE)
|
||||
|
||||
#define SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */
|
||||
#define SPI_RXFCON_RXFITL_M (0x3F << SPI_RXFCON_RXFITL_S)
|
||||
#define SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */
|
||||
#define SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */
|
||||
#define LTQ_SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */
|
||||
#define LTQ_SPI_RXFCON_RXFITL_M (0x3F << LTQ_SPI_RXFCON_RXFITL_S)
|
||||
#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */
|
||||
#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */
|
||||
|
||||
#define SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */
|
||||
#define SPI_TXFCON_TXFITL_M (0x3F << SPI_TXFCON_TXFITL_S)
|
||||
#define SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */
|
||||
#define SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */
|
||||
#define LTQ_SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */
|
||||
#define LTQ_SPI_TXFCON_TXFITL_M (0x3F << LTQ_SPI_TXFCON_TXFITL_S)
|
||||
#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */
|
||||
#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */
|
||||
|
||||
#define SPI_FSTAT_RXFFL_S 0
|
||||
#define SPI_FSTAT_RXFFL_M (0x3f << SPI_FSTAT_RXFFL_S)
|
||||
#define SPI_FSTAT_TXFFL_S 8
|
||||
#define SPI_FSTAT_TXFFL_M (0x3f << SPI_FSTAT_TXFFL_S)
|
||||
#define LTQ_SPI_FSTAT_RXFFL_S 0
|
||||
#define LTQ_SPI_FSTAT_RXFFL_M (0x3f << LTQ_SPI_FSTAT_RXFFL_S)
|
||||
#define LTQ_SPI_FSTAT_TXFFL_S 8
|
||||
#define LTQ_SPI_FSTAT_TXFFL_M (0x3f << LTQ_SPI_FSTAT_TXFFL_S)
|
||||
|
||||
#define SPI_GPOCON_ISCSBN_S 8
|
||||
#define SPI_GPOCON_INVOUTN_S 0
|
||||
#define LTQ_SPI_GPOCON_ISCSBN_S 8
|
||||
#define LTQ_SPI_GPOCON_INVOUTN_S 0
|
||||
|
||||
#define SPI_FGPO_SETOUTN_S 8
|
||||
#define SPI_FGPO_CLROUTN_S 0
|
||||
#define LTQ_SPI_FGPO_SETOUTN_S 8
|
||||
#define LTQ_SPI_FGPO_CLROUTN_S 0
|
||||
|
||||
#define SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */
|
||||
#define SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */
|
||||
#define LTQ_SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */
|
||||
#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */
|
||||
|
||||
#define SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */
|
||||
#define SPI_IRNEN_F BIT(3) /* Frame end interrupt request */
|
||||
#define SPI_IRNEN_E BIT(2) /* Error end interrupt request */
|
||||
#define SPI_IRNEN_T_XWAY BIT(1) /* Transmit end interrupt request */
|
||||
#define SPI_IRNEN_R_XWAY BIT(0) /* Receive end interrupt request */
|
||||
#define SPI_IRNEN_R_XRX BIT(1) /* Transmit end interrupt request */
|
||||
#define SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */
|
||||
#define SPI_IRNEN_ALL 0x1F
|
||||
#define LTQ_SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */
|
||||
#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */
|
||||
#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */
|
||||
#define LTQ_SPI_IRNEN_T_XWAY BIT(1) /* Transmit end interrupt request */
|
||||
#define LTQ_SPI_IRNEN_R_XWAY BIT(0) /* Receive end interrupt request */
|
||||
#define LTQ_SPI_IRNEN_R_XRX BIT(1) /* Transmit end interrupt request */
|
||||
#define LTQ_SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */
|
||||
#define LTQ_SPI_IRNEN_ALL 0x1F
|
||||
|
||||
struct lantiq_ssc_hwcfg {
|
||||
unsigned int irnen_r;
|
||||
|
|
@ -208,16 +212,16 @@ static void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr,
|
|||
|
||||
static unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi)
|
||||
{
|
||||
u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT);
|
||||
u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT);
|
||||
|
||||
return (fstat & SPI_FSTAT_TXFFL_M) >> SPI_FSTAT_TXFFL_S;
|
||||
return (fstat & LTQ_SPI_FSTAT_TXFFL_M) >> LTQ_SPI_FSTAT_TXFFL_S;
|
||||
}
|
||||
|
||||
static unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi)
|
||||
{
|
||||
u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT);
|
||||
u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT);
|
||||
|
||||
return fstat & SPI_FSTAT_RXFFL_M;
|
||||
return fstat & LTQ_SPI_FSTAT_RXFFL_M;
|
||||
}
|
||||
|
||||
static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi)
|
||||
|
|
@ -227,38 +231,38 @@ static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi)
|
|||
|
||||
static void rx_fifo_reset(const struct lantiq_ssc_spi *spi)
|
||||
{
|
||||
u32 val = spi->rx_fifo_size << SPI_RXFCON_RXFITL_S;
|
||||
u32 val = spi->rx_fifo_size << LTQ_SPI_RXFCON_RXFITL_S;
|
||||
|
||||
val |= SPI_RXFCON_RXFEN | SPI_RXFCON_RXFLU;
|
||||
lantiq_ssc_writel(spi, val, SPI_RXFCON);
|
||||
val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU;
|
||||
lantiq_ssc_writel(spi, val, LTQ_SPI_RXFCON);
|
||||
}
|
||||
|
||||
static void tx_fifo_reset(const struct lantiq_ssc_spi *spi)
|
||||
{
|
||||
u32 val = 1 << SPI_TXFCON_TXFITL_S;
|
||||
u32 val = 1 << LTQ_SPI_TXFCON_TXFITL_S;
|
||||
|
||||
val |= SPI_TXFCON_TXFEN | SPI_TXFCON_TXFLU;
|
||||
lantiq_ssc_writel(spi, val, SPI_TXFCON);
|
||||
val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU;
|
||||
lantiq_ssc_writel(spi, val, LTQ_SPI_TXFCON);
|
||||
}
|
||||
|
||||
static void rx_fifo_flush(const struct lantiq_ssc_spi *spi)
|
||||
{
|
||||
lantiq_ssc_maskl(spi, 0, SPI_RXFCON_RXFLU, SPI_RXFCON);
|
||||
lantiq_ssc_maskl(spi, 0, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON);
|
||||
}
|
||||
|
||||
static void tx_fifo_flush(const struct lantiq_ssc_spi *spi)
|
||||
{
|
||||
lantiq_ssc_maskl(spi, 0, SPI_TXFCON_TXFLU, SPI_TXFCON);
|
||||
lantiq_ssc_maskl(spi, 0, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON);
|
||||
}
|
||||
|
||||
static void hw_enter_config_mode(const struct lantiq_ssc_spi *spi)
|
||||
{
|
||||
lantiq_ssc_writel(spi, SPI_WHBSTATE_CLREN, SPI_WHBSTATE);
|
||||
lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE);
|
||||
}
|
||||
|
||||
static void hw_enter_active_mode(const struct lantiq_ssc_spi *spi)
|
||||
{
|
||||
lantiq_ssc_writel(spi, SPI_WHBSTATE_SETEN, SPI_WHBSTATE);
|
||||
lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE);
|
||||
}
|
||||
|
||||
static void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi,
|
||||
|
|
@ -287,7 +291,7 @@ static void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi,
|
|||
dev_dbg(spi->dev, "spi_clk %u, max_speed_hz %u, brt %u\n",
|
||||
spi_clk, max_speed_hz, brt);
|
||||
|
||||
lantiq_ssc_writel(spi, brt, SPI_BRT);
|
||||
lantiq_ssc_writel(spi, brt, LTQ_SPI_BRT);
|
||||
}
|
||||
|
||||
static void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi,
|
||||
|
|
@ -296,9 +300,9 @@ static void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi,
|
|||
u32 bm;
|
||||
|
||||
/* CON.BM value = bits_per_word - 1 */
|
||||
bm = (bits_per_word - 1) << SPI_CON_BM_S;
|
||||
bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_S;
|
||||
|
||||
lantiq_ssc_maskl(spi, SPI_CON_BM_M, bm, SPI_CON);
|
||||
lantiq_ssc_maskl(spi, LTQ_SPI_CON_BM_M, bm, LTQ_SPI_CON);
|
||||
}
|
||||
|
||||
static void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi,
|
||||
|
|
@ -315,28 +319,28 @@ static void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi,
|
|||
* 3 1 1 1 0
|
||||
*/
|
||||
if (mode & SPI_CPHA)
|
||||
con_clr |= SPI_CON_PH;
|
||||
con_clr |= LTQ_SPI_CON_PH;
|
||||
else
|
||||
con_set |= SPI_CON_PH;
|
||||
con_set |= LTQ_SPI_CON_PH;
|
||||
|
||||
if (mode & SPI_CPOL)
|
||||
con_set |= SPI_CON_PO | SPI_CON_IDLE;
|
||||
con_set |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
|
||||
else
|
||||
con_clr |= SPI_CON_PO | SPI_CON_IDLE;
|
||||
con_clr |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
|
||||
|
||||
/* Set heading control */
|
||||
if (mode & SPI_LSB_FIRST)
|
||||
con_clr |= SPI_CON_HB;
|
||||
con_clr |= LTQ_SPI_CON_HB;
|
||||
else
|
||||
con_set |= SPI_CON_HB;
|
||||
con_set |= LTQ_SPI_CON_HB;
|
||||
|
||||
/* Set loopback mode */
|
||||
if (mode & SPI_LOOP)
|
||||
con_set |= SPI_CON_LB;
|
||||
con_set |= LTQ_SPI_CON_LB;
|
||||
else
|
||||
con_clr |= SPI_CON_LB;
|
||||
con_clr |= LTQ_SPI_CON_LB;
|
||||
|
||||
lantiq_ssc_maskl(spi, con_clr, con_set, SPI_CON);
|
||||
lantiq_ssc_maskl(spi, con_clr, con_set, LTQ_SPI_CON);
|
||||
}
|
||||
|
||||
static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
|
||||
|
|
@ -347,37 +351,39 @@ static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
|
|||
* Set clock divider for run mode to 1 to
|
||||
* run at same frequency as FPI bus
|
||||
*/
|
||||
lantiq_ssc_writel(spi, 1 << SPI_CLC_RMC_S, SPI_CLC);
|
||||
lantiq_ssc_writel(spi, 1 << LTQ_SPI_CLC_RMC_S, LTQ_SPI_CLC);
|
||||
|
||||
/* Put controller into config mode */
|
||||
hw_enter_config_mode(spi);
|
||||
|
||||
/* Clear error flags */
|
||||
lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE);
|
||||
lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
|
||||
|
||||
/* Enable error checking, disable TX/RX */
|
||||
lantiq_ssc_writel(spi, SPI_CON_RUEN | SPI_CON_AEN | SPI_CON_TEN |
|
||||
SPI_CON_REN | SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON);
|
||||
lantiq_ssc_writel(spi, LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN |
|
||||
LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | LTQ_SPI_CON_TXOFF |
|
||||
LTQ_SPI_CON_RXOFF, LTQ_SPI_CON);
|
||||
|
||||
/* Setup default SPI mode */
|
||||
hw_setup_bits_per_word(spi, spi->bits_per_word);
|
||||
hw_setup_clock_mode(spi, SPI_MODE_0);
|
||||
|
||||
/* Enable master mode and clear error flags */
|
||||
lantiq_ssc_writel(spi, SPI_WHBSTATE_SETMS | SPI_WHBSTATE_CLR_ERRORS,
|
||||
SPI_WHBSTATE);
|
||||
lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETMS |
|
||||
LTQ_SPI_WHBSTATE_CLR_ERRORS,
|
||||
LTQ_SPI_WHBSTATE);
|
||||
|
||||
/* Reset GPIO/CS registers */
|
||||
lantiq_ssc_writel(spi, 0, SPI_GPOCON);
|
||||
lantiq_ssc_writel(spi, 0xFF00, SPI_FPGO);
|
||||
lantiq_ssc_writel(spi, 0, LTQ_SPI_GPOCON);
|
||||
lantiq_ssc_writel(spi, 0xFF00, LTQ_SPI_FPGO);
|
||||
|
||||
/* Enable and flush FIFOs */
|
||||
rx_fifo_reset(spi);
|
||||
tx_fifo_reset(spi);
|
||||
|
||||
/* Enable interrupts */
|
||||
lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r | SPI_IRNEN_E,
|
||||
SPI_IRNEN);
|
||||
lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r |
|
||||
LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN);
|
||||
}
|
||||
|
||||
static int lantiq_ssc_setup(struct spi_device *spidev)
|
||||
|
|
@ -400,13 +406,13 @@ static int lantiq_ssc_setup(struct spi_device *spidev)
|
|||
}
|
||||
|
||||
/* set GPO pin to CS mode */
|
||||
gpocon = 1 << ((cs - spi->base_cs) + SPI_GPOCON_ISCSBN_S);
|
||||
gpocon = 1 << ((cs - spi->base_cs) + LTQ_SPI_GPOCON_ISCSBN_S);
|
||||
|
||||
/* invert GPO pin */
|
||||
if (spidev->mode & SPI_CS_HIGH)
|
||||
gpocon |= 1 << (cs - spi->base_cs);
|
||||
|
||||
lantiq_ssc_maskl(spi, 0, gpocon, SPI_GPOCON);
|
||||
lantiq_ssc_maskl(spi, 0, gpocon, LTQ_SPI_GPOCON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -442,18 +448,18 @@ static void hw_setup_transfer(struct lantiq_ssc_spi *spi,
|
|||
}
|
||||
|
||||
/* Configure transmitter and receiver */
|
||||
con = lantiq_ssc_readl(spi, SPI_CON);
|
||||
con = lantiq_ssc_readl(spi, LTQ_SPI_CON);
|
||||
if (t->tx_buf)
|
||||
con &= ~SPI_CON_TXOFF;
|
||||
con &= ~LTQ_SPI_CON_TXOFF;
|
||||
else
|
||||
con |= SPI_CON_TXOFF;
|
||||
con |= LTQ_SPI_CON_TXOFF;
|
||||
|
||||
if (t->rx_buf)
|
||||
con &= ~SPI_CON_RXOFF;
|
||||
con &= ~LTQ_SPI_CON_RXOFF;
|
||||
else
|
||||
con |= SPI_CON_RXOFF;
|
||||
con |= LTQ_SPI_CON_RXOFF;
|
||||
|
||||
lantiq_ssc_writel(spi, con, SPI_CON);
|
||||
lantiq_ssc_writel(spi, con, LTQ_SPI_CON);
|
||||
}
|
||||
|
||||
static int lantiq_ssc_unprepare_message(struct spi_master *master,
|
||||
|
|
@ -464,7 +470,8 @@ static int lantiq_ssc_unprepare_message(struct spi_master *master,
|
|||
flush_workqueue(spi->wq);
|
||||
|
||||
/* Disable transmitter and receiver while idle */
|
||||
lantiq_ssc_maskl(spi, 0, SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON);
|
||||
lantiq_ssc_maskl(spi, 0, LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF,
|
||||
LTQ_SPI_CON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -503,7 +510,7 @@ static void tx_fifo_write(struct lantiq_ssc_spi *spi)
|
|||
break;
|
||||
}
|
||||
|
||||
lantiq_ssc_writel(spi, data, SPI_TB);
|
||||
lantiq_ssc_writel(spi, data, LTQ_SPI_TB);
|
||||
tx_free--;
|
||||
}
|
||||
}
|
||||
|
|
@ -517,7 +524,7 @@ static void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi)
|
|||
unsigned int rx_fill = rx_fifo_level(spi);
|
||||
|
||||
while (rx_fill) {
|
||||
data = lantiq_ssc_readl(spi, SPI_RB);
|
||||
data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
|
||||
|
||||
switch (spi->bits_per_word) {
|
||||
case 2 ... 8:
|
||||
|
|
@ -563,9 +570,9 @@ static void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi)
|
|||
*/
|
||||
while (rx_fill) {
|
||||
if (spi->rx_todo < 4) {
|
||||
rxbv = (lantiq_ssc_readl(spi, SPI_STAT) &
|
||||
SPI_STAT_RXBV_M) >> SPI_STAT_RXBV_S;
|
||||
data = lantiq_ssc_readl(spi, SPI_RB);
|
||||
rxbv = (lantiq_ssc_readl(spi, LTQ_SPI_STAT) &
|
||||
LTQ_SPI_STAT_RXBV_M) >> LTQ_SPI_STAT_RXBV_S;
|
||||
data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
|
||||
|
||||
shift = (rxbv - 1) * 8;
|
||||
rx8 = spi->rx;
|
||||
|
|
@ -578,7 +585,7 @@ static void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi)
|
|||
spi->rx++;
|
||||
}
|
||||
} else {
|
||||
data = lantiq_ssc_readl(spi, SPI_RB);
|
||||
data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
|
||||
rx32 = (u32 *) spi->rx;
|
||||
|
||||
*rx32++ = data;
|
||||
|
|
@ -603,7 +610,7 @@ static void rx_request(struct lantiq_ssc_spi *spi)
|
|||
if (rxreq > rxreq_max)
|
||||
rxreq = rxreq_max;
|
||||
|
||||
lantiq_ssc_writel(spi, rxreq, SPI_RXREQ);
|
||||
lantiq_ssc_writel(spi, rxreq, LTQ_SPI_RXREQ);
|
||||
}
|
||||
|
||||
static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data)
|
||||
|
|
@ -642,26 +649,26 @@ completed:
|
|||
static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data)
|
||||
{
|
||||
struct lantiq_ssc_spi *spi = data;
|
||||
u32 stat = lantiq_ssc_readl(spi, SPI_STAT);
|
||||
u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
|
||||
|
||||
if (!(stat & SPI_STAT_ERRORS))
|
||||
if (!(stat & LTQ_SPI_STAT_ERRORS))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (stat & SPI_STAT_RUE)
|
||||
if (stat & LTQ_SPI_STAT_RUE)
|
||||
dev_err(spi->dev, "receive underflow error\n");
|
||||
if (stat & SPI_STAT_TUE)
|
||||
if (stat & LTQ_SPI_STAT_TUE)
|
||||
dev_err(spi->dev, "transmit underflow error\n");
|
||||
if (stat & SPI_STAT_AE)
|
||||
if (stat & LTQ_SPI_STAT_AE)
|
||||
dev_err(spi->dev, "abort error\n");
|
||||
if (stat & SPI_STAT_RE)
|
||||
if (stat & LTQ_SPI_STAT_RE)
|
||||
dev_err(spi->dev, "receive overflow error\n");
|
||||
if (stat & SPI_STAT_TE)
|
||||
if (stat & LTQ_SPI_STAT_TE)
|
||||
dev_err(spi->dev, "transmit overflow error\n");
|
||||
if (stat & SPI_STAT_ME)
|
||||
if (stat & LTQ_SPI_STAT_ME)
|
||||
dev_err(spi->dev, "mode error\n");
|
||||
|
||||
/* Clear error flags */
|
||||
lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE);
|
||||
lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
|
||||
|
||||
/* set bad status so it can be retried */
|
||||
if (spi->master->cur_msg)
|
||||
|
|
@ -721,9 +728,9 @@ static void lantiq_ssc_bussy_work(struct work_struct *work)
|
|||
|
||||
end = jiffies + msecs_to_jiffies(timeout);
|
||||
do {
|
||||
u32 stat = lantiq_ssc_readl(spi, SPI_STAT);
|
||||
u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
|
||||
|
||||
if (!(stat & SPI_STAT_BSY)) {
|
||||
if (!(stat & LTQ_SPI_STAT_BSY)) {
|
||||
spi_finalize_current_transfer(spi->master);
|
||||
return;
|
||||
}
|
||||
|
|
@ -755,9 +762,9 @@ static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable)
|
|||
if (!!(spidev->mode & SPI_CS_HIGH) == enable)
|
||||
fgpo = (1 << (cs - spi->base_cs));
|
||||
else
|
||||
fgpo = (1 << (cs - spi->base_cs + SPI_FGPO_SETOUTN_S));
|
||||
fgpo = (1 << (cs - spi->base_cs + LTQ_SPI_FGPO_SETOUTN_S));
|
||||
|
||||
lantiq_ssc_writel(spi, fgpo, SPI_FPGO);
|
||||
lantiq_ssc_writel(spi, fgpo, LTQ_SPI_FPGO);
|
||||
}
|
||||
|
||||
static int lantiq_ssc_transfer_one(struct spi_master *master,
|
||||
|
|
@ -772,13 +779,13 @@ static int lantiq_ssc_transfer_one(struct spi_master *master,
|
|||
}
|
||||
|
||||
static const struct lantiq_ssc_hwcfg lantiq_ssc_xway = {
|
||||
.irnen_r = SPI_IRNEN_R_XWAY,
|
||||
.irnen_t = SPI_IRNEN_T_XWAY,
|
||||
.irnen_r = LTQ_SPI_IRNEN_R_XWAY,
|
||||
.irnen_t = LTQ_SPI_IRNEN_T_XWAY,
|
||||
};
|
||||
|
||||
static const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = {
|
||||
.irnen_r = SPI_IRNEN_R_XRX,
|
||||
.irnen_t = SPI_IRNEN_T_XRX,
|
||||
.irnen_r = LTQ_SPI_IRNEN_R_XRX,
|
||||
.irnen_t = LTQ_SPI_IRNEN_T_XRX,
|
||||
};
|
||||
|
||||
static const struct of_device_id lantiq_ssc_match[] = {
|
||||
|
|
@ -814,21 +821,21 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
rx_irq = platform_get_irq_byname(pdev, SPI_RX_IRQ_NAME);
|
||||
rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
|
||||
if (rx_irq < 0) {
|
||||
dev_err(dev, "failed to get %s\n", SPI_RX_IRQ_NAME);
|
||||
dev_err(dev, "failed to get %s\n", LTQ_SPI_RX_IRQ_NAME);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
tx_irq = platform_get_irq_byname(pdev, SPI_TX_IRQ_NAME);
|
||||
tx_irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME);
|
||||
if (tx_irq < 0) {
|
||||
dev_err(dev, "failed to get %s\n", SPI_TX_IRQ_NAME);
|
||||
dev_err(dev, "failed to get %s\n", LTQ_SPI_TX_IRQ_NAME);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
err_irq = platform_get_irq_byname(pdev, SPI_ERR_IRQ_NAME);
|
||||
err_irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME);
|
||||
if (err_irq < 0) {
|
||||
dev_err(dev, "failed to get %s\n", SPI_ERR_IRQ_NAME);
|
||||
dev_err(dev, "failed to get %s\n", LTQ_SPI_ERR_IRQ_NAME);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
|
|
@ -849,17 +856,17 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
err = devm_request_irq(dev, rx_irq, lantiq_ssc_xmit_interrupt,
|
||||
0, SPI_RX_IRQ_NAME, spi);
|
||||
0, LTQ_SPI_RX_IRQ_NAME, spi);
|
||||
if (err)
|
||||
goto err_master_put;
|
||||
|
||||
err = devm_request_irq(dev, tx_irq, lantiq_ssc_xmit_interrupt,
|
||||
0, SPI_TX_IRQ_NAME, spi);
|
||||
0, LTQ_SPI_TX_IRQ_NAME, spi);
|
||||
if (err)
|
||||
goto err_master_put;
|
||||
|
||||
err = devm_request_irq(dev, err_irq, lantiq_ssc_err_interrupt,
|
||||
0, SPI_ERR_IRQ_NAME, spi);
|
||||
0, LTQ_SPI_ERR_IRQ_NAME, spi);
|
||||
if (err)
|
||||
goto err_master_put;
|
||||
|
||||
|
|
@ -916,11 +923,11 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
|||
}
|
||||
INIT_WORK(&spi->work, lantiq_ssc_bussy_work);
|
||||
|
||||
id = lantiq_ssc_readl(spi, SPI_ID);
|
||||
spi->tx_fifo_size = (id & SPI_ID_TXFS_M) >> SPI_ID_TXFS_S;
|
||||
spi->rx_fifo_size = (id & SPI_ID_RXFS_M) >> SPI_ID_RXFS_S;
|
||||
supports_dma = (id & SPI_ID_CFG_M) >> SPI_ID_CFG_S;
|
||||
revision = id & SPI_ID_REV_M;
|
||||
id = lantiq_ssc_readl(spi, LTQ_SPI_ID);
|
||||
spi->tx_fifo_size = (id & LTQ_SPI_ID_TXFS_M) >> LTQ_SPI_ID_TXFS_S;
|
||||
spi->rx_fifo_size = (id & LTQ_SPI_ID_RXFS_M) >> LTQ_SPI_ID_RXFS_S;
|
||||
supports_dma = (id & LTQ_SPI_ID_CFG_M) >> LTQ_SPI_ID_CFG_S;
|
||||
revision = id & LTQ_SPI_ID_REV_M;
|
||||
|
||||
lantiq_ssc_hw_init(spi);
|
||||
|
||||
|
|
@ -952,8 +959,8 @@ static int lantiq_ssc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev);
|
||||
|
||||
lantiq_ssc_writel(spi, 0, SPI_IRNEN);
|
||||
lantiq_ssc_writel(spi, 0, SPI_CLC);
|
||||
lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN);
|
||||
lantiq_ssc_writel(spi, 0, LTQ_SPI_CLC);
|
||||
rx_fifo_flush(spi);
|
||||
tx_fifo_flush(spi);
|
||||
hw_enter_config_mode(spi);
|
||||
|
|
@ -970,7 +977,6 @@ static struct platform_driver lantiq_ssc_driver = {
|
|||
.remove = lantiq_ssc_remove,
|
||||
.driver = {
|
||||
.name = "spi-lantiq-ssc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = lantiq_ssc_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue