linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support
@ 2019-01-07  7:47 Clark Wang
  2019-01-07  7:47 ` [PATCH 1/8] spi: lpspi: Add i.MX8 boards support for lpspi Clark Wang
                   ` (7 more replies)
  0 siblings, 8 replies; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

Hi Mark,

As subject, these fucntions support, including:
 - Support i.MX8 series boards;
 - Support cs-gpio fucntion;
 - Support DMA mode for both master and salve mode.

>From patch 3 to 6 are some bug-fix for PIO mode. In order to avoid data loss
and improve data transmission stability.

These are some notes about cs-gpio and DMA:
 - cs-gpio:
   Because LPSPI driver don't use default implementation of
   transfer_one_message(), I do the cs-gpio control way as same as the way
   used in spi core;

 - DMA:
   Any frame length longer than half txfifosize will be sent by DMA mode.
   For now, there are some limits:
      1. The maximum transfer speed in master mode depends on the slave device,
         at least 40MHz on i.MX8 series (tested by spi-nor on 8qm-lpddr4-arm2
         base board);
      2. The maximum transfer speed in slave mode is 15MHz(i.MX7ULP),
         22MHz(i.MX8 series).

Clark Wang (8):
  spi: lpspi: Add i.MX8 boards support for lpspi
  spi: lpspi: enable runtime pm for lpspi
  spi: lpspi: Improve the stability of lpspi data transmission
  spi: lpspi: Fix wrong transmission when don't use CONT
  spi: lpspi: Fix CLK pin becomes low before one transfer
  spi: lpspi: add the error info of transfer speed setting
  spi: lpspi: Add cs-gpio support
  spi: lpspi: add dma mode support

 drivers/spi/spi-fsl-lpspi.c | 612 ++++++++++++++++++++++++++++++++----
 1 file changed, 552 insertions(+), 60 deletions(-)

-- 
2.17.1

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/8] spi: lpspi: Add i.MX8 boards support for lpspi
  2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
@ 2019-01-07  7:47 ` Clark Wang
  2019-01-07 15:15   ` Mark Brown
  2019-01-07  7:47 ` [PATCH 2/8] spi: lpspi: enable runtime pm " Clark Wang
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

Add both ipg and per clock for lpspi to support i.MX8QM/QXP boards.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
---
 drivers/spi/spi-fsl-lpspi.c | 52 +++++++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 08dcc3c22e88..5802f188051b 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -80,7 +80,8 @@ struct lpspi_config {
 struct fsl_lpspi_data {
 	struct device *dev;
 	void __iomem *base;
-	struct clk *clk;
+	struct clk *clk_ipg;
+	struct clk *clk_per;
 	bool is_slave;
 
 	void *rx_buf;
@@ -147,8 +148,19 @@ static int lpspi_prepare_xfer_hardware(struct spi_controller *controller)
 {
 	struct fsl_lpspi_data *fsl_lpspi =
 				spi_controller_get_devdata(controller);
+	int ret;
+
+	ret = clk_prepare_enable(fsl_lpspi->clk_ipg);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(fsl_lpspi->clk_per);
+	if (ret) {
+		clk_disable_unprepare(fsl_lpspi->clk_ipg);
+		return ret;
+	}
 
-	return clk_prepare_enable(fsl_lpspi->clk);
+	return 0;
 }
 
 static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
@@ -156,7 +168,8 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
 	struct fsl_lpspi_data *fsl_lpspi =
 				spi_controller_get_devdata(controller);
 
-	clk_disable_unprepare(fsl_lpspi->clk);
+	clk_disable_unprepare(fsl_lpspi->clk_ipg);
+	clk_disable_unprepare(fsl_lpspi->clk_per);
 
 	return 0;
 }
@@ -249,7 +262,7 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
 	unsigned int perclk_rate, scldiv;
 	u8 prescale;
 
-	perclk_rate = clk_get_rate(fsl_lpspi->clk);
+	perclk_rate = clk_get_rate(fsl_lpspi->clk_per);
 	for (prescale = 0; prescale < 8; prescale++) {
 		scldiv = perclk_rate /
 			 (clkdivs[prescale] * config.speed_hz) - 2;
@@ -522,15 +535,30 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 		goto out_controller_put;
 	}
 
-	fsl_lpspi->clk = devm_clk_get(&pdev->dev, "ipg");
-	if (IS_ERR(fsl_lpspi->clk)) {
-		ret = PTR_ERR(fsl_lpspi->clk);
+	fsl_lpspi->clk_per = devm_clk_get(&pdev->dev, "per");
+	if (IS_ERR(fsl_lpspi->clk_per)) {
+		ret = PTR_ERR(fsl_lpspi->clk_per);
+		goto out_controller_put;
+	}
+
+	fsl_lpspi->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
+	if (IS_ERR(fsl_lpspi->clk_ipg)) {
+		ret = PTR_ERR(fsl_lpspi->clk_ipg);
+		goto out_controller_put;
+	}
+
+	ret = clk_prepare_enable(fsl_lpspi->clk_ipg);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"can't enable lpspi ipg clock, ret=%d\n", ret);
 		goto out_controller_put;
 	}
 
-	ret = clk_prepare_enable(fsl_lpspi->clk);
+	ret = clk_prepare_enable(fsl_lpspi->clk_per);
 	if (ret) {
-		dev_err(&pdev->dev, "can't enable lpspi clock, ret=%d\n", ret);
+		dev_err(&pdev->dev,
+			"can't enable lpspi per clock, ret=%d\n", ret);
+		clk_disable_unprepare(fsl_lpspi->clk_ipg);
 		goto out_controller_put;
 	}
 
@@ -538,7 +566,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 	fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
 	fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
 
-	clk_disable_unprepare(fsl_lpspi->clk);
+	clk_disable_unprepare(fsl_lpspi->clk_per);
+	clk_disable_unprepare(fsl_lpspi->clk_ipg);
 
 	ret = devm_spi_register_controller(&pdev->dev, controller);
 	if (ret < 0) {
@@ -560,7 +589,8 @@ static int fsl_lpspi_remove(struct platform_device *pdev)
 	struct fsl_lpspi_data *fsl_lpspi =
 				spi_controller_get_devdata(controller);
 
-	clk_disable_unprepare(fsl_lpspi->clk);
+	clk_disable_unprepare(fsl_lpspi->clk_per);
+	clk_disable_unprepare(fsl_lpspi->clk_ipg);
 
 	return 0;
 }
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/8] spi: lpspi: enable runtime pm for lpspi
  2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
  2019-01-07  7:47 ` [PATCH 1/8] spi: lpspi: Add i.MX8 boards support for lpspi Clark Wang
@ 2019-01-07  7:47 ` Clark Wang
  2019-01-07 15:16   ` Mark Brown
  2019-01-07  7:47 ` [PATCH 3/8] spi: lpspi: Improve the stability of lpspi data transmission Clark Wang
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

	From: Han Xu <han.xu@nxp.com>

	Enable the runtime power management for lpspi module.

Do some adaptation work from kernel 4.9 to 4.14.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Signed-off-by: Han Xu <han.xu@nxp.com>
Reviewed-by: Frank Li <frank.li@nxp.com>
---
 drivers/spi/spi-fsl-lpspi.c | 117 ++++++++++++++++++++++++++++--------
 1 file changed, 92 insertions(+), 25 deletions(-)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 5802f188051b..3e935db5ff02 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -16,7 +16,9 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
@@ -24,6 +26,8 @@
 
 #define DRIVER_NAME "fsl_lpspi"
 
+#define FSL_LPSPI_RPM_TIMEOUT 50 /* 50ms */
+
 /* i.MX7ULP LPSPI registers */
 #define IMX7ULP_VERID	0x0
 #define IMX7ULP_PARAM	0x4
@@ -150,13 +154,9 @@ static int lpspi_prepare_xfer_hardware(struct spi_controller *controller)
 				spi_controller_get_devdata(controller);
 	int ret;
 
-	ret = clk_prepare_enable(fsl_lpspi->clk_ipg);
-	if (ret)
-		return ret;
-
-	ret = clk_prepare_enable(fsl_lpspi->clk_per);
-	if (ret) {
-		clk_disable_unprepare(fsl_lpspi->clk_ipg);
+	ret = pm_runtime_get_sync(fsl_lpspi->dev);
+	if (ret < 0) {
+		dev_err(fsl_lpspi->dev, "failed to enable clock\n");
 		return ret;
 	}
 
@@ -168,8 +168,8 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
 	struct fsl_lpspi_data *fsl_lpspi =
 				spi_controller_get_devdata(controller);
 
-	clk_disable_unprepare(fsl_lpspi->clk_ipg);
-	clk_disable_unprepare(fsl_lpspi->clk_per);
+	pm_runtime_mark_last_busy(fsl_lpspi->dev);
+	pm_runtime_put_autosuspend(fsl_lpspi->dev);
 
 	return 0;
 }
@@ -476,6 +476,45 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
+int fsl_lpspi_runtime_resume(struct device *dev)
+{
+	struct fsl_lpspi_data *fsl_lpspi = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(fsl_lpspi->clk_per);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(fsl_lpspi->clk_ipg);
+	if (ret) {
+		clk_disable_unprepare(fsl_lpspi->clk_per);
+		return ret;
+	}
+
+	return 0;
+}
+
+int fsl_lpspi_runtime_suspend(struct device *dev)
+{
+	struct fsl_lpspi_data *fsl_lpspi = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(fsl_lpspi->clk_per);
+	clk_disable_unprepare(fsl_lpspi->clk_ipg);
+
+	return 0;
+}
+
+static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi)
+{
+	struct device *dev = fsl_lpspi->dev;
+
+	pm_runtime_enable(dev);
+	pm_runtime_set_autosuspend_delay(dev, FSL_LPSPI_RPM_TIMEOUT);
+	pm_runtime_use_autosuspend(dev);
+
+	return 0;
+}
+
 static int fsl_lpspi_probe(struct platform_device *pdev)
 {
 	struct fsl_lpspi_data *fsl_lpspi;
@@ -501,6 +540,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 
 	fsl_lpspi = spi_controller_get_devdata(controller);
 	fsl_lpspi->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, fsl_lpspi);
 	fsl_lpspi->is_slave = of_property_read_bool((&pdev->dev)->of_node,
 						    "spi-slave");
 
@@ -547,28 +587,21 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 		goto out_controller_put;
 	}
 
-	ret = clk_prepare_enable(fsl_lpspi->clk_ipg);
-	if (ret) {
-		dev_err(&pdev->dev,
-			"can't enable lpspi ipg clock, ret=%d\n", ret);
+	/* enable the clock */
+	ret = fsl_lpspi_init_rpm(fsl_lpspi);
+	if (ret)
 		goto out_controller_put;
-	}
 
-	ret = clk_prepare_enable(fsl_lpspi->clk_per);
-	if (ret) {
-		dev_err(&pdev->dev,
-			"can't enable lpspi per clock, ret=%d\n", ret);
-		clk_disable_unprepare(fsl_lpspi->clk_ipg);
-		goto out_controller_put;
+	ret = pm_runtime_get_sync(fsl_lpspi->dev);
+	if (ret < 0) {
+		dev_err(fsl_lpspi->dev, "failed to enable clock\n");
+		return ret;
 	}
 
 	temp = readl(fsl_lpspi->base + IMX7ULP_PARAM);
 	fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
 	fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
 
-	clk_disable_unprepare(fsl_lpspi->clk_per);
-	clk_disable_unprepare(fsl_lpspi->clk_ipg);
-
 	ret = devm_spi_register_controller(&pdev->dev, controller);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "spi_register_controller error.\n");
@@ -589,16 +622,50 @@ static int fsl_lpspi_remove(struct platform_device *pdev)
 	struct fsl_lpspi_data *fsl_lpspi =
 				spi_controller_get_devdata(controller);
 
-	clk_disable_unprepare(fsl_lpspi->clk_per);
-	clk_disable_unprepare(fsl_lpspi->clk_ipg);
+	pm_runtime_disable(fsl_lpspi->dev);
+
+	spi_master_put(controller);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fsl_lpspi_suspend(struct device *dev)
+{
+	int ret;
+
+	pinctrl_pm_select_sleep_state(dev);
+	ret = pm_runtime_force_suspend(dev);
+	return ret;
+}
+
+static int fsl_lpspi_resume(struct device *dev)
+{
+	int ret;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret) {
+		dev_err(dev, "Error in resume: %d\n", ret);
+		return ret;
+	}
+
+	pinctrl_pm_select_default_state(dev);
 
 	return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_lpspi_pm_ops = {
+	SET_RUNTIME_PM_OPS(fsl_lpspi_runtime_suspend,
+				fsl_lpspi_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume)
+};
 
 static struct platform_driver fsl_lpspi_driver = {
 	.driver = {
 		.name = DRIVER_NAME,
 		.of_match_table = fsl_lpspi_dt_ids,
+		.pm = &fsl_lpspi_pm_ops,
 	},
 	.probe = fsl_lpspi_probe,
 	.remove = fsl_lpspi_remove,
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/8] spi: lpspi: Improve the stability of lpspi data transmission
  2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
  2019-01-07  7:47 ` [PATCH 1/8] spi: lpspi: Add i.MX8 boards support for lpspi Clark Wang
  2019-01-07  7:47 ` [PATCH 2/8] spi: lpspi: enable runtime pm " Clark Wang
@ 2019-01-07  7:47 ` Clark Wang
  2019-01-07  7:47 ` [PATCH 4/8] spi: lpspi: Fix wrong transmission when don't use CONT Clark Wang
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

Use SR_TDF to judge if need to send data, and SR_FCF is to judge if
transmission end and to replace the waiting after transmission end.
This waiting has no actual meaning, for module will set the FCF
flag at the real end.

The changes of interrupt flag and ISR function reduce the times of
calling ISR. The use of the FCF flag improves the stability of the
data transmission. These two points generally improve the data
transfer speed of lpspi, especially when it is set to slave mode
it can support higher transfer speed of the host.

After making these changes, there is no need to use
fsl_lpspi_txfifo_empty(), so remove it.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
---
 drivers/spi/spi-fsl-lpspi.c | 61 ++++++++++++-------------------------
 1 file changed, 20 insertions(+), 41 deletions(-)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 3e935db5ff02..f32a2e0d7ae1 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -53,9 +53,11 @@
 #define CR_RST		BIT(1)
 #define CR_MEN		BIT(0)
 #define SR_TCF		BIT(10)
+#define SR_FCF		BIT(9)
 #define SR_RDF		BIT(1)
 #define SR_TDF		BIT(0)
 #define IER_TCIE	BIT(10)
+#define IER_FCIE	BIT(9)
 #define IER_RDIE	BIT(1)
 #define IER_TDIE	BIT(0)
 #define CFGR1_PCSCFG	BIT(27)
@@ -174,28 +176,10 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
 	return 0;
 }
 
-static int fsl_lpspi_txfifo_empty(struct fsl_lpspi_data *fsl_lpspi)
-{
-	u32 txcnt;
-	unsigned long orig_jiffies = jiffies;
-
-	do {
-		txcnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff;
-
-		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
-			dev_dbg(fsl_lpspi->dev, "txfifo empty timeout\n");
-			return -ETIMEDOUT;
-		}
-		cond_resched();
-
-	} while (txcnt);
-
-	return 0;
-}
-
 static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
 {
 	u8 txfifo_cnt;
+	u32 temp;
 
 	txfifo_cnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff;
 
@@ -206,9 +190,15 @@ static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
 		txfifo_cnt++;
 	}
 
-	if (!fsl_lpspi->remain && (txfifo_cnt < fsl_lpspi->txfifosize))
-		writel(0, fsl_lpspi->base + IMX7ULP_TDR);
-	else
+	if (txfifo_cnt < fsl_lpspi->txfifosize) {
+		if (!fsl_lpspi->is_slave) {
+			temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
+			temp &= ~TCR_CONTC;
+			writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
+		}
+
+		fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE);
+	} else
 		fsl_lpspi_intctrl(fsl_lpspi, IER_TDIE);
 }
 
@@ -404,12 +394,6 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller,
 	if (ret)
 		return ret;
 
-	ret = fsl_lpspi_txfifo_empty(fsl_lpspi);
-	if (ret)
-		return ret;
-
-	fsl_lpspi_read_rx_fifo(fsl_lpspi);
-
 	return 0;
 }
 
@@ -421,7 +405,6 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 	struct spi_device *spi = msg->spi;
 	struct spi_transfer *xfer;
 	bool is_first_xfer = true;
-	u32 temp;
 	int ret = 0;
 
 	msg->status = 0;
@@ -441,13 +424,6 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 	}
 
 complete:
-	if (!fsl_lpspi->is_slave) {
-		/* de-assert SS, then finalize current message */
-		temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
-		temp &= ~TCR_CONTC;
-		writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
-	}
-
 	msg->status = ret;
 	spi_finalize_current_message(controller);
 
@@ -456,20 +432,23 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 
 static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
 {
+	u32 temp_SR, temp_IER;
 	struct fsl_lpspi_data *fsl_lpspi = dev_id;
-	u32 temp;
 
+	temp_IER = readl(fsl_lpspi->base + IMX7ULP_IER);
 	fsl_lpspi_intctrl(fsl_lpspi, 0);
-	temp = readl(fsl_lpspi->base + IMX7ULP_SR);
+	temp_SR = readl(fsl_lpspi->base + IMX7ULP_SR);
 
 	fsl_lpspi_read_rx_fifo(fsl_lpspi);
 
-	if (temp & SR_TDF) {
+	if ((temp_SR & SR_TDF) && (temp_IER & IER_TDIE)) {
 		fsl_lpspi_write_tx_fifo(fsl_lpspi);
+		return IRQ_HANDLED;
+	}
 
-		if (!fsl_lpspi->remain)
+	if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) {
+		writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
 			complete(&fsl_lpspi->xfer_done);
-
 		return IRQ_HANDLED;
 	}
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 4/8] spi: lpspi: Fix wrong transmission when don't use CONT
  2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
                   ` (2 preceding siblings ...)
  2019-01-07  7:47 ` [PATCH 3/8] spi: lpspi: Improve the stability of lpspi data transmission Clark Wang
@ 2019-01-07  7:47 ` Clark Wang
  2019-01-07 18:59   ` Applied "spi: lpspi: Fix wrong transmission when don't use CONT" to the spi tree Mark Brown
  2019-01-07  7:47 ` [PATCH 5/8] spi: lpspi: Fix CLK pin becomes low before one transfer Clark Wang
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

Add judgment on SR_MBF and FSR_RXCOUNT.

In PIO mode, if don't use CONT to keep cs selected in one transfer, the
transfer will go wrong. FCIE will be set after one frame transfer
finish. If use CONT, the frame refer to the whole data in one transfer.
If don't use CONT, the frame refer to one byte of whole data. This will
cause the transfer ending early.

This patch add a register reading in isr function, it might lead to a
slight decrease in the max transmission speed in PIO mode.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
---
 drivers/spi/spi-fsl-lpspi.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index f32a2e0d7ae1..51c85cf0bd9f 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -52,6 +52,7 @@
 #define CR_RTF		BIT(8)
 #define CR_RST		BIT(1)
 #define CR_MEN		BIT(0)
+#define SR_MBF		BIT(24)
 #define SR_TCF		BIT(10)
 #define SR_FCF		BIT(9)
 #define SR_RDF		BIT(1)
@@ -65,6 +66,7 @@
 #define CFGR1_PCSPOL	BIT(8)
 #define CFGR1_NOSTALL	BIT(3)
 #define CFGR1_MASTER	BIT(0)
+#define FSR_RXCOUNT	(BIT(16)|BIT(17)|BIT(18))
 #define RSR_RXEMPTY	BIT(1)
 #define TCR_CPOL	BIT(31)
 #define TCR_CPHA	BIT(30)
@@ -446,6 +448,13 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
 		return IRQ_HANDLED;
 	}
 
+	if (temp_SR & SR_MBF ||
+	    readl(fsl_lpspi->base + IMX7ULP_FSR) & FSR_RXCOUNT) {
+		writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
+		fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE);
+		return IRQ_HANDLED;
+	}
+
 	if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) {
 		writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
 			complete(&fsl_lpspi->xfer_done);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 5/8] spi: lpspi: Fix CLK pin becomes low before one transfer
  2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
                   ` (3 preceding siblings ...)
  2019-01-07  7:47 ` [PATCH 4/8] spi: lpspi: Fix wrong transmission when don't use CONT Clark Wang
@ 2019-01-07  7:47 ` Clark Wang
  2019-01-07  7:47 ` [PATCH 6/8] spi: lpspi: add the error info of transfer speed setting Clark Wang
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

Remove Reset operation in fsl_lpspi_config(). This RST may cause both CLK
and CS pins go from high to low level under cs-gpio mode.
Add fsl_lpspi_reset() function after one message transfer to clear all
flags in use.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Reviewed-by: Fugang Duan <fugang.duan@nxp.com>
---
 drivers/spi/spi-fsl-lpspi.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 51c85cf0bd9f..84dcb9e176b8 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -281,10 +281,6 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
 	u32 temp;
 	int ret;
 
-	temp = CR_RST;
-	writel(temp, fsl_lpspi->base + IMX7ULP_CR);
-	writel(0, fsl_lpspi->base + IMX7ULP_CR);
-
 	if (!fsl_lpspi->is_slave) {
 		ret = fsl_lpspi_set_bitrate(fsl_lpspi);
 		if (ret)
@@ -375,6 +371,24 @@ static int fsl_lpspi_wait_for_completion(struct spi_controller *controller)
 	return 0;
 }
 
+static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi)
+{
+	u32 temp;
+
+	/* Disable all interrupt */
+	fsl_lpspi_intctrl(fsl_lpspi, 0);
+
+	/* W1C for all flags in SR */
+	temp = 0x3F << 8;
+	writel(temp, fsl_lpspi->base + IMX7ULP_SR);
+
+	/* Clear FIFO and disable module */
+	temp = CR_RRF | CR_RTF;
+	writel(temp, fsl_lpspi->base + IMX7ULP_CR);
+
+	return 0;
+}
+
 static int fsl_lpspi_transfer_one(struct spi_controller *controller,
 				  struct spi_device *spi,
 				  struct spi_transfer *t)
@@ -396,6 +410,8 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller,
 	if (ret)
 		return ret;
 
+	fsl_lpspi_reset(fsl_lpspi);
+
 	return 0;
 }
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 6/8] spi: lpspi: add the error info of transfer speed setting
  2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
                   ` (4 preceding siblings ...)
  2019-01-07  7:47 ` [PATCH 5/8] spi: lpspi: Fix CLK pin becomes low before one transfer Clark Wang
@ 2019-01-07  7:47 ` Clark Wang
  2019-01-09 12:43   ` Mark Brown
  2019-01-07  7:47 ` [PATCH 7/8] spi: lpspi: Add cs-gpio support Clark Wang
  2019-01-07  7:47 ` [PATCH 8/8] spi: lpspi: add dma mode support Clark Wang
  7 siblings, 1 reply; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

Add a error info when set a speed which greater than half of per-clk of
spi module.

The minimum SCK period is 2 cycles(CCR[SCKDIV]). So the maximum transfer
speed is half of spi per-clk.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
---
 drivers/spi/spi-fsl-lpspi.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 84dcb9e176b8..69635cde0e22 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -255,6 +255,13 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
 	u8 prescale;
 
 	perclk_rate = clk_get_rate(fsl_lpspi->clk_per);
+
+	if (config.speed_hz > perclk_rate / 2) {
+		dev_err(fsl_lpspi->dev,
+		      "per-clk should be at least two times of transfer speed");
+		return -EINVAL;
+	}
+
 	for (prescale = 0; prescale < 8; prescale++) {
 		scldiv = perclk_rate /
 			 (clkdivs[prescale] * config.speed_hz) - 2;
@@ -304,7 +311,7 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
 	return 0;
 }
 
-static void fsl_lpspi_setup_transfer(struct spi_device *spi,
+static int fsl_lpspi_setup_transfer(struct spi_device *spi,
 				     struct spi_transfer *t)
 {
 	struct fsl_lpspi_data *fsl_lpspi =
@@ -337,7 +344,7 @@ static void fsl_lpspi_setup_transfer(struct spi_device *spi,
 	else
 		fsl_lpspi->watermark = fsl_lpspi->txfifosize;
 
-	fsl_lpspi_config(fsl_lpspi);
+	return fsl_lpspi_config(fsl_lpspi);
 }
 
 static int fsl_lpspi_slave_abort(struct spi_controller *controller)
@@ -429,7 +436,10 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 	msg->actual_length = 0;
 
 	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-		fsl_lpspi_setup_transfer(spi, xfer);
+		ret = fsl_lpspi_setup_transfer(spi, xfer);
+		if (ret < 0)
+			goto complete;
+
 		fsl_lpspi_set_cmd(fsl_lpspi, is_first_xfer);
 
 		is_first_xfer = false;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 7/8] spi: lpspi: Add cs-gpio support
  2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
                   ` (5 preceding siblings ...)
  2019-01-07  7:47 ` [PATCH 6/8] spi: lpspi: add the error info of transfer speed setting Clark Wang
@ 2019-01-07  7:47 ` Clark Wang
  2019-01-09 12:33   ` Mark Brown
  2019-01-07  7:47 ` [PATCH 8/8] spi: lpspi: add dma mode support Clark Wang
  7 siblings, 1 reply; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

Add cs-gpio feature for LPSPI.
The cs line will be controlled in fsl_lpspi_transfe_one_msg() function.

Still support using the mode without cs-gpio. It depends on if attribute
cs-gpio has been configured in dts file.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
---
 drivers/spi/spi-fsl-lpspi.c | 89 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 69635cde0e22..83e15366b739 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -9,6 +9,7 @@
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -16,7 +17,9 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/spi-imx.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
@@ -28,6 +31,10 @@
 
 #define FSL_LPSPI_RPM_TIMEOUT 50 /* 50ms */
 
+#define LPSPI_CS_ACTIVE		1
+#define LPSPI_CS_INACTIVE	0
+#define LPSPI_CS_DELAY		100
+
 /* i.MX7ULP LPSPI registers */
 #define IMX7ULP_VERID	0x0
 #define IMX7ULP_PARAM	0x4
@@ -91,6 +98,7 @@ struct fsl_lpspi_data {
 	struct clk *clk_ipg;
 	struct clk *clk_per;
 	bool is_slave;
+	bool hascsgpio;
 
 	void *rx_buf;
 	const void *tx_buf;
@@ -106,6 +114,8 @@ struct fsl_lpspi_data {
 	struct completion xfer_done;
 
 	bool slave_aborted;
+
+	int chipselect[4];
 };
 
 static const struct of_device_id fsl_lpspi_dt_ids[] = {
@@ -178,6 +188,20 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
 	return 0;
 }
 
+static void fsl_lpspi_chipselect(struct spi_device *spi, bool enable)
+{
+	struct fsl_lpspi_data *fsl_lpspi =
+				spi_controller_get_devdata(spi->controller);
+	int gpio = fsl_lpspi->chipselect[spi->chip_select];
+
+	enable = (!!(spi->mode & SPI_CS_HIGH) == enable);
+
+	if (!gpio_is_valid(gpio))
+		return;
+
+	gpio_set_value_cansleep(gpio, enable);
+}
+
 static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
 {
 	u8 txfifo_cnt;
@@ -422,6 +446,25 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller,
 	return 0;
 }
 
+static int fsl_lpspi_setup(struct spi_device *spi)
+{
+	struct fsl_lpspi_data *fsl_lpspi =
+				spi_controller_get_devdata(spi->controller);
+	int gpio = fsl_lpspi->chipselect[spi->chip_select];
+
+	dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
+		 spi->mode, spi->bits_per_word, spi->max_speed_hz);
+
+	if (gpio_is_valid(gpio)) {
+		gpio_direction_output(gpio,
+				fsl_lpspi->config.mode & SPI_CS_HIGH ? 0 : 1);
+	}
+
+	fsl_lpspi_chipselect(spi, LPSPI_CS_INACTIVE);
+
+	return 0;
+}
+
 static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 				      struct spi_message *msg)
 {
@@ -430,8 +473,12 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 	struct spi_device *spi = msg->spi;
 	struct spi_transfer *xfer;
 	bool is_first_xfer = true;
+	bool keep_cs = false;
 	int ret = 0;
 
+	if (fsl_lpspi->hascsgpio)
+		fsl_lpspi_chipselect(spi, LPSPI_CS_ACTIVE);
+
 	msg->status = 0;
 	msg->actual_length = 0;
 
@@ -448,10 +495,24 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 		if (ret < 0)
 			goto complete;
 
+		if (fsl_lpspi->hascsgpio && xfer->cs_change) {
+			if (list_is_last(&xfer->transfer_list,
+					 &msg->transfers)) {
+				keep_cs = true;
+			} else {
+				fsl_lpspi_chipselect(spi, LPSPI_CS_INACTIVE);
+				udelay(10);
+				fsl_lpspi_chipselect(spi, LPSPI_CS_ACTIVE);
+			}
+		}
+
 		msg->actual_length += xfer->len;
 	}
 
 complete:
+	if (fsl_lpspi->hascsgpio && !keep_cs)
+		fsl_lpspi_chipselect(spi, LPSPI_CS_INACTIVE);
+
 	msg->status = ret;
 	spi_finalize_current_message(controller);
 
@@ -531,10 +592,13 @@ static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi)
 
 static int fsl_lpspi_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct fsl_lpspi_data *fsl_lpspi;
 	struct spi_controller *controller;
+	struct spi_imx_master *lpspi_platform_info =
+		dev_get_platdata(&pdev->dev);
 	struct resource *res;
-	int ret, irq;
+	int i, ret, irq;
 	u32 temp;
 
 	if (of_property_read_bool((&pdev->dev)->of_node, "spi-slave"))
@@ -558,6 +622,29 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 	fsl_lpspi->is_slave = of_property_read_bool((&pdev->dev)->of_node,
 						    "spi-slave");
 
+	fsl_lpspi->hascsgpio = false;
+	if (!fsl_lpspi->is_slave) {
+		for (i = 0; i < controller->num_chipselect; i++) {
+			int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
+
+			if (!gpio_is_valid(cs_gpio) && lpspi_platform_info)
+				cs_gpio = lpspi_platform_info->chipselect[i];
+
+			fsl_lpspi->chipselect[i] = cs_gpio;
+			if (!gpio_is_valid(cs_gpio))
+				continue;
+
+			ret = devm_gpio_request(&pdev->dev,
+					fsl_lpspi->chipselect[i], DRIVER_NAME);
+			if (ret) {
+				dev_err(&pdev->dev, "can't get cs gpios\n");
+				goto out_controller_put;
+			}
+			controller->setup = fsl_lpspi_setup;
+			fsl_lpspi->hascsgpio = true;
+		}
+	}
+
 	controller->transfer_one_message = fsl_lpspi_transfer_one_msg;
 	controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware;
 	controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 8/8] spi: lpspi: add dma mode support
  2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
                   ` (6 preceding siblings ...)
  2019-01-07  7:47 ` [PATCH 7/8] spi: lpspi: Add cs-gpio support Clark Wang
@ 2019-01-07  7:47 ` Clark Wang
  2019-01-07 15:22   ` Mark Brown
  7 siblings, 1 reply; 15+ messages in thread
From: Clark Wang @ 2019-01-07  7:47 UTC (permalink / raw)
  To: broonie; +Cc: linux-spi, linux-kernel, Clark Wang

Add dma mode support for LPSPI. Any frame longer than half txfifosize will
be sent by dma mode.

For now, there are some notes:
1. The maximum transfer speed in master mode depends on the slave device,
   at least 40MHz on i.MX8 series (tested by spi-nor on 8qm-lpddr4-arm2
   base board);
2. The maximum transfer speed in slave mode is 15MHz(i.MX7ULP),
   22MHz(i.MX8 series).

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
---
 drivers/spi/spi-fsl-lpspi.c | 318 ++++++++++++++++++++++++++++++++++--
 1 file changed, 306 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 83e15366b739..85e4e36b71a3 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -8,6 +8,8 @@
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
@@ -19,6 +21,7 @@
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/dma-imx.h>
 #include <linux/platform_data/spi-imx.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -31,6 +34,9 @@
 
 #define FSL_LPSPI_RPM_TIMEOUT 50 /* 50ms */
 
+/* The maximum bytes that edma can transfer once.*/
+#define FSL_LPSPI_MAX_EDMA_BYTES  ((1 << 15) - 1)
+
 #define LPSPI_CS_ACTIVE		1
 #define LPSPI_CS_INACTIVE	0
 #define LPSPI_CS_DELAY		100
@@ -68,6 +74,8 @@
 #define IER_FCIE	BIT(9)
 #define IER_RDIE	BIT(1)
 #define IER_TDIE	BIT(0)
+#define DER_RDDE	BIT(1)
+#define DER_TDDE	BIT(0)
 #define CFGR1_PCSCFG	BIT(27)
 #define CFGR1_PINCFG	(BIT(24)|BIT(25))
 #define CFGR1_PCSPOL	BIT(8)
@@ -95,6 +103,7 @@ struct lpspi_config {
 struct fsl_lpspi_data {
 	struct device *dev;
 	void __iomem *base;
+	unsigned long base_phys;
 	struct clk *clk_ipg;
 	struct clk *clk_per;
 	bool is_slave;
@@ -105,6 +114,8 @@ struct fsl_lpspi_data {
 	void (*tx)(struct fsl_lpspi_data *);
 	void (*rx)(struct fsl_lpspi_data *);
 
+	u32 bytes_per_word;
+	u32 bits_per_word;
 	u32 remain;
 	u8 watermark;
 	u8 txfifosize;
@@ -115,6 +126,11 @@ struct fsl_lpspi_data {
 
 	bool slave_aborted;
 
+	/* DMA */
+	bool usedma;
+	struct completion dma_rx_completion;
+	struct completion dma_tx_completion;
+
 	int chipselect[4];
 };
 
@@ -162,6 +178,35 @@ static void fsl_lpspi_intctrl(struct fsl_lpspi_data *fsl_lpspi,
 	writel(enable, fsl_lpspi->base + IMX7ULP_IER);
 }
 
+static int fsl_lpspi_bytes_per_word(const int bpw)
+{
+	return DIV_ROUND_UP(bpw, BITS_PER_BYTE);
+}
+
+static bool fsl_lpspi_can_dma(struct spi_controller *controller,
+			      struct spi_device *spi,
+			      struct spi_transfer *transfer)
+{
+	struct fsl_lpspi_data *fsl_lpspi =
+				spi_controller_get_devdata(controller);
+	unsigned int bytes_per_word;
+
+	if (!controller->dma_rx)
+		return false;
+
+	if (fsl_lpspi->is_slave)
+		return false;
+
+	bytes_per_word = fsl_lpspi_bytes_per_word(transfer->bits_per_word);
+	if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
+		return false;
+
+	if (transfer->len < fsl_lpspi->txfifosize / 2)
+		return false;
+
+	return true;
+}
+
 static int lpspi_prepare_xfer_hardware(struct spi_controller *controller)
 {
 	struct fsl_lpspi_data *fsl_lpspi =
@@ -250,11 +295,13 @@ static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi,
 		 * For the first transfer, clear TCR_CONTC to assert SS.
 		 * For subsequent transfer, set TCR_CONTC to keep SS asserted.
 		 */
-		temp |= TCR_CONT;
-		if (is_first_xfer)
-			temp &= ~TCR_CONTC;
-		else
-			temp |= TCR_CONTC;
+		if (!fsl_lpspi->usedma) {
+			temp |= TCR_CONT;
+			if (is_first_xfer)
+				temp &= ~TCR_CONTC;
+			else
+				temp |= TCR_CONTC;
+		}
 	}
 	writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
 
@@ -265,7 +312,11 @@ static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi)
 {
 	u32 temp;
 
-	temp = fsl_lpspi->watermark >> 1 | (fsl_lpspi->watermark >> 1) << 16;
+	if (!fsl_lpspi->usedma)
+		temp = fsl_lpspi->watermark >> 1 |
+		       (fsl_lpspi->watermark >> 1) << 16;
+	else
+		temp = fsl_lpspi->txfifosize >> 1;
 
 	writel(temp, fsl_lpspi->base + IMX7ULP_FCR);
 
@@ -301,12 +352,59 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
 	writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16),
 					fsl_lpspi->base + IMX7ULP_CCR);
 
-	dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale =%d, scldiv=%d\n",
+	dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale=%d, scldiv=%d\n",
 		perclk_rate, config.speed_hz, prescale, scldiv);
 
 	return 0;
 }
 
+static int fsl_lpspi_dma_configure(struct spi_controller *controller)
+{
+	int ret;
+	enum dma_slave_buswidth buswidth;
+	struct dma_slave_config rx = {}, tx = {};
+	struct fsl_lpspi_data *fsl_lpspi =
+				spi_controller_get_devdata(controller);
+
+	switch (fsl_lpspi_bytes_per_word(fsl_lpspi->bits_per_word)) {
+	case 4:
+		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
+	case 2:
+		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		break;
+	case 1:
+		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tx.direction = DMA_MEM_TO_DEV;
+	tx.dst_addr = fsl_lpspi->base_phys + IMX7ULP_TDR;
+	tx.dst_addr_width = buswidth;
+	tx.dst_maxburst = 1;
+	ret = dmaengine_slave_config(controller->dma_tx, &tx);
+	if (ret) {
+		dev_err(fsl_lpspi->dev, "TX dma configuration failed with %d\n",
+			ret);
+		return ret;
+	}
+
+	rx.direction = DMA_DEV_TO_MEM;
+	rx.src_addr = fsl_lpspi->base_phys + IMX7ULP_RDR;
+	rx.src_addr_width = buswidth;
+	rx.src_maxburst = 1;
+	ret = dmaengine_slave_config(controller->dma_rx, &rx);
+	if (ret) {
+		dev_err(fsl_lpspi->dev, "RX dma configuration failed with %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
 {
 	u32 temp;
@@ -332,15 +430,22 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
 	temp |= CR_RRF | CR_RTF | CR_MEN;
 	writel(temp, fsl_lpspi->base + IMX7ULP_CR);
 
+	temp = 0;
+	if (fsl_lpspi->usedma)
+		temp = DER_TDDE | DER_RDDE;
+	writel(temp, fsl_lpspi->base + IMX7ULP_DER);
+
 	return 0;
 }
 
-static int fsl_lpspi_setup_transfer(struct spi_device *spi,
+static int fsl_lpspi_setup_transfer(struct spi_controller *controller,
+				     struct spi_device *spi,
 				     struct spi_transfer *t)
 {
 	struct fsl_lpspi_data *fsl_lpspi =
 				spi_controller_get_devdata(spi->controller);
 
+	fsl_lpspi->bits_per_word = t->bits_per_word;
 	fsl_lpspi->config.mode = spi->mode;
 	fsl_lpspi->config.bpw = t ? t->bits_per_word : spi->bits_per_word;
 	fsl_lpspi->config.speed_hz = t ? t->speed_hz : spi->max_speed_hz;
@@ -368,6 +473,11 @@ static int fsl_lpspi_setup_transfer(struct spi_device *spi,
 	else
 		fsl_lpspi->watermark = fsl_lpspi->txfifosize;
 
+	if (fsl_lpspi_can_dma(controller, spi, t))
+		fsl_lpspi->usedma = 1;
+	else
+		fsl_lpspi->usedma = 0;
+
 	return fsl_lpspi_config(fsl_lpspi);
 }
 
@@ -406,8 +516,10 @@ static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi)
 {
 	u32 temp;
 
-	/* Disable all interrupt */
-	fsl_lpspi_intctrl(fsl_lpspi, 0);
+	if (!fsl_lpspi->usedma) {
+		/* Disable all interrupt */
+		fsl_lpspi_intctrl(fsl_lpspi, 0);
+	}
 
 	/* W1C for all flags in SR */
 	temp = 0x3F << 8;
@@ -420,6 +532,128 @@ static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi)
 	return 0;
 }
 
+static void fsl_lpspi_dma_rx_callback(void *cookie)
+{
+	struct fsl_lpspi_data *fsl_lpspi = (struct fsl_lpspi_data *)cookie;
+
+	complete(&fsl_lpspi->dma_rx_completion);
+}
+
+static void fsl_lpspi_dma_tx_callback(void *cookie)
+{
+	struct fsl_lpspi_data *fsl_lpspi = (struct fsl_lpspi_data *)cookie;
+
+	complete(&fsl_lpspi->dma_tx_completion);
+}
+
+static int fsl_lpspi_calculate_timeout(struct fsl_lpspi_data *fsl_lpspi,
+				       int size)
+{
+	unsigned long timeout = 0;
+
+	/* Time with actual data transfer and CS change delay related to HW */
+	timeout = (8 + 4) * size / fsl_lpspi->config.speed_hz;
+
+	/* Add extra second for scheduler related activities */
+	timeout += 1;
+
+	/* Double calculated timeout */
+	return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC);
+}
+
+static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
+				struct fsl_lpspi_data *fsl_lpspi,
+				struct spi_transfer *transfer)
+{
+	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
+	unsigned long transfer_timeout;
+	unsigned long timeout;
+	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
+	int ret;
+
+	ret = fsl_lpspi_dma_configure(controller);
+	if (ret)
+		return ret;
+
+	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
+				rx->sgl, rx->nents, DMA_DEV_TO_MEM,
+				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc_rx)
+		return -EINVAL;
+
+	desc_rx->callback = fsl_lpspi_dma_rx_callback;
+	desc_rx->callback_param = (void *)fsl_lpspi;
+	dmaengine_submit(desc_rx);
+	reinit_completion(&fsl_lpspi->dma_rx_completion);
+	dma_async_issue_pending(controller->dma_rx);
+
+	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
+				tx->sgl, tx->nents, DMA_MEM_TO_DEV,
+				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc_tx) {
+		dmaengine_terminate_all(controller->dma_tx);
+		return -EINVAL;
+	}
+
+	desc_tx->callback = fsl_lpspi_dma_tx_callback;
+	desc_tx->callback_param = (void *)fsl_lpspi;
+	dmaengine_submit(desc_tx);
+	reinit_completion(&fsl_lpspi->dma_tx_completion);
+	dma_async_issue_pending(controller->dma_tx);
+
+	fsl_lpspi->slave_aborted = false;
+
+	if (!fsl_lpspi->is_slave) {
+		transfer_timeout = fsl_lpspi_calculate_timeout(fsl_lpspi,
+							       transfer->len);
+
+		/* Wait eDMA to finish the data transfer.*/
+		timeout = wait_for_completion_timeout(&fsl_lpspi->dma_tx_completion,
+						      transfer_timeout);
+		if (!timeout) {
+			dev_err(fsl_lpspi->dev, "I/O Error in DMA TX\n");
+			dmaengine_terminate_all(controller->dma_tx);
+			dmaengine_terminate_all(controller->dma_rx);
+			fsl_lpspi_reset(fsl_lpspi);
+			return -ETIMEDOUT;
+		}
+
+		timeout = wait_for_completion_timeout(&fsl_lpspi->dma_rx_completion,
+						      transfer_timeout);
+		if (!timeout) {
+			dev_err(fsl_lpspi->dev, "I/O Error in DMA RX\n");
+			dmaengine_terminate_all(controller->dma_tx);
+			dmaengine_terminate_all(controller->dma_rx);
+			fsl_lpspi_reset(fsl_lpspi);
+			return -ETIMEDOUT;
+		}
+	} else {
+		if (wait_for_completion_interruptible(&fsl_lpspi->dma_tx_completion) ||
+			fsl_lpspi->slave_aborted) {
+			dev_dbg(fsl_lpspi->dev,
+				"I/O Error in DMA TX interrupted\n");
+			dmaengine_terminate_all(controller->dma_tx);
+			dmaengine_terminate_all(controller->dma_rx);
+			fsl_lpspi_reset(fsl_lpspi);
+			return -EINTR;
+		}
+
+		if (wait_for_completion_interruptible(&fsl_lpspi->dma_rx_completion) ||
+			fsl_lpspi->slave_aborted) {
+			dev_dbg(fsl_lpspi->dev,
+				"I/O Error in DMA RX interrupted\n");
+			dmaengine_terminate_all(controller->dma_tx);
+			dmaengine_terminate_all(controller->dma_rx);
+			fsl_lpspi_reset(fsl_lpspi);
+			return -EINTR;
+		}
+	}
+
+	fsl_lpspi_reset(fsl_lpspi);
+
+	return 0;
+}
+
 static int fsl_lpspi_transfer_one(struct spi_controller *controller,
 				  struct spi_device *spi,
 				  struct spi_transfer *t)
@@ -446,6 +680,54 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller,
 	return 0;
 }
 
+static void fsl_lpspi_dma_exit(struct spi_controller *controller)
+{
+	if (controller->dma_rx) {
+		dma_release_channel(controller->dma_rx);
+		controller->dma_rx = NULL;
+	}
+
+	if (controller->dma_tx) {
+		dma_release_channel(controller->dma_tx);
+		controller->dma_tx = NULL;
+	}
+}
+
+static int fsl_lpspi_dma_init(struct device *dev,
+			      struct fsl_lpspi_data *fsl_lpspi,
+			      struct spi_controller *controller)
+{
+	int ret;
+
+	/* Prepare for TX DMA: */
+	controller->dma_tx = dma_request_slave_channel_reason(dev, "tx");
+	if (IS_ERR(controller->dma_tx)) {
+		ret = PTR_ERR(controller->dma_tx);
+		dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
+		controller->dma_tx = NULL;
+		goto err;
+	}
+
+	/* Prepare for RX DMA: */
+	controller->dma_rx = dma_request_slave_channel(dev, "rx");
+	if (IS_ERR(controller->dma_rx)) {
+		ret = PTR_ERR(controller->dma_rx);
+		dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
+		controller->dma_rx = NULL;
+		goto err;
+	}
+
+	init_completion(&fsl_lpspi->dma_rx_completion);
+	init_completion(&fsl_lpspi->dma_tx_completion);
+	controller->can_dma = fsl_lpspi_can_dma;
+	controller->max_dma_len = FSL_LPSPI_MAX_EDMA_BYTES;
+
+	return 0;
+err:
+	fsl_lpspi_dma_exit(controller);
+	return ret;
+}
+
 static int fsl_lpspi_setup(struct spi_device *spi)
 {
 	struct fsl_lpspi_data *fsl_lpspi =
@@ -483,7 +765,7 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 	msg->actual_length = 0;
 
 	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-		ret = fsl_lpspi_setup_transfer(spi, xfer);
+		ret = fsl_lpspi_setup_transfer(controller, spi, xfer);
 		if (ret < 0)
 			goto complete;
 
@@ -491,7 +773,11 @@ static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller,
 
 		is_first_xfer = false;
 
-		ret = fsl_lpspi_transfer_one(controller, spi, xfer);
+		if (fsl_lpspi->usedma)
+			ret = fsl_lpspi_dma_transfer(controller, fsl_lpspi,
+						     xfer);
+		else
+			ret = fsl_lpspi_transfer_one(controller, spi, xfer);
 		if (ret < 0)
 			goto complete;
 
@@ -662,6 +948,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 		ret = PTR_ERR(fsl_lpspi->base);
 		goto out_controller_put;
 	}
+	fsl_lpspi->base_phys = res->start;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
@@ -703,6 +990,13 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 	fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
 	fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
 
+	ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller);
+	if (ret == -EPROBE_DEFER)
+		goto out_controller_put;
+
+	if (ret < 0)
+		dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret);
+
 	ret = devm_spi_register_controller(&pdev->dev, controller);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "spi_register_controller error.\n");
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/8] spi: lpspi: Add i.MX8 boards support for lpspi
  2019-01-07  7:47 ` [PATCH 1/8] spi: lpspi: Add i.MX8 boards support for lpspi Clark Wang
@ 2019-01-07 15:15   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2019-01-07 15:15 UTC (permalink / raw)
  To: Clark Wang; +Cc: linux-spi, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 280 bytes --]

On Mon, Jan 07, 2019 at 07:47:34AM +0000, Clark Wang wrote:
> Add both ipg and per clock for lpspi to support i.MX8QM/QXP boards.

This needs a binding doc update to reflect the new clock that is being
added (it's not clear from the changelog that ipg was already being
handled).

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/8] spi: lpspi: enable runtime pm for lpspi
  2019-01-07  7:47 ` [PATCH 2/8] spi: lpspi: enable runtime pm " Clark Wang
@ 2019-01-07 15:16   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2019-01-07 15:16 UTC (permalink / raw)
  To: Clark Wang; +Cc: linux-spi, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 338 bytes --]

On Mon, Jan 07, 2019 at 07:47:36AM +0000, Clark Wang wrote:
> 	From: Han Xu <han.xu@nxp.com>
> 
> 	Enable the runtime power management for lpspi module.
> 
> Do some adaptation work from kernel 4.9 to 4.14.
> 

Looks like the changelog here is a bit corrupted (extra indents on the
first two lines).  Otherwise this looks fine.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 8/8] spi: lpspi: add dma mode support
  2019-01-07  7:47 ` [PATCH 8/8] spi: lpspi: add dma mode support Clark Wang
@ 2019-01-07 15:22   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2019-01-07 15:22 UTC (permalink / raw)
  To: Clark Wang; +Cc: linux-spi, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 858 bytes --]

On Mon, Jan 07, 2019 at 07:47:49AM +0000, Clark Wang wrote:

A couple of small nits but otherwise this looks good:

> +	bytes_per_word = fsl_lpspi_bytes_per_word(transfer->bits_per_word);
> +	if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
> +		return false;

This would be clearer written as a switch statement.

> @@ -301,12 +352,59 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
>  	writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16),
>  					fsl_lpspi->base + IMX7ULP_CCR);
>  
> -	dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale =%d, scldiv=%d\n",
> +	dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale=%d, scldiv=%d\n",
>  		perclk_rate, config.speed_hz, prescale, scldiv);
>  
>  	return 0;
>  }
>  

This looks like an unrelated typo fix, should be a separate patch.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Applied "spi: lpspi: Fix wrong transmission when don't use CONT" to the spi tree
  2019-01-07  7:47 ` [PATCH 4/8] spi: lpspi: Fix wrong transmission when don't use CONT Clark Wang
@ 2019-01-07 18:59   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2019-01-07 18:59 UTC (permalink / raw)
  To: Clark Wang; +Cc: Mark Brown, broonie, linux-spi, linux-kernel, linux-spi

The patch

   spi: lpspi: Fix wrong transmission when don't use CONT

has been applied to the spi tree at

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 6a130448498c151d31f1fb6f3003f5cf37b829e0 Mon Sep 17 00:00:00 2001
From: Clark Wang <xiaoning.wang@nxp.com>
Date: Mon, 7 Jan 2019 07:47:41 +0000
Subject: [PATCH] spi: lpspi: Fix wrong transmission when don't use CONT

Add judgment on SR_MBF and FSR_RXCOUNT.

In PIO mode, if don't use CONT to keep cs selected in one transfer, the
transfer will go wrong. FCIE will be set after one frame transfer
finish. If use CONT, the frame refer to the whole data in one transfer.
If don't use CONT, the frame refer to one byte of whole data. This will
cause the transfer ending early.

This patch add a register reading in isr function, it might lead to a
slight decrease in the max transmission speed in PIO mode.

Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/spi/spi-fsl-lpspi.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index ba207931e209..d0b2d551cc43 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -48,6 +48,7 @@
 #define CR_RTF		BIT(8)
 #define CR_RST		BIT(1)
 #define CR_MEN		BIT(0)
+#define SR_MBF		BIT(24)
 #define SR_TCF		BIT(10)
 #define SR_FCF		BIT(9)
 #define SR_RDF		BIT(1)
@@ -61,6 +62,7 @@
 #define CFGR1_PCSPOL	BIT(8)
 #define CFGR1_NOSTALL	BIT(3)
 #define CFGR1_MASTER	BIT(0)
+#define FSR_RXCOUNT	(BIT(16)|BIT(17)|BIT(18))
 #define RSR_RXEMPTY	BIT(1)
 #define TCR_CPOL	BIT(31)
 #define TCR_CPHA	BIT(30)
@@ -433,6 +435,13 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
 		return IRQ_HANDLED;
 	}
 
+	if (temp_SR & SR_MBF ||
+	    readl(fsl_lpspi->base + IMX7ULP_FSR) & FSR_RXCOUNT) {
+		writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
+		fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE);
+		return IRQ_HANDLED;
+	}
+
 	if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) {
 		writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
 			complete(&fsl_lpspi->xfer_done);
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 7/8] spi: lpspi: Add cs-gpio support
  2019-01-07  7:47 ` [PATCH 7/8] spi: lpspi: Add cs-gpio support Clark Wang
@ 2019-01-09 12:33   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2019-01-09 12:33 UTC (permalink / raw)
  To: Clark Wang; +Cc: linux-spi, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 534 bytes --]

On Mon, Jan 07, 2019 at 07:47:47AM +0000, Clark Wang wrote:
> Add cs-gpio feature for LPSPI.
> The cs line will be controlled in fsl_lpspi_transfe_one_msg() function.
> 
> Still support using the mode without cs-gpio. It depends on if attribute
> cs-gpio has been configured in dts file.

This is open coding the GPIO - it'd be better to convert to use
transfer_one() so you can use the core GPIO handling but that's not
really directly relevant to this patch so I'm going to apply, just
something it'd be good to work on.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 6/8] spi: lpspi: add the error info of transfer speed setting
  2019-01-07  7:47 ` [PATCH 6/8] spi: lpspi: add the error info of transfer speed setting Clark Wang
@ 2019-01-09 12:43   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2019-01-09 12:43 UTC (permalink / raw)
  To: Clark Wang; +Cc: linux-spi, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 278 bytes --]

On Mon, Jan 07, 2019 at 07:47:45AM +0000, Clark Wang wrote:
> Add a error info when set a speed which greater than half of per-clk of
> spi module.

This (and it turns out the subsequent patch which I said I'd apply)
doesn't apply against current code, please check and resend.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2019-01-09 12:43 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-07  7:47 [PATCH 0/8] spi: lpspi: Fix bugs and Add some functions support Clark Wang
2019-01-07  7:47 ` [PATCH 1/8] spi: lpspi: Add i.MX8 boards support for lpspi Clark Wang
2019-01-07 15:15   ` Mark Brown
2019-01-07  7:47 ` [PATCH 2/8] spi: lpspi: enable runtime pm " Clark Wang
2019-01-07 15:16   ` Mark Brown
2019-01-07  7:47 ` [PATCH 3/8] spi: lpspi: Improve the stability of lpspi data transmission Clark Wang
2019-01-07  7:47 ` [PATCH 4/8] spi: lpspi: Fix wrong transmission when don't use CONT Clark Wang
2019-01-07 18:59   ` Applied "spi: lpspi: Fix wrong transmission when don't use CONT" to the spi tree Mark Brown
2019-01-07  7:47 ` [PATCH 5/8] spi: lpspi: Fix CLK pin becomes low before one transfer Clark Wang
2019-01-07  7:47 ` [PATCH 6/8] spi: lpspi: add the error info of transfer speed setting Clark Wang
2019-01-09 12:43   ` Mark Brown
2019-01-07  7:47 ` [PATCH 7/8] spi: lpspi: Add cs-gpio support Clark Wang
2019-01-09 12:33   ` Mark Brown
2019-01-07  7:47 ` [PATCH 8/8] spi: lpspi: add dma mode support Clark Wang
2019-01-07 15:22   ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).