[PATCH 1/2] spi: spi-fsl-dspi: replace regmap R/W with internal implementation

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

 



From: Yuan Yao <yao.yuan@xxxxxxx>

The qSPI controller's endian is independent of the CPU core's endian.

For eg, Core on NXP LS1043A SoC is little endian but DSPI is big endian
whereas Core on LS2080A SoC is little endian and DSPI also is little
endian on the same core.

At first we use regmap to cover this issue.
But the regmap is designed too large and complex.
The issue for regmap often effect the DSPI's stability.

DSPI driver just only need a effective way to R/W the controller register
with BE or LE mode.

So it's better to packaging a sample function.
This will make the DSPI driver more stability and high effective.

Signed-off-by: Yuan Yao <yao.yuan@xxxxxxx>
---
 drivers/spi/spi-fsl-dspi.c | 99 +++++++++++++++++++++++++++-------------------
 1 file changed, 59 insertions(+), 40 deletions(-)

diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 9e9dadb..9a61572 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -27,7 +27,6 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
-#include <linux/regmap.h>
 #include <linux/sched.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
@@ -143,7 +142,7 @@ struct fsl_dspi {
 	struct spi_master	*master;
 	struct platform_device	*pdev;
 
-	struct regmap		*regmap;
+	void __iomem		*iobase;
 	int			irq;
 	struct clk		*clk;
 
@@ -165,13 +164,46 @@ struct fsl_dspi {
 	u32			waitflags;
 
 	u32			spi_tcnt;
+	bool			big_endian;
 };
 
+/*
+ * R/W functions for big- or little-endian registers:
+ * The qSPI controller's endian is independent of the CPU core's endian.
+ */
+static void dspi_writel(struct fsl_dspi *d, u32 val, u32 offset)
+{
+	if (d->big_endian)
+		iowrite32be(val, d->iobase + offset);
+	else
+		iowrite32(val, d->iobase + offset);
+}
+
+static u32 dspi_readl(struct fsl_dspi *d, u32 offset)
+{
+	if (d->big_endian)
+		return ioread32be(d->iobase + offset);
+	else
+		return ioread32(d->iobase + offset);
+}
+
+static void dspi_updatel(struct fsl_dspi *d, u32 mask, u32 val, u32 offset)
+{
+	u32 tmp, orig;
+
+	orig = dspi_readl(d, offset);
+
+	tmp = orig & ~mask;
+	tmp |= val & mask;
+
+	dspi_writel(d, tmp, offset);
+}
+
 static inline int is_double_byte_mode(struct fsl_dspi *dspi)
 {
 	unsigned int val;
 
-	regmap_read(dspi->regmap, SPI_CTAR(0), &val);
+	val = dspi_readl(dspi, SPI_CTAR(0));
 
 	return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
 }
@@ -270,7 +302,7 @@ static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word)
 	u16 d;
 	unsigned int val;
 
-	regmap_read(dspi->regmap, SPI_POPR, &val);
+	val = dspi_readl(dspi, SPI_POPR);
 	d = SPI_POPR_RXDATA(val);
 
 	if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
@@ -294,8 +326,8 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
 		 */
 		if (tx_word && (dspi->len == 1)) {
 			dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-			regmap_update_bits(dspi->regmap, SPI_CTAR(0),
-					SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
+			dspi_updatel(dspi, SPI_FRAME_BITS_MASK,
+					SPI_FRAME_BITS(8), SPI_CTAR(0));
 			tx_word = 0;
 		}
 
@@ -309,7 +341,7 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
 		} else if (tx_word && (dspi->len == 1))
 			dspi_pushr |= SPI_PUSHR_EOQ;
 
-		regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
+		dspi_writel(dspi, dspi_pushr, SPI_PUSHR);
 
 		tx_count++;
 	}
@@ -343,8 +375,8 @@ static int dspi_tcfq_write(struct fsl_dspi *dspi)
 
 	if (tx_word && (dspi->len == 1)) {
 		dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-		regmap_update_bits(dspi->regmap, SPI_CTAR(0),
-				SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
+		dspi_updatel(dspi, SPI_FRAME_BITS_MASK,
+				SPI_FRAME_BITS(8), SPI_CTAR(0));
 		tx_word = 0;
 	}
 
@@ -353,7 +385,7 @@ static int dspi_tcfq_write(struct fsl_dspi *dspi)
 	if ((dspi->cs_change) && (!dspi->len))
 		dspi_pushr &= ~SPI_PUSHR_CONT;
 
-	regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
+	dspi_writel(dspi, dspi_pushr, SPI_PUSHR);
 
 	return tx_word + 1;
 }
@@ -378,7 +410,7 @@ static int dspi_transfer_one_message(struct spi_master *master,
 	enum dspi_trans_mode trans_mode;
 	u32 spi_tcr;
 
-	regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
+	spi_tcr = dspi_readl(dspi, SPI_TCR);
 	dspi->spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
 
 	message->actual_length = 0;
@@ -407,21 +439,19 @@ static int dspi_transfer_one_message(struct spi_master *master,
 		if (!dspi->tx)
 			dspi->dataflags |= TRAN_STATE_TX_VOID;
 
-		regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
-		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);
+		dspi_writel(dspi, dspi->cur_chip->mcr_val, SPI_MCR);
+		dspi_updatel(dspi, SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
+				   SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF, SPI_MCR);
+		dspi_writel(dspi, dspi->cur_chip->ctar_val, SPI_CTAR(0));
 
 		trans_mode = dspi->devtype_data->trans_mode;
 		switch (trans_mode) {
 		case DSPI_EOQ_MODE:
-			regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
+			dspi_writel(dspi, SPI_RSER_EOQFE, SPI_RSER);
 			dspi_eoq_write(dspi);
 			break;
 		case DSPI_TCFQ_MODE:
-			regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE);
+			dspi_writel(dspi, SPI_RSER_TCFQE, SPI_RSER);
 			dspi_tcfq_write(dspi);
 			break;
 		default:
@@ -525,14 +555,14 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
 	u32 spi_tcnt, tcnt_diff;
 	int tx_word;
 
-	regmap_read(dspi->regmap, SPI_SR, &spi_sr);
-	regmap_write(dspi->regmap, SPI_SR, spi_sr);
+	spi_sr = dspi_readl(dspi, SPI_SR);
+	dspi_writel(dspi, spi_sr, SPI_SR);
 
 
 	if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) {
 		tx_word = is_double_byte_mode(dspi);
 
-		regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
+		spi_tcr = dspi_readl(dspi, SPI_TCR);
 		spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
 		/*
 		 * The width of SPI Transfer Counter in SPI_TCR is 16bits,
@@ -569,10 +599,10 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
 
 		if (!dspi->len) {
 			if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) {
-				regmap_update_bits(dspi->regmap,
-						   SPI_CTAR(0),
-						   SPI_FRAME_BITS_MASK,
-						   SPI_FRAME_BITS(16));
+				dspi_updatel(dspi,
+					     SPI_FRAME_BITS_MASK,
+					     SPI_FRAME_BITS(16),
+					     SPI_CTAR(0));
 				dspi->dataflags &= ~TRAN_STATE_WORD_ODD_NUM;
 			}
 
@@ -636,13 +666,6 @@ static int dspi_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
 
-static const struct regmap_config dspi_regmap_config = {
-	.reg_bits = 32,
-	.val_bits = 32,
-	.reg_stride = 4,
-	.max_register = 0x88,
-};
-
 static int dspi_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -700,13 +723,7 @@ static int dspi_probe(struct platform_device *pdev)
 		goto out_master_put;
 	}
 
-	dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
-						&dspi_regmap_config);
-	if (IS_ERR(dspi->regmap)) {
-		dev_err(&pdev->dev, "failed to init regmap: %ld\n",
-				PTR_ERR(dspi->regmap));
-		return PTR_ERR(dspi->regmap);
-	}
+	dspi->iobase = base;
 
 	dspi->irq = platform_get_irq(pdev, 0);
 	if (dspi->irq < 0) {
@@ -730,6 +747,8 @@ static int dspi_probe(struct platform_device *pdev)
 	}
 	clk_prepare_enable(dspi->clk);
 
+	dspi->big_endian = of_property_read_bool(np, "big-endian");
+
 	master->max_speed_hz =
 		clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
 
-- 
2.1.0.27.g96db324

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux