[PATCH 4/5] spi: Add fsl-dspi driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.
+
 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



[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux