On Wed, Mar 25, 2020 at 1:36 AM Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> wrote: > > The fsl-dspi is found on Freescale Vybrid, Coldfire and Layerscape SoCs. > This adds the driver based on the Linux driver as of v5.5. Coldfire > support has been dropped as it's rather obsolete. Vybrid support has > been dropped because it needs the DMA engine support we do not have in > barebox. What's left is support for Layerscape where this driver has > been tested on. > > Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > --- > drivers/spi/Kconfig | 7 + > drivers/spi/Makefile | 1 + > drivers/spi/spi-fsl-dspi.c | 655 +++++++++++++++++++++++++++++++++++++ > 3 files changed, 663 insertions(+) > create mode 100644 drivers/spi/spi-fsl-dspi.c > > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig > index 3758a0fad9..96235a1be2 100644 > --- a/drivers/spi/Kconfig > +++ b/drivers/spi/Kconfig > @@ -44,6 +44,13 @@ config DRIVER_SPI_FSL_QUADSPI > This controller does not support generic SPI messages. It only > supports the high-level SPI memory interface. > > +config SPI_FSL_DSPI > + bool "Freescale DSPI controller" > + depends on ARCH_LAYERSCAPE > + help > + This enables support for the Freescale DSPI controller in master > + mode. VF610, LS1021A and ColdFire platforms uses the controller. Sorry I didn't notice this patch earlier. Maybe we should drop the wording about VF610 here since there a separate DSPI driver for Vybrid as well: https://git.pengutronix.de/cgit/barebox/tree/drivers/spi/Kconfig?h=next#n90 > + > config DRIVER_SPI_GPIO > bool "GPIO SPI Master driver" > depends on GPIOLIB > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile > index 75a89ef38e..908d514a01 100644 > --- a/drivers/spi/Makefile > +++ b/drivers/spi/Makefile > @@ -8,6 +8,7 @@ obj-$(CONFIG_DRIVER_SPI_MVEBU) += mvebu_spi.o > obj-$(CONFIG_DRIVER_SPI_MXS) += mxs_spi.o > obj-$(CONFIG_DRIVER_SPI_ALTERA) += altera_spi.o > obj-$(CONFIG_DRIVER_SPI_ATMEL) += atmel_spi.o > +obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o > obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o > obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o > obj-$(CONFIG_DRIVER_SPI_DSPI) += dspi_spi.o > diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c > new file mode 100644 > index 0000000000..a7ceb854e9 > --- /dev/null > +++ b/drivers/spi/spi-fsl-dspi.c > @@ -0,0 +1,655 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +// > +// Copyright 2013 Freescale Semiconductor, Inc. > +// > +// Freescale DSPI driver > +// This file contains a driver for the Freescale DSPI > + > +#include <common.h> > +#include <driver.h> > +#include <errno.h> > +#include <init.h> > +#include <io.h> > +#include <regmap.h> > +#include <spi/spi.h> > +#include <linux/clk.h> > +#include <linux/math64.h> > + > +#define DRIVER_NAME "fsl-dspi" > + > +#define DSPI_FIFO_SIZE 4 > +#define DSPI_DMA_BUFSIZE (DSPI_FIFO_SIZE * 1024) > + > +#define SPI_MCR 0x00 > +#define SPI_MCR_MASTER BIT(31) > +#define SPI_MCR_PCSIS (0x3F << 16) > +#define SPI_MCR_CLR_TXF BIT(11) > +#define SPI_MCR_CLR_RXF BIT(10) > +#define SPI_MCR_XSPI BIT(3) > + > +#define SPI_TCR 0x08 > +#define SPI_TCR_GET_TCNT(x) (((x) & GENMASK(31, 16)) >> 16) > + > +#define SPI_CTAR(x) (0x0c + (((x) & GENMASK(1, 0)) * 4)) > +#define SPI_CTAR_FMSZ(x) (((x) << 27) & GENMASK(30, 27)) > +#define SPI_CTAR_CPOL BIT(26) > +#define SPI_CTAR_CPHA BIT(25) > +#define SPI_CTAR_LSBFE BIT(24) > +#define SPI_CTAR_PCSSCK(x) (((x) << 22) & GENMASK(23, 22)) > +#define SPI_CTAR_PASC(x) (((x) << 20) & GENMASK(21, 20)) > +#define SPI_CTAR_PDT(x) (((x) << 18) & GENMASK(19, 18)) > +#define SPI_CTAR_PBR(x) (((x) << 16) & GENMASK(17, 16)) > +#define SPI_CTAR_CSSCK(x) (((x) << 12) & GENMASK(15, 12)) > +#define SPI_CTAR_ASC(x) (((x) << 8) & GENMASK(11, 8)) > +#define SPI_CTAR_DT(x) (((x) << 4) & GENMASK(7, 4)) > +#define SPI_CTAR_BR(x) ((x) & GENMASK(3, 0)) > +#define SPI_CTAR_SCALE_BITS 0xf > + > +#define SPI_CTAR0_SLAVE 0x0c > + > +#define SPI_SR 0x2c > +#define SPI_SR_TCFQF BIT(31) > +#define SPI_SR_EOQF BIT(28) > +#define SPI_SR_TFUF BIT(27) > +#define SPI_SR_TFFF BIT(25) > +#define SPI_SR_CMDTCF BIT(23) > +#define SPI_SR_SPEF BIT(21) > +#define SPI_SR_RFOF BIT(19) > +#define SPI_SR_TFIWF BIT(18) > +#define SPI_SR_RFDF BIT(17) > +#define SPI_SR_CMDFFF BIT(16) > +#define SPI_SR_CLEAR (SPI_SR_TCFQF | SPI_SR_EOQF | \ > + SPI_SR_TFUF | SPI_SR_TFFF | \ > + SPI_SR_CMDTCF | SPI_SR_SPEF | \ > + SPI_SR_RFOF | SPI_SR_TFIWF | \ > + SPI_SR_RFDF | SPI_SR_CMDFFF) > + > +#define SPI_RSER_TFFFE BIT(25) > +#define SPI_RSER_TFFFD BIT(24) > +#define SPI_RSER_RFDFE BIT(17) > +#define SPI_RSER_RFDFD BIT(16) > + > +#define SPI_RSER 0x30 > +#define SPI_RSER_TCFQE BIT(31) > +#define SPI_RSER_EOQFE BIT(28) > + > +#define SPI_PUSHR 0x34 > +#define SPI_PUSHR_CMD_CONT BIT(15) > +#define SPI_PUSHR_CMD_CTAS(x) (((x) << 12 & GENMASK(14, 12))) > +#define SPI_PUSHR_CMD_EOQ BIT(11) > +#define SPI_PUSHR_CMD_CTCNT BIT(10) > +#define SPI_PUSHR_CMD_PCS(x) (BIT(x) & GENMASK(5, 0)) > + > +#define SPI_PUSHR_SLAVE 0x34 > + > +#define SPI_POPR 0x38 > + > +#define SPI_TXFR0 0x3c > +#define SPI_TXFR1 0x40 > +#define SPI_TXFR2 0x44 > +#define SPI_TXFR3 0x48 > +#define SPI_RXFR0 0x7c > +#define SPI_RXFR1 0x80 > +#define SPI_RXFR2 0x84 > +#define SPI_RXFR3 0x88 > + > +#define SPI_CTARE(x) (0x11c + (((x) & GENMASK(1, 0)) * 4)) > +#define SPI_CTARE_FMSZE(x) (((x) & 0x1) << 16) > +#define SPI_CTARE_DTCP(x) ((x) & 0x7ff) > + > +#define SPI_SREX 0x13c > + > +#define SPI_FRAME_BITS(bits) SPI_CTAR_FMSZ((bits) - 1) > +#define SPI_FRAME_EBITS(bits) SPI_CTARE_FMSZE(((bits) - 1) >> 4) > + > +/* Register offsets for regmap_pushr */ > +#define PUSHR_CMD 0x0 > +#define PUSHR_TX 0x2 > + > +#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000) > + > +struct chip_data { > + u32 ctar_val; > + u16 void_write_data; > +}; > + > +struct fsl_dspi_devtype_data { > + u8 max_clock_factor; > + bool ptp_sts_supported; > + bool xspi_mode; > +}; > + > +static const struct fsl_dspi_devtype_data ls1021a_v1_data = { > + .max_clock_factor = 8, > + .ptp_sts_supported = true, > + .xspi_mode = true, > +}; > + > +static const struct fsl_dspi_devtype_data ls2085a_data = { > + .max_clock_factor = 8, > + .ptp_sts_supported = true, > +}; > + > +struct fsl_dspi { > + struct spi_controller ctlr; > + struct device_d *dev; > + > + struct regmap *regmap; > + struct regmap *regmap_pushr; > + int irq; > + struct clk *clk; > + > + struct spi_transfer *cur_transfer; > + struct spi_message *cur_msg; > + struct chip_data *cur_chip; > + size_t progress; > + size_t len; > + const void *tx; > + void *rx; > + void *rx_end; > + u16 void_write_data; > + u16 tx_cmd; > + u8 bits_per_word; > + u8 bytes_per_word; > + const struct fsl_dspi_devtype_data *devtype_data; > +}; > + > +static u32 dspi_pop_tx(struct fsl_dspi *dspi) > +{ > + u32 txdata = 0; > + > + if (dspi->tx) { > + if (dspi->bytes_per_word == 1) > + txdata = *(u8 *)dspi->tx; > + else if (dspi->bytes_per_word == 2) > + txdata = *(u16 *)dspi->tx; > + else /* dspi->bytes_per_word == 4 */ > + txdata = *(u32 *)dspi->tx; > + dspi->tx += dspi->bytes_per_word; > + } > + dspi->len -= dspi->bytes_per_word; > + return txdata; > +} > + > +static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi) > +{ > + u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi); > + > + if (dspi->len > 0) > + cmd |= SPI_PUSHR_CMD_CONT; > + return cmd << 16 | data; > +} > + > +static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata) > +{ > + if (!dspi->rx) > + return; > + > + /* Mask off undefined bits */ > + rxdata &= (1 << dspi->bits_per_word) - 1; > + > + if (dspi->bytes_per_word == 1) > + *(u8 *)dspi->rx = rxdata; > + else if (dspi->bytes_per_word == 2) > + *(u16 *)dspi->rx = rxdata; > + else /* dspi->bytes_per_word == 4 */ > + *(u32 *)dspi->rx = rxdata; > + dspi->rx += dspi->bytes_per_word; > +} > + > +static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, > + unsigned long clkrate) > +{ > + /* Valid baud rate pre-scaler values */ > + int pbr_tbl[4] = {2, 3, 5, 7}; > + int brs[16] = { 2, 4, 6, 8, > + 16, 32, 64, 128, > + 256, 512, 1024, 2048, > + 4096, 8192, 16384, 32768 }; > + int scale_needed, scale, minscale = INT_MAX; > + int i, j; > + > + scale_needed = clkrate / speed_hz; > + if (clkrate % speed_hz) > + scale_needed++; > + > + for (i = 0; i < ARRAY_SIZE(brs); i++) > + for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) { > + scale = brs[i] * pbr_tbl[j]; > + if (scale >= scale_needed) { > + if (scale < minscale) { > + minscale = scale; > + *br = i; > + *pbr = j; > + } > + break; > + } > + } > + > + if (minscale == INT_MAX) { > + pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld, we use the max prescaler value.\n", > + speed_hz, clkrate); > + *pbr = ARRAY_SIZE(pbr_tbl) - 1; > + *br = ARRAY_SIZE(brs) - 1; > + } > +} > + > +static void ns_delay_scale(char *psc, char *sc, int delay_ns, > + unsigned long clkrate) > +{ > + int scale_needed, scale, minscale = INT_MAX; > + int pscale_tbl[4] = {1, 3, 5, 7}; > + u32 remainder; > + int i, j; > + > + scale_needed = div_u64_rem((u64)delay_ns * clkrate, NSEC_PER_SEC, > + &remainder); > + if (remainder) > + scale_needed++; > + > + for (i = 0; i < ARRAY_SIZE(pscale_tbl); i++) > + for (j = 0; j <= SPI_CTAR_SCALE_BITS; j++) { > + scale = pscale_tbl[i] * (2 << j); > + if (scale >= scale_needed) { > + if (scale < minscale) { > + minscale = scale; > + *psc = i; > + *sc = j; > + } > + break; > + } > + } > + > + if (minscale == INT_MAX) { > + pr_warn("Cannot find correct scale values for %dns delay at clkrate %ld, using max prescaler value", > + delay_ns, clkrate); > + *psc = ARRAY_SIZE(pscale_tbl) - 1; > + *sc = SPI_CTAR_SCALE_BITS; > + } > +} > + > +static void fifo_write(struct fsl_dspi *dspi) > +{ > + regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi)); > +} > + > +static void cmd_fifo_write(struct fsl_dspi *dspi) > +{ > + u16 cmd = dspi->tx_cmd; > + > + if (dspi->len > 0) > + cmd |= SPI_PUSHR_CMD_CONT; > + regmap_write(dspi->regmap_pushr, PUSHR_CMD, cmd); > +} > + > +static void tx_fifo_write(struct fsl_dspi *dspi, u16 txdata) > +{ > + regmap_write(dspi->regmap_pushr, PUSHR_TX, txdata); > +} > + > +static void dspi_tcfq_write(struct fsl_dspi *dspi) > +{ > + /* Clear transfer count */ > + dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT; > + > + if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) { > + /* Write the CMD FIFO entry first, and then the two > + * corresponding TX FIFO entries. > + */ > + u32 data = dspi_pop_tx(dspi); > + > + cmd_fifo_write(dspi); > + tx_fifo_write(dspi, data & 0xFFFF); > + tx_fifo_write(dspi, data >> 16); > + } else { > + /* Write one entry to both TX FIFO and CMD FIFO > + * simultaneously. > + */ > + fifo_write(dspi); > + } > +} > + > +static u32 fifo_read(struct fsl_dspi *dspi) > +{ > + u32 rxdata = 0; > + > + regmap_read(dspi->regmap, SPI_POPR, &rxdata); > + return rxdata; > +} > + > +static void dspi_tcfq_read(struct fsl_dspi *dspi) > +{ > + dspi_push_rx(dspi, fifo_read(dspi)); > +} > + > +static int dspi_rxtx(struct fsl_dspi *dspi) > +{ > + struct spi_message *msg = dspi->cur_msg; > + u16 spi_tcnt; > + u32 spi_tcr; > + > + /* Get transfer counter (in number of SPI transfers). It was > + * reset to 0 when transfer(s) were started. > + */ > + regmap_read(dspi->regmap, SPI_TCR, &spi_tcr); > + spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr); > + /* Update total number of bytes that were transferred */ > + msg->actual_length += spi_tcnt * dspi->bytes_per_word; > + dspi->progress += spi_tcnt; > + > + dspi_tcfq_read(dspi); > + if (!dspi->len) > + /* Success! */ > + return 0; > + > + dspi_tcfq_write(dspi); > + > + return -EINPROGRESS; > +} > + > +static int dspi_poll(struct fsl_dspi *dspi) > +{ > + int tries = 1000; > + u32 spi_sr; > + > + do { > + regmap_read(dspi->regmap, SPI_SR, &spi_sr); > + regmap_write(dspi->regmap, SPI_SR, spi_sr); > + > + if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) > + break; > + udelay(1); > + } while (--tries); > + > + if (!tries) > + return -ETIMEDOUT; > + > + return dspi_rxtx(dspi); > +} > + > +static int dspi_transfer_one_message(struct spi_device *spi, > + struct spi_message *message) > +{ > + struct fsl_dspi *dspi = container_of(spi->master, struct fsl_dspi, ctlr); > + struct spi_transfer *transfer; > + int status = 0; > + > + message->actual_length = 0; > + > + list_for_each_entry(transfer, &message->transfers, transfer_list) { > + dspi->cur_transfer = transfer; > + dspi->cur_msg = message; > + dspi->cur_chip = spi->controller_data; > + /* Prepare command word for CMD FIFO */ > + dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) | > + SPI_PUSHR_CMD_PCS(spi->chip_select); > + if (list_is_last(&dspi->cur_transfer->transfer_list, > + &dspi->cur_msg->transfers)) { > + /* Leave PCS activated after last transfer when > + * cs_change is set. > + */ > + if (transfer->cs_change) > + dspi->tx_cmd |= SPI_PUSHR_CMD_CONT; > + } else { > + /* Keep PCS active between transfers in same message > + * when cs_change is not set, and de-activate PCS > + * between transfers in the same message when > + * cs_change is set. > + */ > + if (!transfer->cs_change) > + dspi->tx_cmd |= SPI_PUSHR_CMD_CONT; > + } > + > + dspi->void_write_data = dspi->cur_chip->void_write_data; > + > + dspi->tx = transfer->tx_buf; > + dspi->rx = transfer->rx_buf; > + dspi->rx_end = dspi->rx + transfer->len; > + dspi->len = transfer->len; > + dspi->progress = 0; > + /* Validated transfer specific frame size (defaults applied) */ > + dspi->bits_per_word = transfer->bits_per_word; > + > + if (transfer->bits_per_word <= 8) > + dspi->bytes_per_word = 1; > + else if (transfer->bits_per_word <= 16) > + dspi->bytes_per_word = 2; > + else > + dspi->bytes_per_word = 4; > + > + regmap_update_bits(dspi->regmap, SPI_MCR, > + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF, > + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF); > + regmap_write(dspi->regmap, SPI_CTAR(0), > + dspi->cur_chip->ctar_val | > + SPI_FRAME_BITS(transfer->bits_per_word)); > + if (dspi->devtype_data->xspi_mode) > + regmap_write(dspi->regmap, SPI_CTARE(0), > + SPI_FRAME_EBITS(transfer->bits_per_word) | > + SPI_CTARE_DTCP(1)); > + > + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE); > + dspi_tcfq_write(dspi); > + > + do { > + status = dspi_poll(dspi); > + } while (status == -EINPROGRESS); > + > + if (status) > + dev_err(dspi->dev, > + "Waiting for transfer to complete failed!\n"); > + } > + > + message->status = status; > + > + return status; > +} > + > +static int dspi_setup(struct spi_device *spi) > +{ > + struct fsl_dspi *dspi = container_of(spi->master, struct fsl_dspi, ctlr); > + unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0; > + u32 cs_sck_delay = 0, sck_cs_delay = 0; > + unsigned char pasc = 0, asc = 0; > + struct chip_data *chip; > + unsigned long clkrate; > + > + /* Only alloc on first setup */ > + chip = spi->controller_data; > + if (chip == NULL) { > + chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); > + if (!chip) > + return -ENOMEM; > + } > + > + of_property_read_u32(spi->dev.device_node, "fsl,spi-cs-sck-delay", > + &cs_sck_delay); > + > + of_property_read_u32(spi->dev.device_node, "fsl,spi-sck-cs-delay", > + &sck_cs_delay); > + > + chip->void_write_data = 0; > + > + clkrate = clk_get_rate(dspi->clk); > + hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate); > + > + /* Set PCS to SCK delay scale values */ > + ns_delay_scale(&pcssck, &cssck, cs_sck_delay, clkrate); > + > + /* Set After SCK delay scale values */ > + ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate); > + > + chip->ctar_val = 0; > + if (spi->mode & SPI_CPOL) > + chip->ctar_val |= SPI_CTAR_CPOL; > + if (spi->mode & SPI_CPHA) > + chip->ctar_val |= SPI_CTAR_CPHA; > + > + chip->ctar_val |= SPI_CTAR_PCSSCK(pcssck) | > + SPI_CTAR_CSSCK(cssck) | > + SPI_CTAR_PASC(pasc) | > + SPI_CTAR_ASC(asc) | > + SPI_CTAR_PBR(pbr) | > + SPI_CTAR_BR(br); > + > + if (spi->mode & SPI_LSB_FIRST) > + chip->ctar_val |= SPI_CTAR_LSBFE; > + > + spi->controller_data = chip; > + > + return 0; > +} > + > +static void dspi_cleanup(struct spi_device *spi) > +{ > + struct chip_data *chip = spi->controller_data; > + > + dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n", > + spi->controller->bus_num, spi->chip_select); > + > + kfree(chip); > +} > + > +static const struct of_device_id fsl_dspi_dt_ids[] = { > + { .compatible = "fsl,ls1021a-v1.0-dspi", .data = &ls1021a_v1_data, }, > + { .compatible = "fsl,ls2085a-dspi", .data = &ls2085a_data, }, > + { /* sentinel */ } > +}; > + > +static const struct regmap_config dspi_regmap_config = { > + .reg_bits = 32, > + .val_bits = 32, > + .reg_stride = 4, > + .max_register = 0x88, > +}; > + > +static const struct regmap_config dspi_xspi_regmap_config[] = { > + { > + .reg_bits = 32, > + .val_bits = 32, > + .reg_stride = 4, > + .max_register = 0x13c, > + }, { > + .name = "pushr", > + .reg_bits = 16, > + .val_bits = 16, > + .reg_stride = 2, > + .max_register = 0x2, > + }, > +}; > + > +static void dspi_init(struct fsl_dspi *dspi) > +{ > + unsigned int mcr = SPI_MCR_PCSIS; > + > + if (dspi->devtype_data->xspi_mode) > + mcr |= SPI_MCR_XSPI; > + mcr |= SPI_MCR_MASTER; > + > + regmap_write(dspi->regmap, SPI_MCR, mcr); > + regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR); > + if (dspi->devtype_data->xspi_mode) > + regmap_write(dspi->regmap, SPI_CTARE(0), > + SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1)); > +} > + > +static int dspi_probe(struct device_d *dev) > +{ > + struct device_node *np = dev->device_node; > + const struct regmap_config *regmap_config; > + struct spi_master *master; > + int ret, cs_num, bus_num = -1; > + struct fsl_dspi *dspi; > + struct resource *res; > + void __iomem *base; > + > + dspi = xzalloc(sizeof(*dspi)); > + > + dspi->dev = dev; > + master = &dspi->ctlr; > + > + master->dev = dev; > + master->setup = dspi_setup; > + master->transfer = dspi_transfer_one_message; > + > + master->cleanup = dspi_cleanup; > + > + ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num); > + if (ret < 0) { > + dev_err(dev, "can't get spi-num-chipselects\n"); > + goto out_ctlr_put; > + } > + master->num_chipselect = cs_num; > + > + of_property_read_u32(np, "bus-num", &bus_num); > + master->bus_num = bus_num; > + > + ret = dev_get_drvdata(dev, (const void **)&dspi->devtype_data); > + if (ret) > + return -ENODEV; > + > + res = dev_request_mem_resource(dev, 0); > + if (IS_ERR(res)) > + return PTR_ERR(res); > + > + base = IOMEM(res->start); > + > + if (dspi->devtype_data->xspi_mode) > + regmap_config = &dspi_xspi_regmap_config[0]; > + else > + regmap_config = &dspi_regmap_config; > + > + dspi->regmap = regmap_init_mmio(dev, base, regmap_config); > + if (IS_ERR(dspi->regmap)) { > + dev_err(dev, "failed to init regmap: %ld\n", > + PTR_ERR(dspi->regmap)); > + ret = PTR_ERR(dspi->regmap); > + goto out_ctlr_put; > + } > + > + if (dspi->devtype_data->xspi_mode) { > + dspi->regmap_pushr = regmap_init_mmio( > + dev, base + SPI_PUSHR, > + &dspi_xspi_regmap_config[1]); > + if (IS_ERR(dspi->regmap_pushr)) { > + dev_err(dev, > + "failed to init pushr regmap: %ld\n", > + PTR_ERR(dspi->regmap_pushr)); > + ret = PTR_ERR(dspi->regmap_pushr); > + goto out_ctlr_put; > + } > + } > + > + dspi->clk = clk_get(dev, "dspi"); > + if (IS_ERR(dspi->clk)) { > + ret = PTR_ERR(dspi->clk); > + dev_err(dev, "unable to get clock\n"); > + goto out_ctlr_put; > + } > + ret = clk_enable(dspi->clk); > + if (ret) > + goto out_ctlr_put; > + > + dspi_init(dspi); > + > + ret = spi_register_master(master); > + if (ret != 0) { > + dev_err(dev, "Problem registering DSPI ctlr\n"); > + goto out_clk_put; > + } > + > + return ret; > + > +out_clk_put: > + clk_disable(dspi->clk); > +out_ctlr_put: > + > + return ret; > +} > + > +static struct driver_d fsl_dspi_driver = { > + .name = "fsl-dspi", > + .probe = dspi_probe, > + .of_compatible = DRV_OF_COMPAT(fsl_dspi_dt_ids), > +}; > +coredevice_platform_driver(fsl_dspi_driver); > -- > 2.26.0.rc2 > > > _______________________________________________ > barebox mailing list > barebox@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/barebox _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox