mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 05:33:09 +00:00
Merge series "spi: Adding support for Microchip Sparx5 SoC" from Lars Povlsen <lars.povlsen@microchip.com>:
The series add support for the Sparx5 SoC SPI controller in the spi-dw-mmio.c spi driver. v5 changes: - rx-sample-delay-ns documentation changes from Rob Herring: - Drop superfluous type $ref - Add default value = 0 v4 changes: - Changed snps,rx-sample-delay-ns to snps,rx-sample-delay-ns suggested by Rob Herring (rockchip also has this property). - Added support for controller-level rx-sample-delay-ns value as well as per SPI slave value (rockchip has controller-level property). - Dropped internal mux in favor of suggested spi-mux to control bus inteface selection. v3 changes: - Added mux support for controlling SPI bus interface. This is new mux driver, bindings and added to sparx5 base DT. - Removed "microchip,spi-interface2" property in favour of "mux-controls" property in SPI controller (sparx5 only). - Changed dw_spi_sparx5_set_cs() to use the mux control instead of directly acessing "mux" register. Associated code/defines moved to mux driver. - Changed dw_spi_sparx5_set_cs() to match other similar functions in signature and avoid explicit CS toggling. - Spun off duplicated NAND device DT chunks into separate DT file. v2 changes: - Moved all RX sample delay into spi-dw-core.c, using the "snps,rx-sample-delay-ns" device property. - Integrated Sparx5 support directly in spi-dw-mmio.c - Changed SPI2 configuration to per-slave "microchip,spi-interface2" property. - Added bindings to existing snps,dw-apb-ssi.yaml file - Dropped patches for polled mode and SPI memory operations. Lars Povlsen (6): spi: dw: Add support for RX sample delay register spi: dw: Add Microchip Sparx5 support arm64: dts: sparx5: Add SPI controller and associated mmio-mux dt-bindings: snps,dw-apb-ssi: Add sparx5 support, plus rx-sample-delay-ns property arm64: dts: sparx5: Add spi-nor support arm64: dts: sparx5: Add spi-nand devices .../bindings/spi/snps,dw-apb-ssi.yaml | 21 ++++++ arch/arm64/boot/dts/microchip/sparx5.dtsi | 47 ++++++++++++- .../arm64/boot/dts/microchip/sparx5_nand.dtsi | 31 ++++++++ .../boot/dts/microchip/sparx5_pcb125.dts | 30 ++++++++ .../boot/dts/microchip/sparx5_pcb134.dts | 1 + .../dts/microchip/sparx5_pcb134_board.dtsi | 16 +++++ .../boot/dts/microchip/sparx5_pcb135.dts | 1 + .../dts/microchip/sparx5_pcb135_board.dtsi | 16 +++++ drivers/spi/spi-dw-core.c | 26 +++++++ drivers/spi/spi-dw-mmio.c | 70 ++++++++++++++++++- drivers/spi/spi-dw.h | 3 + 11 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/microchip/sparx5_nand.dtsi -- 2.27.0 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
This commit is contained in:
commit
b0b71a6f5d
@ -36,6 +36,8 @@ properties:
|
|||||||
- mscc,ocelot-spi
|
- mscc,ocelot-spi
|
||||||
- mscc,jaguar2-spi
|
- mscc,jaguar2-spi
|
||||||
- const: snps,dw-apb-ssi
|
- const: snps,dw-apb-ssi
|
||||||
|
- description: Microchip Sparx5 SoC SPI Controller
|
||||||
|
const: microchip,sparx5-spi
|
||||||
- description: Amazon Alpine SPI Controller
|
- description: Amazon Alpine SPI Controller
|
||||||
const: amazon,alpine-dw-apb-ssi
|
const: amazon,alpine-dw-apb-ssi
|
||||||
- description: Renesas RZ/N1 SPI Controller
|
- description: Renesas RZ/N1 SPI Controller
|
||||||
@ -93,6 +95,12 @@ properties:
|
|||||||
- const: tx
|
- const: tx
|
||||||
- const: rx
|
- const: rx
|
||||||
|
|
||||||
|
rx-sample-delay-ns:
|
||||||
|
default: 0
|
||||||
|
description: Default value of the rx-sample-delay-ns property.
|
||||||
|
This value will be used if the property is not explicitly defined
|
||||||
|
for a SPI slave device. See below.
|
||||||
|
|
||||||
patternProperties:
|
patternProperties:
|
||||||
"^.*@[0-9a-f]+$":
|
"^.*@[0-9a-f]+$":
|
||||||
type: object
|
type: object
|
||||||
@ -107,6 +115,13 @@ patternProperties:
|
|||||||
spi-tx-bus-width:
|
spi-tx-bus-width:
|
||||||
const: 1
|
const: 1
|
||||||
|
|
||||||
|
rx-sample-delay-ns:
|
||||||
|
description: SPI Rx sample delay offset, unit is nanoseconds.
|
||||||
|
The delay from the default sample time before the actual
|
||||||
|
sample of the rxd input signal occurs. The "rx_sample_delay"
|
||||||
|
is an optional feature of the designware controller, and the
|
||||||
|
upper limit is also subject to controller configuration.
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
required:
|
required:
|
||||||
@ -129,5 +144,11 @@ examples:
|
|||||||
num-cs = <2>;
|
num-cs = <2>;
|
||||||
cs-gpios = <&gpio0 13 0>,
|
cs-gpios = <&gpio0 13 0>,
|
||||||
<&gpio0 14 0>;
|
<&gpio0 14 0>;
|
||||||
|
rx-sample-delay-ns = <3>;
|
||||||
|
spi-flash@1 {
|
||||||
|
compatible = "spi-nand";
|
||||||
|
reg = <1>;
|
||||||
|
rx-sample-delay-ns = <7>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
...
|
...
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
#include "spi-dw.h"
|
#include "spi-dw.h"
|
||||||
|
|
||||||
@ -26,6 +27,8 @@ struct chip_data {
|
|||||||
|
|
||||||
u16 clk_div; /* baud rate divider */
|
u16 clk_div; /* baud rate divider */
|
||||||
u32 speed_hz; /* baud rate */
|
u32 speed_hz; /* baud rate */
|
||||||
|
|
||||||
|
u32 rx_sample_dly; /* RX sample delay */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
@ -52,6 +55,7 @@ static const struct debugfs_reg32 dw_spi_dbgfs_regs[] = {
|
|||||||
DW_SPI_DBGFS_REG("DMACR", DW_SPI_DMACR),
|
DW_SPI_DBGFS_REG("DMACR", DW_SPI_DMACR),
|
||||||
DW_SPI_DBGFS_REG("DMATDLR", DW_SPI_DMATDLR),
|
DW_SPI_DBGFS_REG("DMATDLR", DW_SPI_DMATDLR),
|
||||||
DW_SPI_DBGFS_REG("DMARDLR", DW_SPI_DMARDLR),
|
DW_SPI_DBGFS_REG("DMARDLR", DW_SPI_DMARDLR),
|
||||||
|
DW_SPI_DBGFS_REG("RX_SAMPLE_DLY", DW_SPI_RX_SAMPLE_DLY),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dw_spi_debugfs_init(struct dw_spi *dws)
|
static int dw_spi_debugfs_init(struct dw_spi *dws)
|
||||||
@ -328,6 +332,12 @@ static int dw_spi_transfer_one(struct spi_controller *master,
|
|||||||
if (master->can_dma && master->can_dma(master, spi, transfer))
|
if (master->can_dma && master->can_dma(master, spi, transfer))
|
||||||
dws->dma_mapped = master->cur_msg_mapped;
|
dws->dma_mapped = master->cur_msg_mapped;
|
||||||
|
|
||||||
|
/* Update RX sample delay if required */
|
||||||
|
if (dws->cur_rx_sample_dly != chip->rx_sample_dly) {
|
||||||
|
dw_writel(dws, DW_SPI_RX_SAMPLE_DLY, chip->rx_sample_dly);
|
||||||
|
dws->cur_rx_sample_dly = chip->rx_sample_dly;
|
||||||
|
}
|
||||||
|
|
||||||
/* For poll mode just disable all interrupts */
|
/* For poll mode just disable all interrupts */
|
||||||
spi_mask_intr(dws, 0xff);
|
spi_mask_intr(dws, 0xff);
|
||||||
|
|
||||||
@ -380,10 +390,22 @@ static int dw_spi_setup(struct spi_device *spi)
|
|||||||
/* Only alloc on first setup */
|
/* Only alloc on first setup */
|
||||||
chip = spi_get_ctldata(spi);
|
chip = spi_get_ctldata(spi);
|
||||||
if (!chip) {
|
if (!chip) {
|
||||||
|
struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
|
||||||
|
u32 rx_sample_dly_ns;
|
||||||
|
|
||||||
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
|
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
|
||||||
if (!chip)
|
if (!chip)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
spi_set_ctldata(spi, chip);
|
spi_set_ctldata(spi, chip);
|
||||||
|
/* Get specific / default rx-sample-delay */
|
||||||
|
if (device_property_read_u32(&spi->dev,
|
||||||
|
"rx-sample-delay-ns",
|
||||||
|
&rx_sample_dly_ns) != 0)
|
||||||
|
/* Use default controller value */
|
||||||
|
rx_sample_dly_ns = dws->def_rx_sample_dly_ns;
|
||||||
|
chip->rx_sample_dly = DIV_ROUND_CLOSEST(rx_sample_dly_ns,
|
||||||
|
NSEC_PER_SEC /
|
||||||
|
dws->max_freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
chip->tmode = SPI_TMOD_TR;
|
chip->tmode = SPI_TMOD_TR;
|
||||||
@ -472,6 +494,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
|||||||
if (dws->set_cs)
|
if (dws->set_cs)
|
||||||
master->set_cs = dws->set_cs;
|
master->set_cs = dws->set_cs;
|
||||||
|
|
||||||
|
/* Get default rx sample delay */
|
||||||
|
device_property_read_u32(dev, "rx-sample-delay-ns",
|
||||||
|
&dws->def_rx_sample_dly_ns);
|
||||||
|
|
||||||
/* Basic HW init */
|
/* Basic HW init */
|
||||||
spi_hw_init(dev, dws);
|
spi_hw_init(dev, dws);
|
||||||
|
|
||||||
|
@ -45,6 +45,9 @@ struct dw_spi_mmio {
|
|||||||
#define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13)
|
#define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13)
|
||||||
#define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5)
|
#define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5)
|
||||||
|
|
||||||
|
#define SPARX5_FORCE_ENA 0xa4
|
||||||
|
#define SPARX5_FORCE_VAL 0xa8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For Keem Bay, CTRLR0[31] is used to select controller mode.
|
* For Keem Bay, CTRLR0[31] is used to select controller mode.
|
||||||
* 0: SSI is slave
|
* 0: SSI is slave
|
||||||
@ -54,7 +57,7 @@ struct dw_spi_mmio {
|
|||||||
|
|
||||||
struct dw_spi_mscc {
|
struct dw_spi_mscc {
|
||||||
struct regmap *syscon;
|
struct regmap *syscon;
|
||||||
void __iomem *spi_mst;
|
void __iomem *spi_mst; /* Not sparx5 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -134,6 +137,70 @@ static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev,
|
|||||||
JAGUAR2_IF_SI_OWNER_OFFSET);
|
JAGUAR2_IF_SI_OWNER_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 driven by a CS override
|
||||||
|
* register. enable is an active low signal.
|
||||||
|
*/
|
||||||
|
static void dw_spi_sparx5_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;
|
||||||
|
u8 cs = spi->chip_select;
|
||||||
|
|
||||||
|
if (!enable) {
|
||||||
|
/* CS override drive enable */
|
||||||
|
regmap_write(dwsmscc->syscon, SPARX5_FORCE_ENA, 1);
|
||||||
|
/* Now set CSx enabled */
|
||||||
|
regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~BIT(cs));
|
||||||
|
/* Allow settle */
|
||||||
|
usleep_range(1, 5);
|
||||||
|
} else {
|
||||||
|
/* CS value */
|
||||||
|
regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~0);
|
||||||
|
/* Allow settle */
|
||||||
|
usleep_range(1, 5);
|
||||||
|
/* CS override drive disable */
|
||||||
|
regmap_write(dwsmscc->syscon, SPARX5_FORCE_ENA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
dw_spi_set_cs(spi, enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dw_spi_mscc_sparx5_init(struct platform_device *pdev,
|
||||||
|
struct dw_spi_mmio *dwsmmio)
|
||||||
|
{
|
||||||
|
const char *syscon_name = "microchip,sparx5-cpu-syscon";
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct dw_spi_mscc *dwsmscc;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_SPI_MUX)) {
|
||||||
|
dev_err(dev, "This driver needs CONFIG_SPI_MUX\n");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwsmscc = devm_kzalloc(dev, sizeof(*dwsmscc), GFP_KERNEL);
|
||||||
|
if (!dwsmscc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dwsmscc->syscon =
|
||||||
|
syscon_regmap_lookup_by_compatible(syscon_name);
|
||||||
|
if (IS_ERR(dwsmscc->syscon)) {
|
||||||
|
dev_err(dev, "No syscon map %s\n", syscon_name);
|
||||||
|
return PTR_ERR(dwsmscc->syscon);
|
||||||
|
}
|
||||||
|
|
||||||
|
dwsmmio->dws.set_cs = dw_spi_sparx5_set_cs;
|
||||||
|
dwsmmio->priv = dwsmscc;
|
||||||
|
|
||||||
|
/* Register hook to configure CTRLR0 */
|
||||||
|
dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int dw_spi_alpine_init(struct platform_device *pdev,
|
static int dw_spi_alpine_init(struct platform_device *pdev,
|
||||||
struct dw_spi_mmio *dwsmmio)
|
struct dw_spi_mmio *dwsmmio)
|
||||||
{
|
{
|
||||||
@ -297,6 +364,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
|
|||||||
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init},
|
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init},
|
||||||
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
|
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
|
||||||
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
|
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
|
||||||
|
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
|
||||||
{ /* end of table */}
|
{ /* end of table */}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#define DW_SPI_IDR 0x58
|
#define DW_SPI_IDR 0x58
|
||||||
#define DW_SPI_VERSION 0x5c
|
#define DW_SPI_VERSION 0x5c
|
||||||
#define DW_SPI_DR 0x60
|
#define DW_SPI_DR 0x60
|
||||||
|
#define DW_SPI_RX_SAMPLE_DLY 0xf0
|
||||||
#define DW_SPI_CS_OVERRIDE 0xf4
|
#define DW_SPI_CS_OVERRIDE 0xf4
|
||||||
|
|
||||||
/* Bit fields in CTRLR0 */
|
/* Bit fields in CTRLR0 */
|
||||||
@ -140,6 +141,8 @@ struct dw_spi {
|
|||||||
u8 n_bytes; /* current is a 1/2 bytes op */
|
u8 n_bytes; /* current is a 1/2 bytes op */
|
||||||
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
|
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
|
||||||
u32 current_freq; /* frequency in hz */
|
u32 current_freq; /* frequency in hz */
|
||||||
|
u32 cur_rx_sample_dly;
|
||||||
|
u32 def_rx_sample_dly_ns;
|
||||||
|
|
||||||
/* DMA info */
|
/* DMA info */
|
||||||
struct dma_chan *txchan;
|
struct dma_chan *txchan;
|
||||||
|
Loading…
Reference in New Issue
Block a user