diff options
Diffstat (limited to 'drivers/spi/spi-dw-mmio.c')
-rw-r--r-- | drivers/spi/spi-dw-mmio.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 328541b5fb52..5e6faa98aa85 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -54,6 +54,20 @@ struct dw_spi_mscc { }; /* + * Elba SoC does not use ssi, pin override is used for cs 0,1 and + * gpios for cs 2,3 as defined in the device tree. + * + * cs: | 1 0 + * bit: |---3-------2-------1-------0 + * | cs1 cs1_ovr cs0 cs0_ovr + */ +#define ELBA_SPICS_REG 0x2468 +#define ELBA_SPICS_OFFSET(cs) ((cs) << 1) +#define ELBA_SPICS_MASK(cs) (GENMASK(1, 0) << ELBA_SPICS_OFFSET(cs)) +#define ELBA_SPICS_SET(cs, val) \ + ((((val) << 1) | BIT(0)) << ELBA_SPICS_OFFSET(cs)) + +/* * 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 @@ -237,6 +251,49 @@ static int dw_spi_canaan_k210_init(struct platform_device *pdev, return 0; } +static void dw_spi_elba_override_cs(struct regmap *syscon, int cs, int enable) +{ + regmap_update_bits(syscon, ELBA_SPICS_REG, ELBA_SPICS_MASK(cs), + ELBA_SPICS_SET(cs, enable)); +} + +static void dw_spi_elba_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 regmap *syscon = dwsmmio->priv; + u8 cs; + + cs = spi->chip_select; + if (cs < 2) + dw_spi_elba_override_cs(syscon, spi->chip_select, enable); + + /* + * The DW SPI controller needs a native CS bit selected to start + * the serial engine. + */ + spi->chip_select = 0; + dw_spi_set_cs(spi, enable); + spi->chip_select = cs; +} + +static int dw_spi_elba_init(struct platform_device *pdev, + struct dw_spi_mmio *dwsmmio) +{ + struct regmap *syscon; + + syscon = syscon_regmap_lookup_by_phandle(dev_of_node(&pdev->dev), + "amd,pensando-elba-syscon"); + if (IS_ERR(syscon)) + return dev_err_probe(&pdev->dev, PTR_ERR(syscon), + "syscon regmap lookup failed\n"); + + dwsmmio->priv = syscon; + dwsmmio->dws.set_cs = dw_spi_elba_set_cs; + + return 0; +} + static int dw_spi_mmio_probe(struct platform_device *pdev) { int (*init_func)(struct platform_device *pdev, @@ -350,6 +407,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = { { .compatible = "intel,thunderbay-ssi", .data = dw_spi_intel_init}, { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init}, { .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init}, + { .compatible = "amd,pensando-elba-spi", .data = dw_spi_elba_init}, { /* end of table */} }; MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); |