Skip to content

Commit

Permalink
Merge branch 'spi-4.19' into spi-next
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Brown committed Aug 10, 2018
2 parents c3c7126 + 401c0d7 commit c1acb21
Show file tree
Hide file tree
Showing 27 changed files with 1,167 additions and 609 deletions.
6 changes: 4 additions & 2 deletions Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/spi/spi-rockchip.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
22 changes: 22 additions & 0 deletions Documentation/devicetree/bindings/spi/spi-uniphier.txt
Original file line number Diff line number Diff line change
@@ -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>;
};
3 changes: 3 additions & 0 deletions drivers/mtd/devices/m25p80.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,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.
Expand Down
13 changes: 13 additions & 0 deletions drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drivers/spi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion drivers/spi/spi-ath79.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
50 changes: 37 additions & 13 deletions drivers/spi/spi-bitbang.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;

bitbang = spi_master_get_devdata(spi->master);
if (bitbang->set_line_direction) {
int err;

return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
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);
}

/*----------------------------------------------------------------------*/
Expand Down
4 changes: 2 additions & 2 deletions drivers/spi/spi-butterfly.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/*----------------------------------------------------------------------*/
Expand Down
90 changes: 90 additions & 0 deletions drivers/spi/spi-dw-mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
6 changes: 5 additions & 1 deletion drivers/spi/spi-dw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -507,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);

Expand Down
2 changes: 2 additions & 0 deletions drivers/spi/spi-dw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit c1acb21

Please sign in to comment.