mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
Merge tag 'spi-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"Quite an active release for the SPI subsystem, lots of small updates
and fixes scattered about with highlights including:
- 3-wire support in the GPIO driver.
- support for setting a custom memory name in the memory mapped flash
drivers.
- support for extended mode in the Freescale DSPI controller.
- support for the non-standard integration with the Microsemi Ocelot
platform in the DesignWare driver.
- new driver for the SocioNext UniPhier"
* tag 'spi-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (47 commits)
spi: davinci: fix a NULL pointer dereference
spi: spi-mem: Constify spi_mem->name
mtd: m25p80: Call spi_mem_get_name() to let controller set a custom name
spi: spi-mem: Extend the SPI mem interface to set a custom memory name
spi: spi-mem: Fix a typo in the documentation of struct spi_mem
spi: uniphier: remove unnecessary include headers
spi: spi-gpio: add SPI_3WIRE support
spi: add flags parameter to txrx_word function pointers
spi: add SPI controller driver for UniPhier SoC
spi: add DT bindings for UniPhier SPI controller
spi: dw: document Microsemi integration
spi: img-spfi: Set device select bits for SPFI port state
spi: omap2-mcspi: remove several redundant variables
spi: dw-mmio: add MSCC Ocelot support
spi: dw: export dw_spi_set_cs
spi: spi-fsl-espi: Log fifo counters on error
spi: imx: Use the longuest possible burst size when in dynamic_burst
spi: imx: remove unnecessary check in spi_imx_can_dma
spi: imx: Use correct number of bytes per words
spi: imx: Use dynamic bursts only when bits_per_word is 8, 16 or 32
...
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface.
|
||||
|
||||
Required properties:
|
||||
- compatible : "snps,dw-apb-ssi"
|
||||
- reg : The register base for the controller.
|
||||
- compatible : "snps,dw-apb-ssi" or "mscc,<soc>-spi", where soc is "ocelot" or
|
||||
"jaguar2"
|
||||
- reg : The register base for the controller. For "mscc,<soc>-spi", a second
|
||||
register set is required (named ICPU_CFG:SPI_MST)
|
||||
- interrupts : One interrupt, used by the controller.
|
||||
- #address-cells : <1>, as required by generic SPI binding.
|
||||
- #size-cells : <0>, also as required by generic SPI binding.
|
||||
|
||||
@@ -7,6 +7,7 @@ Required Properties:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
"rockchip,rv1108-spi" for rv1108 SoCs.
|
||||
"rockchip,px30-spi", "rockchip,rk3066-spi" for px30 SoCs.
|
||||
"rockchip,rk3036-spi" for rk3036 SoCS.
|
||||
"rockchip,rk3066-spi" for rk3066 SoCs.
|
||||
"rockchip,rk3188-spi" for rk3188 SoCs.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
Socionext UniPhier SPI controller driver
|
||||
|
||||
UniPhier SoCs have SCSSI which supports SPI single channel.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "socionext,uniphier-scssi"
|
||||
- reg: address and length of the spi master registers
|
||||
- #address-cells: must be <1>, see spi-bus.txt
|
||||
- #size-cells: must be <0>, see spi-bus.txt
|
||||
- clocks: A phandle to the clock for the device.
|
||||
- resets: A phandle to the reset control for the device.
|
||||
|
||||
Example:
|
||||
|
||||
spi0: spi@54006000 {
|
||||
compatible = "socionext,uniphier-scssi";
|
||||
reg = <0x54006000 0x100>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&peri_clk 11>;
|
||||
resets = <&peri_rst 11>;
|
||||
};
|
||||
@@ -199,6 +199,9 @@ static int m25p_probe(struct spi_mem *spimem)
|
||||
if (data && data->name)
|
||||
nor->mtd.name = data->name;
|
||||
|
||||
if (!nor->mtd.name)
|
||||
nor->mtd.name = spi_mem_get_name(spimem);
|
||||
|
||||
/* For some (historical?) reason many platforms provide two different
|
||||
* names in flash_platform_data: "name" and "type". Quite often name is
|
||||
* set to "m25p80" and then "type" provides a real chip name.
|
||||
|
||||
@@ -688,6 +688,19 @@ config SPI_TXX9
|
||||
help
|
||||
SPI driver for Toshiba TXx9 MIPS SoCs
|
||||
|
||||
config SPI_UNIPHIER
|
||||
tristate "Socionext UniPhier SPI Controller"
|
||||
depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
|
||||
help
|
||||
This enables a driver for the Socionext UniPhier SoC SCSSI SPI controller.
|
||||
|
||||
UniPhier SoCs have SCSSI and MCSSI SPI controllers.
|
||||
Every UniPhier SoC has SCSSI which supports single channel.
|
||||
Older UniPhier Pro4/Pro5 also has MCSSI which support multiple channels.
|
||||
This driver supports SCSSI only.
|
||||
|
||||
If your SoC supports SCSSI, say Y here.
|
||||
|
||||
config SPI_XCOMM
|
||||
tristate "Analog Devices AD-FMCOMMS1-EBZ SPI-I2C-bridge driver"
|
||||
depends on I2C
|
||||
|
||||
@@ -101,6 +101,7 @@ spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o
|
||||
obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o
|
||||
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
|
||||
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
|
||||
obj-$(CONFIG_SPI_UNIPHIER) += spi-uniphier.o
|
||||
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
|
||||
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
|
||||
obj-$(CONFIG_SPI_XLP) += spi-xlp.o
|
||||
|
||||
@@ -176,7 +176,7 @@ static void ath79_spi_cleanup(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs,
|
||||
u32 word, u8 bits)
|
||||
u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
u32 ioc = sp->ioc_base;
|
||||
|
||||
+37
-13
@@ -49,22 +49,26 @@
|
||||
struct spi_bitbang_cs {
|
||||
unsigned nsecs; /* (clock cycle time)/2 */
|
||||
u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs,
|
||||
u32 word, u8 bits);
|
||||
u32 word, u8 bits, unsigned flags);
|
||||
unsigned (*txrx_bufs)(struct spi_device *,
|
||||
u32 (*txrx_word)(
|
||||
struct spi_device *spi,
|
||||
unsigned nsecs,
|
||||
u32 word, u8 bits),
|
||||
unsigned, struct spi_transfer *);
|
||||
u32 word, u8 bits,
|
||||
unsigned flags),
|
||||
unsigned, struct spi_transfer *,
|
||||
unsigned);
|
||||
};
|
||||
|
||||
static unsigned bitbang_txrx_8(
|
||||
struct spi_device *spi,
|
||||
u32 (*txrx_word)(struct spi_device *spi,
|
||||
unsigned nsecs,
|
||||
u32 word, u8 bits),
|
||||
u32 word, u8 bits,
|
||||
unsigned flags),
|
||||
unsigned ns,
|
||||
struct spi_transfer *t
|
||||
struct spi_transfer *t,
|
||||
unsigned flags
|
||||
) {
|
||||
unsigned bits = t->bits_per_word;
|
||||
unsigned count = t->len;
|
||||
@@ -76,7 +80,7 @@ static unsigned bitbang_txrx_8(
|
||||
|
||||
if (tx)
|
||||
word = *tx++;
|
||||
word = txrx_word(spi, ns, word, bits);
|
||||
word = txrx_word(spi, ns, word, bits, flags);
|
||||
if (rx)
|
||||
*rx++ = word;
|
||||
count -= 1;
|
||||
@@ -88,9 +92,11 @@ static unsigned bitbang_txrx_16(
|
||||
struct spi_device *spi,
|
||||
u32 (*txrx_word)(struct spi_device *spi,
|
||||
unsigned nsecs,
|
||||
u32 word, u8 bits),
|
||||
u32 word, u8 bits,
|
||||
unsigned flags),
|
||||
unsigned ns,
|
||||
struct spi_transfer *t
|
||||
struct spi_transfer *t,
|
||||
unsigned flags
|
||||
) {
|
||||
unsigned bits = t->bits_per_word;
|
||||
unsigned count = t->len;
|
||||
@@ -102,7 +108,7 @@ static unsigned bitbang_txrx_16(
|
||||
|
||||
if (tx)
|
||||
word = *tx++;
|
||||
word = txrx_word(spi, ns, word, bits);
|
||||
word = txrx_word(spi, ns, word, bits, flags);
|
||||
if (rx)
|
||||
*rx++ = word;
|
||||
count -= 2;
|
||||
@@ -114,9 +120,11 @@ static unsigned bitbang_txrx_32(
|
||||
struct spi_device *spi,
|
||||
u32 (*txrx_word)(struct spi_device *spi,
|
||||
unsigned nsecs,
|
||||
u32 word, u8 bits),
|
||||
u32 word, u8 bits,
|
||||
unsigned flags),
|
||||
unsigned ns,
|
||||
struct spi_transfer *t
|
||||
struct spi_transfer *t,
|
||||
unsigned flags
|
||||
) {
|
||||
unsigned bits = t->bits_per_word;
|
||||
unsigned count = t->len;
|
||||
@@ -128,7 +136,7 @@ static unsigned bitbang_txrx_32(
|
||||
|
||||
if (tx)
|
||||
word = *tx++;
|
||||
word = txrx_word(spi, ns, word, bits);
|
||||
word = txrx_word(spi, ns, word, bits, flags);
|
||||
if (rx)
|
||||
*rx++ = word;
|
||||
count -= 4;
|
||||
@@ -235,8 +243,24 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
{
|
||||
struct spi_bitbang_cs *cs = spi->controller_state;
|
||||
unsigned nsecs = cs->nsecs;
|
||||
struct spi_bitbang *bitbang;
|
||||
|
||||
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
|
||||
bitbang = spi_master_get_devdata(spi->master);
|
||||
if (bitbang->set_line_direction) {
|
||||
int err;
|
||||
|
||||
err = bitbang->set_line_direction(spi, !!(t->tx_buf));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (spi->mode & SPI_3WIRE) {
|
||||
unsigned flags;
|
||||
|
||||
flags = t->tx_buf ? SPI_MASTER_NO_RX : SPI_MASTER_NO_TX;
|
||||
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, flags);
|
||||
}
|
||||
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, 0);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
@@ -144,9 +144,9 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
|
||||
|
||||
static u32
|
||||
butterfly_txrx_word_mode0(struct spi_device *spi, unsigned nsecs, u32 word,
|
||||
u8 bits)
|
||||
u8 bits, unsigned flags)
|
||||
{
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
@@ -319,7 +319,7 @@ static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi)
|
||||
*/
|
||||
if (cdns_spi_read(xspi, CDNS_SPI_ISR) &
|
||||
CDNS_SPI_IXR_TXFULL)
|
||||
usleep_range(10, 20);
|
||||
udelay(10);
|
||||
|
||||
if (xspi->txbuf)
|
||||
cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++);
|
||||
@@ -739,7 +739,7 @@ static int __maybe_unused cnds_runtime_resume(struct device *dev)
|
||||
ret = clk_prepare_enable(xspi->ref_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot enable device clock.\n");
|
||||
clk_disable(xspi->pclk);
|
||||
clk_disable_unprepare(xspi->pclk);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -217,7 +217,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
|
||||
pdata = &dspi->pdata;
|
||||
|
||||
/* program delay transfers if tx_delay is non zero */
|
||||
if (spicfg->wdelay)
|
||||
if (spicfg && spicfg->wdelay)
|
||||
spidat1 |= SPIDAT1_WDEL;
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "spi-dw.h"
|
||||
|
||||
@@ -28,10 +30,90 @@
|
||||
struct dw_spi_mmio {
|
||||
struct dw_spi dws;
|
||||
struct clk *clk;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
#define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
|
||||
#define OCELOT_IF_SI_OWNER_MASK GENMASK(5, 4)
|
||||
#define OCELOT_IF_SI_OWNER_OFFSET 4
|
||||
#define MSCC_IF_SI_OWNER_SISL 0
|
||||
#define MSCC_IF_SI_OWNER_SIBM 1
|
||||
#define MSCC_IF_SI_OWNER_SIMC 2
|
||||
|
||||
#define MSCC_SPI_MST_SW_MODE 0x14
|
||||
#define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13)
|
||||
#define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5)
|
||||
|
||||
struct dw_spi_mscc {
|
||||
struct regmap *syscon;
|
||||
void __iomem *spi_mst;
|
||||
};
|
||||
|
||||
/*
|
||||
* The Designware SPI controller (referred to as master in the documentation)
|
||||
* automatically deasserts chip select when the tx fifo is empty. The chip
|
||||
* selects then needs to be either driven as GPIOs or, for the first 4 using the
|
||||
* the SPI boot controller registers. the final chip select is an OR gate
|
||||
* between the Designware SPI controller and the SPI boot controller.
|
||||
*/
|
||||
static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
struct dw_spi *dws = spi_master_get_devdata(spi->master);
|
||||
struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
|
||||
struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
|
||||
u32 cs = spi->chip_select;
|
||||
|
||||
if (cs < 4) {
|
||||
u32 sw_mode = MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE;
|
||||
|
||||
if (!enable)
|
||||
sw_mode |= MSCC_SPI_MST_SW_MODE_SW_SPI_CS(BIT(cs));
|
||||
|
||||
writel(sw_mode, dwsmscc->spi_mst + MSCC_SPI_MST_SW_MODE);
|
||||
}
|
||||
|
||||
dw_spi_set_cs(spi, enable);
|
||||
}
|
||||
|
||||
static int dw_spi_mscc_init(struct platform_device *pdev,
|
||||
struct dw_spi_mmio *dwsmmio)
|
||||
{
|
||||
struct dw_spi_mscc *dwsmscc;
|
||||
struct resource *res;
|
||||
|
||||
dwsmscc = devm_kzalloc(&pdev->dev, sizeof(*dwsmscc), GFP_KERNEL);
|
||||
if (!dwsmscc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
dwsmscc->spi_mst = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(dwsmscc->spi_mst)) {
|
||||
dev_err(&pdev->dev, "SPI_MST region map failed\n");
|
||||
return PTR_ERR(dwsmscc->spi_mst);
|
||||
}
|
||||
|
||||
dwsmscc->syscon = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon");
|
||||
if (IS_ERR(dwsmscc->syscon))
|
||||
return PTR_ERR(dwsmscc->syscon);
|
||||
|
||||
/* Deassert all CS */
|
||||
writel(0, dwsmscc->spi_mst + MSCC_SPI_MST_SW_MODE);
|
||||
|
||||
/* Select the owner of the SI interface */
|
||||
regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL,
|
||||
OCELOT_IF_SI_OWNER_MASK,
|
||||
MSCC_IF_SI_OWNER_SIMC << OCELOT_IF_SI_OWNER_OFFSET);
|
||||
|
||||
dwsmmio->dws.set_cs = dw_spi_mscc_set_cs;
|
||||
dwsmmio->priv = dwsmscc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int (*init_func)(struct platform_device *pdev,
|
||||
struct dw_spi_mmio *dwsmmio);
|
||||
struct dw_spi_mmio *dwsmmio;
|
||||
struct dw_spi *dws;
|
||||
struct resource *mem;
|
||||
@@ -99,6 +181,13 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
init_func = device_get_match_data(&pdev->dev);
|
||||
if (init_func) {
|
||||
ret = init_func(pdev, dwsmmio);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dw_spi_add_host(&pdev->dev, dws);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -123,6 +212,7 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id dw_spi_mmio_of_match[] = {
|
||||
{ .compatible = "snps,dw-apb-ssi", },
|
||||
{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_init},
|
||||
{ /* end of table */}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
||||
|
||||
@@ -133,7 +133,7 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
static void dw_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
void dw_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
|
||||
struct chip_data *chip = spi_get_ctldata(spi);
|
||||
@@ -145,6 +145,7 @@ static void dw_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
if (!enable)
|
||||
dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_spi_set_cs);
|
||||
|
||||
/* Return the max entries we can fill into tx fifo */
|
||||
static inline u32 tx_max(struct dw_spi *dws)
|
||||
@@ -485,6 +486,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||
dws->dma_inited = 0;
|
||||
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
|
||||
|
||||
spi_controller_set_devdata(master, dws);
|
||||
|
||||
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
|
||||
master);
|
||||
if (ret < 0) {
|
||||
@@ -505,6 +508,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||
master->dev.of_node = dev->of_node;
|
||||
master->flags = SPI_MASTER_GPIO_SS;
|
||||
|
||||
if (dws->set_cs)
|
||||
master->set_cs = dws->set_cs;
|
||||
|
||||
/* Basic HW init */
|
||||
spi_hw_init(dev, dws);
|
||||
|
||||
@@ -518,7 +524,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||
}
|
||||
}
|
||||
|
||||
spi_controller_set_devdata(master, dws);
|
||||
ret = devm_spi_register_controller(dev, master);
|
||||
if (ret) {
|
||||
dev_err(&master->dev, "problem registering spi master\n");
|
||||
|
||||
@@ -112,6 +112,7 @@ struct dw_spi {
|
||||
u32 reg_io_width; /* DR I/O width in bytes */
|
||||
u16 bus_num;
|
||||
u16 num_cs; /* supported slave numbers */
|
||||
void (*set_cs)(struct spi_device *spi, bool enable);
|
||||
|
||||
/* Current message transfer state info */
|
||||
size_t len;
|
||||
@@ -244,6 +245,7 @@ struct dw_spi_chip {
|
||||
void (*cs_control)(u32 command);
|
||||
};
|
||||
|
||||
extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
|
||||
extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
|
||||
extern void dw_spi_remove_host(struct dw_spi *dws);
|
||||
extern int dw_spi_suspend_host(struct dw_spi *dws);
|
||||
|
||||
+276
-239
File diff suppressed because it is too large
Load Diff
@@ -547,8 +547,11 @@ static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events)
|
||||
dev_err(espi->dev,
|
||||
"Transfer done but SPIE_DON isn't set!\n");
|
||||
|
||||
if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE)
|
||||
if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE) {
|
||||
dev_err(espi->dev, "Transfer done but rx/tx fifo's aren't empty!\n");
|
||||
dev_err(espi->dev, "SPIE_RXCNT = %d, SPIE_TXCNT = %d\n",
|
||||
SPIE_RXCNT(events), SPIE_TXCNT(events));
|
||||
}
|
||||
|
||||
complete(&espi->done);
|
||||
}
|
||||
|
||||
+32
-17
@@ -121,7 +121,10 @@ static inline int getmiso(const struct spi_device *spi)
|
||||
{
|
||||
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
|
||||
|
||||
return !!gpiod_get_value_cansleep(spi_gpio->miso);
|
||||
if (spi->mode & SPI_3WIRE)
|
||||
return !!gpiod_get_value_cansleep(spi_gpio->mosi);
|
||||
else
|
||||
return !!gpiod_get_value_cansleep(spi_gpio->miso);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -149,27 +152,27 @@ static inline int getmiso(const struct spi_device *spi)
|
||||
*/
|
||||
|
||||
static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
|
||||
unsigned nsecs, u32 word, u8 bits)
|
||||
unsigned nsecs, u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
|
||||
}
|
||||
|
||||
static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi,
|
||||
unsigned nsecs, u32 word, u8 bits)
|
||||
unsigned nsecs, u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
|
||||
return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
|
||||
}
|
||||
|
||||
static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi,
|
||||
unsigned nsecs, u32 word, u8 bits)
|
||||
unsigned nsecs, u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
|
||||
}
|
||||
|
||||
static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
|
||||
unsigned nsecs, u32 word, u8 bits)
|
||||
unsigned nsecs, u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
|
||||
return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -183,30 +186,30 @@ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
|
||||
*/
|
||||
|
||||
static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
|
||||
unsigned nsecs, u32 word, u8 bits)
|
||||
unsigned nsecs, u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
unsigned flags = spi->master->flags;
|
||||
flags = spi->master->flags;
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
|
||||
}
|
||||
|
||||
static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
|
||||
unsigned nsecs, u32 word, u8 bits)
|
||||
unsigned nsecs, u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
unsigned flags = spi->master->flags;
|
||||
flags = spi->master->flags;
|
||||
return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
|
||||
}
|
||||
|
||||
static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
|
||||
unsigned nsecs, u32 word, u8 bits)
|
||||
unsigned nsecs, u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
unsigned flags = spi->master->flags;
|
||||
flags = spi->master->flags;
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
|
||||
}
|
||||
|
||||
static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
|
||||
unsigned nsecs, u32 word, u8 bits)
|
||||
unsigned nsecs, u32 word, u8 bits, unsigned flags)
|
||||
{
|
||||
unsigned flags = spi->master->flags;
|
||||
flags = spi->master->flags;
|
||||
return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
|
||||
}
|
||||
|
||||
@@ -250,6 +253,16 @@ static int spi_gpio_setup(struct spi_device *spi)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int spi_gpio_set_direction(struct spi_device *spi, bool output)
|
||||
{
|
||||
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
|
||||
|
||||
if (output)
|
||||
return gpiod_direction_output(spi_gpio->mosi, 1);
|
||||
else
|
||||
return gpiod_direction_input(spi_gpio->mosi);
|
||||
}
|
||||
|
||||
static void spi_gpio_cleanup(struct spi_device *spi)
|
||||
{
|
||||
spi_bitbang_cleanup(spi);
|
||||
@@ -395,6 +408,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
||||
return status;
|
||||
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
|
||||
master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL;
|
||||
master->flags = master_flags;
|
||||
master->bus_num = pdev->id;
|
||||
/* The master needs to think there is a chipselect even if not connected */
|
||||
@@ -407,6 +421,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
spi_gpio->bitbang.master = master;
|
||||
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
|
||||
spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction;
|
||||
|
||||
if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
|
||||
spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
|
||||
|
||||
@@ -419,6 +419,9 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
|
||||
u32 val;
|
||||
|
||||
val = spfi_readl(spfi, SPFI_PORT_STATE);
|
||||
val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK <<
|
||||
SPFI_PORT_STATE_DEV_SEL_SHIFT);
|
||||
val |= msg->spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
|
||||
if (msg->spi->mode & SPI_CPHA)
|
||||
val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
|
||||
else
|
||||
|
||||
+101
-61
@@ -94,8 +94,7 @@ struct spi_imx_data {
|
||||
void *rx_buf;
|
||||
const void *tx_buf;
|
||||
unsigned int txfifo; /* number of words pushed in tx FIFO */
|
||||
unsigned int dynamic_burst, read_u32;
|
||||
unsigned int word_mask;
|
||||
unsigned int dynamic_burst;
|
||||
|
||||
/* Slave mode */
|
||||
bool slave_mode;
|
||||
@@ -140,6 +139,8 @@ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \
|
||||
*(type *)spi_imx->rx_buf = val; \
|
||||
spi_imx->rx_buf += sizeof(type); \
|
||||
} \
|
||||
\
|
||||
spi_imx->remainder -= sizeof(type); \
|
||||
}
|
||||
|
||||
#define MXC_SPI_BUF_TX(type) \
|
||||
@@ -203,7 +204,12 @@ out:
|
||||
|
||||
static int spi_imx_bytes_per_word(const int bits_per_word)
|
||||
{
|
||||
return DIV_ROUND_UP(bits_per_word, BITS_PER_BYTE);
|
||||
if (bits_per_word <= 8)
|
||||
return 1;
|
||||
else if (bits_per_word <= 16)
|
||||
return 2;
|
||||
else
|
||||
return 4;
|
||||
}
|
||||
|
||||
static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
|
||||
@@ -220,17 +226,11 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
|
||||
|
||||
bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
|
||||
|
||||
if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
|
||||
return false;
|
||||
|
||||
for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
|
||||
if (!(transfer->len % (i * bytes_per_word)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
return false;
|
||||
|
||||
spi_imx->wml = i;
|
||||
spi_imx->dynamic_burst = 0;
|
||||
|
||||
@@ -291,26 +291,39 @@ static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx)
|
||||
else if (bytes_per_word == 2)
|
||||
val = (val << 16) | (val >> 16);
|
||||
#endif
|
||||
val &= spi_imx->word_mask;
|
||||
*(u32 *)spi_imx->rx_buf = val;
|
||||
spi_imx->rx_buf += sizeof(u32);
|
||||
}
|
||||
|
||||
spi_imx->remainder -= sizeof(u32);
|
||||
}
|
||||
|
||||
static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)
|
||||
{
|
||||
unsigned int bytes_per_word;
|
||||
int unaligned;
|
||||
u32 val;
|
||||
|
||||
bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
|
||||
if (spi_imx->read_u32) {
|
||||
unaligned = spi_imx->remainder % 4;
|
||||
|
||||
if (!unaligned) {
|
||||
spi_imx_buf_rx_swap_u32(spi_imx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_per_word == 1)
|
||||
spi_imx_buf_rx_u8(spi_imx);
|
||||
else if (bytes_per_word == 2)
|
||||
if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
|
||||
spi_imx_buf_rx_u16(spi_imx);
|
||||
return;
|
||||
}
|
||||
|
||||
val = readl(spi_imx->base + MXC_CSPIRXDATA);
|
||||
|
||||
while (unaligned--) {
|
||||
if (spi_imx->rx_buf) {
|
||||
*(u8 *)spi_imx->rx_buf = (val >> (8 * unaligned)) & 0xff;
|
||||
spi_imx->rx_buf++;
|
||||
}
|
||||
spi_imx->remainder--;
|
||||
}
|
||||
}
|
||||
|
||||
static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
|
||||
@@ -322,7 +335,6 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
|
||||
|
||||
if (spi_imx->tx_buf) {
|
||||
val = *(u32 *)spi_imx->tx_buf;
|
||||
val &= spi_imx->word_mask;
|
||||
spi_imx->tx_buf += sizeof(u32);
|
||||
}
|
||||
|
||||
@@ -340,40 +352,30 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
|
||||
|
||||
static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
|
||||
{
|
||||
u32 ctrl, val;
|
||||
unsigned int bytes_per_word;
|
||||
int unaligned;
|
||||
u32 val = 0;
|
||||
|
||||
if (spi_imx->count == spi_imx->remainder) {
|
||||
ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
|
||||
ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
|
||||
if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) {
|
||||
spi_imx->remainder = spi_imx->count %
|
||||
MX51_ECSPI_CTRL_MAX_BURST;
|
||||
val = MX51_ECSPI_CTRL_MAX_BURST * 8 - 1;
|
||||
} else if (spi_imx->count >= sizeof(u32)) {
|
||||
spi_imx->remainder = spi_imx->count % sizeof(u32);
|
||||
val = (spi_imx->count - spi_imx->remainder) * 8 - 1;
|
||||
} else {
|
||||
spi_imx->remainder = 0;
|
||||
val = spi_imx->bits_per_word - 1;
|
||||
spi_imx->read_u32 = 0;
|
||||
}
|
||||
unaligned = spi_imx->count % 4;
|
||||
|
||||
ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET);
|
||||
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
|
||||
}
|
||||
|
||||
if (spi_imx->count >= sizeof(u32)) {
|
||||
if (!unaligned) {
|
||||
spi_imx_buf_tx_swap_u32(spi_imx);
|
||||
return;
|
||||
}
|
||||
|
||||
bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
|
||||
|
||||
if (bytes_per_word == 1)
|
||||
spi_imx_buf_tx_u8(spi_imx);
|
||||
else if (bytes_per_word == 2)
|
||||
if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
|
||||
spi_imx_buf_tx_u16(spi_imx);
|
||||
return;
|
||||
}
|
||||
|
||||
while (unaligned--) {
|
||||
if (spi_imx->tx_buf) {
|
||||
val |= *(u8 *)spi_imx->tx_buf << (8 * unaligned);
|
||||
spi_imx->tx_buf++;
|
||||
}
|
||||
spi_imx->count--;
|
||||
}
|
||||
|
||||
writel(val, spi_imx->base + MXC_CSPITXDATA);
|
||||
}
|
||||
|
||||
static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
|
||||
@@ -392,6 +394,8 @@ static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
|
||||
spi_imx->rx_buf += n_bytes;
|
||||
spi_imx->slave_burst -= n_bytes;
|
||||
}
|
||||
|
||||
spi_imx->remainder -= sizeof(u32);
|
||||
}
|
||||
|
||||
static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
|
||||
@@ -1001,12 +1005,52 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)
|
||||
gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active);
|
||||
}
|
||||
|
||||
static void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits)
|
||||
{
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
|
||||
ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
|
||||
ctrl |= ((n_bits - 1) << MX51_ECSPI_CTRL_BL_OFFSET);
|
||||
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
|
||||
}
|
||||
|
||||
static void spi_imx_push(struct spi_imx_data *spi_imx)
|
||||
{
|
||||
unsigned int burst_len, fifo_words;
|
||||
|
||||
if (spi_imx->dynamic_burst)
|
||||
fifo_words = 4;
|
||||
else
|
||||
fifo_words = spi_imx_bytes_per_word(spi_imx->bits_per_word);
|
||||
/*
|
||||
* Reload the FIFO when the remaining bytes to be transferred in the
|
||||
* current burst is 0. This only applies when bits_per_word is a
|
||||
* multiple of 8.
|
||||
*/
|
||||
if (!spi_imx->remainder) {
|
||||
if (spi_imx->dynamic_burst) {
|
||||
|
||||
/* We need to deal unaligned data first */
|
||||
burst_len = spi_imx->count % MX51_ECSPI_CTRL_MAX_BURST;
|
||||
|
||||
if (!burst_len)
|
||||
burst_len = MX51_ECSPI_CTRL_MAX_BURST;
|
||||
|
||||
spi_imx_set_burst_len(spi_imx, burst_len * 8);
|
||||
|
||||
spi_imx->remainder = burst_len;
|
||||
} else {
|
||||
spi_imx->remainder = fifo_words;
|
||||
}
|
||||
}
|
||||
|
||||
while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) {
|
||||
if (!spi_imx->count)
|
||||
break;
|
||||
if (spi_imx->txfifo && (spi_imx->count == spi_imx->remainder))
|
||||
if (spi_imx->dynamic_burst &&
|
||||
spi_imx->txfifo >= DIV_ROUND_UP(spi_imx->remainder,
|
||||
fifo_words))
|
||||
break;
|
||||
spi_imx->tx(spi_imx);
|
||||
spi_imx->txfifo++;
|
||||
@@ -1102,27 +1146,20 @@ static int spi_imx_setupxfer(struct spi_device *spi,
|
||||
spi_imx->bits_per_word = t->bits_per_word;
|
||||
spi_imx->speed_hz = t->speed_hz;
|
||||
|
||||
/* Initialize the functions for transfer */
|
||||
if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) {
|
||||
u32 mask;
|
||||
/*
|
||||
* Initialize the functions for transfer. To transfer non byte-aligned
|
||||
* words, we have to use multiple word-size bursts, we can't use
|
||||
* dynamic_burst in that case.
|
||||
*/
|
||||
if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode &&
|
||||
(spi_imx->bits_per_word == 8 ||
|
||||
spi_imx->bits_per_word == 16 ||
|
||||
spi_imx->bits_per_word == 32)) {
|
||||
|
||||
spi_imx->dynamic_burst = 0;
|
||||
spi_imx->remainder = 0;
|
||||
spi_imx->read_u32 = 1;
|
||||
|
||||
mask = (1 << spi_imx->bits_per_word) - 1;
|
||||
spi_imx->rx = spi_imx_buf_rx_swap;
|
||||
spi_imx->tx = spi_imx_buf_tx_swap;
|
||||
spi_imx->dynamic_burst = 1;
|
||||
spi_imx->remainder = t->len;
|
||||
|
||||
if (spi_imx->bits_per_word <= 8)
|
||||
spi_imx->word_mask = mask << 24 | mask << 16
|
||||
| mask << 8 | mask;
|
||||
else if (spi_imx->bits_per_word <= 16)
|
||||
spi_imx->word_mask = mask << 16 | mask;
|
||||
else
|
||||
spi_imx->word_mask = mask;
|
||||
} else {
|
||||
if (spi_imx->bits_per_word <= 8) {
|
||||
spi_imx->rx = spi_imx_buf_rx_u8;
|
||||
@@ -1134,6 +1171,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
|
||||
spi_imx->rx = spi_imx_buf_rx_u32;
|
||||
spi_imx->tx = spi_imx_buf_tx_u32;
|
||||
}
|
||||
spi_imx->dynamic_burst = 0;
|
||||
}
|
||||
|
||||
if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t))
|
||||
@@ -1317,6 +1355,7 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
|
||||
spi_imx->rx_buf = transfer->rx_buf;
|
||||
spi_imx->count = transfer->len;
|
||||
spi_imx->txfifo = 0;
|
||||
spi_imx->remainder = 0;
|
||||
|
||||
reinit_completion(&spi_imx->xfer_done);
|
||||
|
||||
@@ -1354,6 +1393,7 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi,
|
||||
spi_imx->rx_buf = transfer->rx_buf;
|
||||
spi_imx->count = transfer->len;
|
||||
spi_imx->txfifo = 0;
|
||||
spi_imx->remainder = 0;
|
||||
|
||||
reinit_completion(&spi_imx->xfer_done);
|
||||
spi_imx->slave_aborted = false;
|
||||
|
||||
@@ -188,9 +188,10 @@ static void lm70_chipselect(struct spi_device *spi, int value)
|
||||
/*
|
||||
* Our actual bitbanger routine.
|
||||
*/
|
||||
static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
|
||||
static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits,
|
||||
unsigned flags)
|
||||
{
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
|
||||
return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
|
||||
}
|
||||
|
||||
static void spi_lm70llp_attach(struct parport *p)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user