Skip to contentSkip to conversation

Add SPI control driver for Sunplus SP7021 SoC

PATCH In review LH.Kuo 7 participants 35 messages Nov 1, 2021 – Dec 1, 2021 11 messages not in the archive

Subsystems (3)
lore
Share & tools
lore

LH.Kuo

author maintainer
#0 lore raw

cover Add SPI control driver for Sunplus SP7021 SoC

This is a patch series for SPI driver for Sunplus SP7021 SoC.

Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates many peripherals (ex: UART, I2C, SPI, SDIO, eMMC, USB, SD card and etc.) into a single chip. It is designed for industrial control.

Refer to:
https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
https://tibbo.com/store/plus1.html

LH.Kuo (2):
SPI: Add SPI driver for Sunplus SP7021
devicetree bindings SPI Add bindings doc for Sunplus SP7021

 .../bindings/spi/spi-sunplus-sp7021.yaml           |   95 ++
 MAINTAINERS                                        |    7 +
 drivers/spi/Kconfig                                |   11 +
 drivers/spi/Makefile                               |    1 +
 drivers/spi/spi-sunplus-sp7021.c                   | 1356 ++++++++++++++++++++
 5 files changed, 1470 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
 create mode 100644 drivers/spi/spi-sunplus-sp7021.c
Signature · 1 line
2.7.4
author maintainer
#1 lore raw

PATCH 1/2 SPI: Add SPI driver for Sunplus SP7021

Add SPI driver for Sunplus SP7021.

---
 MAINTAINERS                      |    6 +
 drivers/spi/Kconfig              |   11 +
 drivers/spi/Makefile             |    1 +
 drivers/spi/spi-sunplus-sp7021.c | 1356 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 1374 insertions(+)
 create mode 100644 drivers/spi/spi-sunplus-sp7021.c
MAINTAINERS +6 -0
index 3b79fd4..f00c466 100644
@@ -17945,6 +17945,12 @@ L:	[email protected]
 S:	Maintained
 F:	drivers/net/ethernet/dlink/sundance.c
 
+SUNPLUS SPI CONTROLLER INTERFACE DRIVER
+M:	LH Kuo <[email protected]>
+L:	[email protected] (subscribers-only)
+S:	Maintained
+F:	drivers/spi/spi-sunplus-sp7021.c
+
 SUPERH
 M:	Yoshinori Sato <[email protected]>
 M:	Rich Felker <[email protected]>
drivers/spi/Kconfig +11 -0
index 83e352b..24a39c8 100644
@@ -844,6 +844,17 @@ config SPI_SUN6I
 	help
 	  This enables using the SPI controller on the Allwinner A31 SoCs.
 
+config SPI_SUNPLUS_SP7021
+	tristate "Sunplus SP7021 SPI controller"
+	depends on SOC_SP7021
+	help
+	  This enable Sunplus SP7021 spi controller driver on the SP7021 SoCs.
+	  This driver can also be built as a module. If so, the module will be
+	  called as spi-sunplus-sp7021.
+
+	  If you have a  Sunplus SP7021 platform say Y here.
+	  If unsure, say N.
+
 config SPI_SYNQUACER
 	tristate "Socionext's SynQuacer HighSpeed SPI controller"
 	depends on ARCH_SYNQUACER || COMPILE_TEST
drivers/spi/Makefile +1 -0
index 699db95..04428e7 100644
@@ -117,6 +117,7 @@ obj-$(CONFIG_SPI_STM32_QSPI) 		+= spi-stm32-qspi.o
 obj-$(CONFIG_SPI_ST_SSC4)		+= spi-st-ssc4.o
 obj-$(CONFIG_SPI_SUN4I)			+= spi-sun4i.o
 obj-$(CONFIG_SPI_SUN6I)			+= spi-sun6i.o
+obj-$(CONFIG_SPI_SUNPLUS_SP7021)	+= spi-sunplus-sp7021.o
 obj-$(CONFIG_SPI_SYNQUACER)		+= spi-synquacer.o
 obj-$(CONFIG_SPI_TEGRA210_QUAD)		+= spi-tegra210-quad.o
 obj-$(CONFIG_SPI_TEGRA114)		+= spi-tegra114.o
drivers/spi/spi-sunplus-sp7021.c new file +1356 -0

1,356 lines not on this page · raw message

Signature · 1 line
2.7.4
maintainer
#2 lore raw

Re: [PATCH 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 1 line · LH.Kuo

Add SPI driver for Sunplus SP7021.

In general it looks like this needs quite a bit of a refresh for mainline - a lot of it looks to be a combination of minor, easily fixable things and stylistic issues which make things hard to follow but I think there are some more substantial things going on here as well.

One big thing is that the driver appears to copy everything through bounce buffers ore or less unconditionally. It's not clear why it's doing this - if it's for DMA usage in general the buffers supplied to SPI devices should be suitable for this.

Stylistically the code just doesn't really look like Linux code, there's a few frequent issues I've highlighted in the review but there's probably more that are masked, it'd be worth visually comparing the driver to others and making sure it looks similar.

drivers/spi/spi-sunplus-sp7021.c line 5

Quoted 7 lines

+++ b/drivers/spi/spi-sunplus-sp7021.c

drivers/spi/spi-sunplus-sp7021.c new file +5 -0
@@ -0,0 +1,1356 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Sunplus SPI controller driver
+ *
+ * Author: Sunplus Technology Co., Ltd.

Please make the entire comment a C++ one so things look more intentional.

drivers/spi/spi-sunplus-sp7021.c line 11

Quoted 1 line
drivers/spi/spi-sunplus-sp7021.c new file +1 -0
+//#define DEBUG

Please drop commented out lines like this, there's *lots* of this in the driver.

drivers/spi/spi-sunplus-sp7021.c line 35

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+/* ---------------------------------------------------------------------------------------------- */
+
+//#define SPI_FUNC_DEBUG
+//#define SPI_DBG_INFO
+#define SPI_DBG_ERR

All this stuff is just duplicating the standard facilities we have in the kernel for controlling output, please remove it and convert things over to using normal logging infrastructure rather than a custom setup for your device driver.

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+#define SPI_FULL_DUPLEX
+
+#define MAS_REG_NAME "spi_master"
+#define SLA_REG_NAME "spi_slave"
+
+#define DMA_IRQ_NAME "dma_w_intr"
+#define MAS_IRQ_NAME "mas_risc_intr"
+
+#define SLA_IRQ_NAME "slave_risc_intr"
+

drivers/spi/spi-sunplus-sp7021.c line 75

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+#define SPI_TRANS_DATA_CNT (4)
+#define SPI_TRANS_DATA_SIZE (255)
+#define SPI_MSG_DATA_SIZE (SPI_TRANS_DATA_SIZE * SPI_TRANS_DATA_CNT)
+
+
+#define CLEAR_MASTER_INT (1<<6)
+#define MASTER_INT (1<<7)
+
+#define DMA_READ (0xd)
+#define SLA_SW_RST (1<<1)

Many of these names seem very generic and likely to have collisions in future, please use prefixes to avoid potential future collisions.

drivers/spi/spi-sunplus-sp7021.c line 165

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+struct SPI_MAS {
+	// Group 091 : SPI_MASTER
+	unsigned int MST_TX_DATA_ADDR                      ; // 00  (ADDR : 0x9C00_2D80)

Please try to follow the kernel coding style, we don't use upper case for struct or variable names.

drivers/spi/spi-sunplus-sp7021.c line 166

Quoted 1 line
drivers/spi/spi-sunplus-sp7021.c new file +1 -0
+	unsigned int MST_TX_DATA_3_2_1_0                   ; // 01  (ADDR : 0x9C00_2D84)

I don't know what these numbers at the end of variable names are intended to represent but they don't feel like they're helping.

drivers/spi/spi-sunplus-sp7021.c line 264

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+	u8 tx_data_buf[SPI_TRANS_DATA_SIZE];
+	u8 rx_data_buf[SPI_TRANS_DATA_SIZE];

These look like they'd be better as dynamically allocated buffers, aside from anything else this will ensure that they are well aligned for DMA.

drivers/spi/spi-sunplus-sp7021.c line 272

Quoted 1 line
drivers/spi/spi-sunplus-sp7021.c new file +1 -0
+static unsigned int bufsiz = 4096;

This should be per device.

drivers/spi/spi-sunplus-sp7021.c line 284

Quoted 11 lines
drivers/spi/spi-sunplus-sp7021.c new file +11 -0
+static void pentagram_set_cs(struct spi_device *_s, bool _on)
+{
+	if (_s->mode & SPI_NO_CS)
+		return;
+	if (!(_s->cs_gpiod))
+		return;
+	dev_dbg(&(_s->dev), "%d gpiod:%d", _on, desc_to_gpio(_s->cs_gpiod));
+	if (_s->mode & SPI_CS_HIGH)
+		_on = !_on;
+	gpiod_set_value_cansleep(_s->cs_gpiod, _on);
+}

If the device has a GPIO chip select it should use the core support for GPIO chip selects rather than open coding.

drivers/spi/spi-sunplus-sp7021.c line 294

Quoted 8 lines
drivers/spi/spi-sunplus-sp7021.c new file +8 -0
+static irqreturn_t pentagram_spi_S_irq(int _irq, void *_dev)
+{
+	unsigned long flags;
+	struct pentagram_spi_master *pspim = (struct pentagram_spi_master *)_dev;
+	struct SPI_SLA *sr = (struct SPI_SLA *)pspim->sla_base;
+
+	FUNC_DBG();
+	spin_lock_irqsave(&pspim->lock, flags);

If you're in an interrupt you should only use the regular spin lock, no need to save IRQ status.

drivers/spi/spi-sunplus-sp7021.c line 298

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+	writel(readl(&sr->RISC_INT_DATA_RDY) | CLEAR_SLAVE_INT, &sr->RISC_INT_DATA_RDY);
+	spin_unlock_irqrestore(&pspim->lock, flags);
+	complete(&pspim->sla_isr);
+	return IRQ_HANDLED;

This appears to unconditionally ack an interrupt regardless of any status bits? This seems to be a problem for all the interrupts in this functions.

drivers/spi/spi-sunplus-sp7021.c line 325

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+		writel(readl(&spis_reg->RISC_INT_DATA_RDY) | SLAVE_DATA_RDY,
+					&spis_reg->RISC_INT_DATA_RDY);
+		//regs1->SLV_DMA_CTRL = 0x4d;
+		//regs1->SLV_DMA_LENGTH = 0x50;
+		//regs1->SLV_DMA_INI_ADDR = 0x300;
+		//regs1->RISC_INT_DATA_RDY |= 0x1;

This commented out stuff looks worrying...

drivers/spi/spi-sunplus-sp7021.c line 350

Quoted 9 lines
drivers/spi/spi-sunplus-sp7021.c new file +8 -0
+		if (!wait_for_completion_timeout(&pspim->isr_done, timeout)) {
+			dev_err(&dev, "wait_for_completion_timeout\n");
+			goto exit_spi_slave_rw;
+		}
 
+exit_spi_slave_rw:
+	mutex_unlock(&pspim->buf_lock);
+	return 0;
+}

If there's an error it's not reported anywhere.

Quoted 7 lines
drivers/spi/spi-sunplus-sp7021.c new file +7 -0
+	if (RW_phase == SPI_SLAVE_WRITE) {
+		DBG_INF("S_WRITE len %d", _t->len);
+		reinit_completion(&pspim->sla_isr);
+
+		if (_t->tx_dma == pspim->tx_dma_phy_base)
+			memcpy(pspim->tx_dma_vir_base, _t->tx_buf, _t->len);
+

drivers/spi/spi-sunplus-sp7021.c line 388

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+		writel_relaxed(DMA_WRITE, &spis_reg->SLV_DMA_CTRL);
+		writel_relaxed(_t->len, &spis_reg->SLV_DMA_LENGTH);
+		writel_relaxed(_t->tx_dma, &spis_reg->SLV_DMA_INI_ADDR);
+		writel(readl(&spis_reg->RISC_INT_DATA_RDY) | SLAVE_DATA_RDY,
+				&spis_reg->RISC_INT_DATA_RDY);
+
+		if (wait_for_completion_interruptible(&pspim->sla_isr))
+			dev_err(devp, "%s() wait_for_completion timeout\n", __func__);
+
+	} else if (RW_phase == SPI_SLAVE_READ) {

These two cases share no code, they should probably be separate functions (and what happens if it's an unknown phase?).

drivers/spi/spi-sunplus-sp7021.c line 438

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+	}
+}
+void sp7021spi_wb(struct pentagram_spi_master *_m, u8 _len)

Missing blank line between functions. In general more blank lines between blocks would help.

Review

Quoted 2 lines
(quoted diff) +2 -0
+{
+	struct SPI_MAS *sr = (struct SPI_MAS *)_m->mas_base;

These _ names really aren't at all idiomatic for the kernel. This is a problem throughout the driver, it's a barrier to legibility. I'm also concerned that it looks like you're trying to do accesses to the device via a struct dereference rather than readl/writel - this will probably work a lot of the time but I'm not sure it's guaranteed.

Quoted 1 line

+static irqreturn_t pentagram_spi_M_irq(int _irq, void *_dev)

Nor are capitals in function names.

drivers/spi/spi-sunplus-sp7021.c line 529

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+static void spspi_delay_ns(u32 _ns)
+{
+

Why is this open coded?

drivers/spi/spi-sunplus-sp7021.c line 568

Quoted 8 lines
drivers/spi/spi-sunplus-sp7021.c new file +8 -0
+	if (_t->speed_hz <= _s->max_speed_hz)
+		div = clk_rate / _t->speed_hz;
+	else if (_s->max_speed_hz <= _c->max_speed_hz)
+		div = clk_rate / _s->max_speed_hz;
+	else if (_c->max_speed_hz < pspim->spi_max_frequency)
+		div = clk_rate / _c->max_speed_hz;
+	else
+		div = clk_rate / pspim->spi_max_frequency;

The core will set the speed up for the transfer, don't open code this.

drivers/spi/spi-sunplus-sp7021.c line 615

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+	if (pspim->tx_cur_len < data_len) {
+		len_temp = min(pspim->data_unit, data_len);
+		sp7021spi_wb(pspim, len_temp);
+	}

What if there's more data?

drivers/spi/spi-sunplus-sp7021.c line 649

Quoted 9 lines
drivers/spi/spi-sunplus-sp7021.c new file +9 -0
+	data_len = 0;
+	t = first;
+	for (i = 0; i < transfers_cnt; i++) {
+		if (t->rx_buf)
+			memcpy(t->rx_buf, &pspim->rx_data_buf[data_len], t->len);
+
+		data_len += t->len;
+		t = list_entry(t->transfer_list.next, struct spi_transfer, transfer_list);
+	}

I find it difficult to convince myself that this isn't going to have any overflow issues, and it'll break operation with anything that does any manipulation of chip select during the message. Given that the device uses GPIO chip selects I'd expect it to just implement transfer_one() and not handle messages at all. This would greatly simplify the code.

drivers/spi/spi-sunplus-sp7021.c line 770

Quoted 12 lines
drivers/spi/spi-sunplus-sp7021.c new file +12 -0
+#ifdef CONFIG_PM_RUNTIME_SPI
+
+	struct pentagram_spi_master *pspim = spi_controller_get_devdata(_s->controller);
+
+	if (pm_runtime_enabled(pspim->dev)) {
+		ret = pm_runtime_get_sync(pspim->dev)
+		if (ret < 0)
+			goto pm_out;
+	}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME_SPI

The runtime PM code compiles out when disabled, you shouldn't need these ifdefs (and you definitely shouldn't need two blocks for the same define together like this).

drivers/spi/spi-sunplus-sp7021.c line 836

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+static int pentagram_spi_controller_unprepare_message(struct spi_controller *ctlr,
+				    struct spi_message *msg)
+{
+	FUNC_DBG();
+	return 0;
+}

Remove empty functions, the core will cope.

drivers/spi/spi-sunplus-sp7021.c line 848

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+static int pentagram_spi_S_transfer_one(struct spi_controller *_c, struct spi_device *_s,
+					struct spi_transfer *_t)
+{

So we are using transfer_one? In that case I'm very confused why the driver would be walking a transfer list...

drivers/spi/spi-sunplus-sp7021.c line 860

Quoted 12 lines
drivers/spi/spi-sunplus-sp7021.c new file +12 -0
+	struct pentagram_spi_master *pspim = spi_master_get_devdata(_c);
+	struct device *dev = pspim->dev;
+	int mode = SPI_IDLE, ret = 0;
+
+	FUNC_DBG();
+#ifdef CONFIG_PM_RUNTIME_SPI
+	if (pm_runtime_enabled(pspim->dev)) {
+		ret = pm_runtime_get_sync(pspim->dev);
+		if (ret < 0)
+			goto pm_out;
+	}
+#endif

Let the core handle runtime PM for you, don't open code it.

drivers/spi/spi-sunplus-sp7021.c line 867

Quoted 7 lines
drivers/spi/spi-sunplus-sp7021.c new file +7 -0
+
+	if (spi_controller_is_slave(_c)) {
+
+		pspim->isr_flag = SPI_IDLE;
+
+		if ((_t->tx_buf) && (_t->rx_buf)) {
+			dev_dbg(&_c->dev, "%s() wrong command\n", __func__);

Return an error, don't just ignore problems.

drivers/spi/spi-sunplus-sp7021.c line 872

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+		} else if (_t->tx_buf) {
+			/* tx_buf is a const void* where we need a void * for
+			 * the dma mapping
+			 */
+			void *nonconst_tx = (void *)_t->tx_buf;

Why do other drivers not need this? Are you *sure* that's just getting rid of a const here?

Review

Quoted 2 lines
(quoted diff) +2 -0
+			} else
+				mode = SPI_SLAVE_WRITE;

{ } on both sides of the ifelse.

drivers/spi/spi-sunplus-sp7021.c

Quoted 11 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+		switch (mode) {
+		case SPI_SLAVE_WRITE:
+		case SPI_SLAVE_READ:
+			pentagram_spi_S_rw(_s, _t, mode);
+			break;
+		default:
+			DBG_INF("idle?");
+			break;
+		}
 
+	pdev->id = 0;

Why?

drivers/spi/spi-sunplus-sp7021.c line 1090

Quoted 7 lines
drivers/spi/spi-sunplus-sp7021.c new file +7 -0
+	ctlr->bus_num = pdev->id;
+	// flags, understood by the driver
+	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+	ctlr->min_speed_hz = 40000;
+	ctlr->max_speed_hz = 50000000;
+	// ctlr->flags = 0

The driver should at least be flagging itself as half duplex.

drivers/spi/spi-sunplus-sp7021.c line 1125

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+	/* find and map our resources */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, MAS_REG_NAME);
+	if (res) {
+		pspim->mas_base = devm_ioremap_resource(&pdev->dev, res);

devm_platform_ioremap_resource_by_name().

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+	FUNC_DBG();
+
+	reset_control_assert(pspim->rstc);
+
+	return 0;
+}

drivers/spi/spi-sunplus-sp7021.c line 1297

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+
+static int pentagram_spi_controller_resume(struct platform_device *pdev)
+{
+	struct spi_controller *ctlr = platform_get_drvdata(pdev);
+	struct pentagram_spi_master *pspim = spi_master_get_devdata(ctlr);
+
+	FUNC_DBG();
+
+	reset_control_deassert(pspim->rstc);
+	clk_prepare_enable(pspim->spi_clk);

There's no matching disable...

drivers/spi/spi-sunplus-sp7021.c line 1349

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+#ifdef CONFIG_PM_RUNTIME_SPI
+		.pm     = &sp7021_spi_pm_ops,
+#endif

There's a helper for this.

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#4 lore raw

Re: [PATCH 1/2] SPI: Add SPI driver for Sunplus SP7021

On Fri, Nov 05, 2021 at 03:12:32AM +0000, Lh Kuo 郭力豪 wrote:

Please delete unneeded context from mails when replying. Doing this makes it much easier to find your reply in the message, helping ensure it won't be missed by people scrolling through the irrelevant quoted material.

Quoted 11 lines
Quoted 9 lines

drivers/spi/spi-sunplus-sp7021.c line 5

Quoted 7 lines

+++ b/drivers/spi/spi-sunplus-sp7021.c

drivers/spi/spi-sunplus-sp7021.c new file +5 -0
@@ -0,0 +1,1356 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Sunplus SPI controller driver
+ *
+ * Author: Sunplus Technology Co., Ltd.

Please make the entire comment a C++ one so things look more intentional.

Sorry I don't understand. Is there a explanation?

Make the entire comment block C++ style - //

Quoted 4 lines
Quoted 2 lines

If the device has a GPIO chip select it should use the core support for GPIO chip selects rather than open coding.

Sorry But I didn't find the core function support to use simply. The core function is too complicated for me.

What did you try and in what way was it complicated? There's lots of other drivers using this and it's generally resulted in less code in the drivers so it seems this should be soemthing we can solve.

Quoted 8 lines
Quoted 6 lines

drivers/spi/spi-sunplus-sp7021.c line 326

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+	if (RW_phase == SPI_SLAVE_WRITE) {
 
+	} else if (RW_phase == SPI_SLAVE_READ) {

These two cases share no code, they should probably be separate functions (and what happens if it's an unknown phase?).

The slave mode of SP7021 is only half duplex.

Not sure that really addresses the concern?

Quoted 8 lines
Quoted 6 lines

drivers/spi/spi-sunplus-sp7021.c line 615

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+	if (pspim->tx_cur_len < data_len) {
+		len_temp = min(pspim->data_unit, data_len);
+		sp7021spi_wb(pspim, len_temp);
+	}

What if there's more data?

SP7021 only support 16bytes FIFO transfer.

It can transfer more than one FIFO's worth of data though can't it?

Quoted 8 lines
Quoted 5 lines

I find it difficult to convince myself that this isn't going to have any overflow issues, and it'll break operation with anything that does any manipulation of chip select during the message. Given that the device uses GPIO chip selects I'd expect it to just implement transfer_one() and not handle messages at all. This would greatly simplify the code.

More conditions will be checked in the spi-message function. In this case, only rx-date is allocated for each transfer of the message.

Part of the issue with both this and the previous section is code clarity - it's not just if the code is correct, it's if it's clear that the code is correct.

Quoted 11 lines
Quoted 2 lines

So we are using transfer_one? In that case I'm very confused why the driver would be walking a transfer list...

And the spi of SP7021 includes two working modes: spi-master and spi-slave

SP7021 spi-master : full-duplex FIFO-mode only.
SP7021 spi-slave : helf-duplex DMA-mode

It seems that linux can contain these two modes in one drive. And this is what I need. Because many registers are overlapped, if they are used in different drives, they will crash if they are declared.

I think the driver needs to be restructured so it's clear which bits apply to which mode, it's basically two completely separate code paths. I have to say that it's really very surprising that the two different modes use such completely different control mechanisms, normally the differentiation would be more triggered by performance reasons.

#5 lore raw

Re: [PATCH 1/2] SPI: Add SPI driver for Sunplus SP7021

In reply to Mark Brown
Quoted 8 lines · Mark Brown
Quoted 1 line · LH.Kuo

Add SPI driver for Sunplus SP7021.

In general it looks like this needs quite a bit of a refresh for mainline - a lot of it looks to be a combination of minor, easily fixable things and stylistic issues which make things hard to follow but I think there are some more substantial things going on here as well.

Just looked at their UART driver submission with the similar idea in mind. Asked them to shrink the size 1.5-2x times. I believe this is possible (and yes, I already saw a new version which is better, but can be cleaned up more).

Folks, try again for all your drivers for this SoC.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#6 lore raw

Re: [PATCH 1/2] SPI: Add SPI driver for Sunplus SP7021

In reply to LH.Kuo

On Mon, 2021-11-01 at 14:18 +0800, LH.Kuo wrote:
[...]

drivers/spi/spi-sunplus-sp7021.c line 1065

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+static int pentagram_spi_controller_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+	int mode;
+	unsigned int max_freq;
+	struct spi_controller *ctlr;
+	struct pentagram_spi_master *pspim;
+
+	FUNC_DBG();

Drop these.

[...]

drivers/spi/spi-sunplus-sp7021.c line 1192

Quoted 7 lines
drivers/spi/spi-sunplus-sp7021.c new file +7 -0
+	/* clk*/
+	pspim->spi_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pspim->spi_clk)) {
+		dev_err(&pdev->dev, "devm_clk_get fail\n");
+		goto free_alloc;
+	}
+	ret = clk_prepare_enable(pspim->spi_clk);

Move this and reset_control_deassert() as far back as possible.

drivers/spi/spi-sunplus-sp7021.c line 1197

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+	if (ret)
+		goto free_alloc;
+
+	/* reset*/
+	pspim->rstc = devm_reset_control_get(&pdev->dev, NULL);

Use devm_reset_control_get_exclusive() instead.
This should be done before clk_prepare_enable().

drivers/spi/spi-sunplus-sp7021.c line 1204

Quoted 7 lines
drivers/spi/spi-sunplus-sp7021.c new file +7 -0
+	dev_dbg(&pdev->dev, "pspim->rstc : 0x%x\n", (unsigned int)pspim->rstc);
+	if (IS_ERR(pspim->rstc)) {
+		ret = PTR_ERR(pspim->rstc);
+		dev_err(&pdev->dev, "SPI failed to retrieve reset controller: %d\n", ret);
+		goto free_clk;
+	}
+	ret = reset_control_deassert(pspim->rstc);

Same as the clock, I'd move this after the dma allocations.

drivers/spi/spi-sunplus-sp7021.c line 1210

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+	if (ret)
+		goto free_clk;
+
+	/* dma alloc*/
+	pspim->tx_dma_vir_base = dma_alloc_coherent(&pdev->dev, bufsiz,
+					&pspim->tx_dma_phy_base, GFP_ATOMIC);

Consider using dmam_alloc_coherent, same for rx_dma_vir_base.

regards
Philipp

#7 lore raw

Re: [PATCH 1/2] SPI: Add SPI driver for Sunplus SP7021

In reply to LH.Kuo

drivers/spi/spi-sunplus-sp7021.c line 1081

Quoted 6 lines · LH.Kuo
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+	if (mode == SPI_SLAVE)
+		ctlr = spi_alloc_slave(&pdev->dev, sizeof(*pspim));
+	else
+		ctlr = spi_alloc_master(&pdev->dev, sizeof(*pspim));
+	if (!ctlr)
+		return -ENOMEM;

You need to use devm_spi_alloc_master() and devm_spi_alloc_slave() here to avoid a use-after-free in pentagram_spi_controller_remove():

That's because spi_unregister_master() frees the spi_controller struct and the adjacent pspim allocation and pentagram_spi_controller_remove() accesses pspim afterwards.

The allocation is *not* freed by spi_unregister_master() if the devm_* variants are used for allocation. Rather, the allocation is freed only after pentagram_spi_controller_remove() has finished.

drivers/spi/spi-sunplus-sp7021.c line 1249

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+free_alloc:
+	spi_controller_put(ctlr);

This can be dropped if the devm_* variants are used for allocation.

drivers/spi/spi-sunplus-sp7021.c line 1270

Quoted 1 line
drivers/spi/spi-sunplus-sp7021.c new file +1 -0
+	spi_unregister_master(pspim->ctlr);

Please use spi_unregister_controller() here. (It could be a slave.)

Thanks,

Lukas

author maintainer
#8 lore raw

PATCH 2/2 devicetree bindings SPI Add bindings doc for Sunplus SP7021

In reply to LH.Kuo

Add devicetree bindings SPI Add bindings doc for Sunplus SP7021

---
 .../bindings/spi/spi-sunplus-sp7021.yaml           | 95 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 96 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +95 -0
new file mode 100644
index 0000000..3ce90db
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-sunplus-sp7021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus sp7021 SPI controller
+
+allOf:
+  - $ref: "spi-controller.yaml"
+
+maintainers:
+  - lh.kuo <[email protected]>
+
+properties:
+  compatible:
+    enum:
+      - sunplus,sp7021-spi-controller
+
+  reg:
+    items:
+      - description: Base address and length of the SPI master registers
+      - description: Base address and length of the SPI slave registers
+
+  reg-names:
+    items:
+      - const: spi_master
+      - const: spi_slave
+
+  interrupt-names:
+    items:
+      - const: dma_w_intr
+      - const: mas_risc_intr
+      - const: slave_risc_intr
+
+  interrupts:
+    minItems: 3
+
+  clocks:
+    maxItems: 1
+
+  clocks-names:
+    items:
+      - const: sys_pll
+
+  resets:
+    maxItems: 1
+
+  pinctrl-names:
+    description:
+      A pinctrl state named "default" must be defined.
+    const: default
+
+  pinctrl-0:
+    description:
+      A phandle to the default pinctrl state.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clocks-names
+  - resets
+  - pinctrl-names
+  - pinctrl-0
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/sp-sp7021.h>
+    #include <dt-bindings/reset/sp-sp7021.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi_controller0: spi@9C002D80 {
+        compatible = "sunplus,sp7021-spi-controller";
+        reg = <0x9C002D80 0x80>, <0x9C002E00 0x80>;
+        reg-names = "spi_master", "spi_slave";
+        interrupt-parent = <&intc>;
+        interrupt-names = "dma_w_intr",
+                          "mas_risc_intr",
+                          "slave_risc_intr";
+        interrupts = <144 IRQ_TYPE_LEVEL_HIGH>,
+                     <146 IRQ_TYPE_LEVEL_HIGH>,
+                     <145 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clkc SPI_COMBO_0>;
+        clocks-names = "sys_pll";
+        resets = <&rstc RST_SPI_COMBO_0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pins_spi0>;
+    };
+...
MAINTAINERS +1 -0
index f00c466..f6cf9d8 100644
@@ -17949,6 +17949,7 @@ SUNPLUS SPI CONTROLLER INTERFACE DRIVER
 M:	LH Kuo <[email protected]>
 L:	[email protected] (subscribers-only)
 S:	Maintained
+F:	Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
 F:	drivers/spi/spi-sunplus-sp7021.c
 
 SUPERH
Signature · 1 line
2.7.4
author maintainer
#9 lore raw

v2 cover Add SPI control driver for Sunplus SP7021 SoC

In reply to LH.Kuo

This is a patch series for SPI driver for Sunplus SP7021 SoC.

Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates many peripherals (ex: UART, I2C, SPI, SDIO, eMMC, USB, SD card and etc.) into a single chip. It is designed for industrial control.

Refer to:
https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
https://tibbo.com/store/plus1.html

LH.Kuo (2):
SPI: Add SPI driver for Sunplus SP7021
devicetree bindings SPI Add bindings doc for Sunplus SP7021

 .../bindings/spi/spi-sunplus-sp7021.yaml           |   95 ++
 MAINTAINERS                                        |    7 +
 drivers/spi/Kconfig                                |   11 +
 drivers/spi/Makefile                               |    1 +
 drivers/spi/spi-sunplus-sp7021.c                   | 1043 ++++++++++++++++++++
 5 files changed, 1157 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
 create mode 100644 drivers/spi/spi-sunplus-sp7021.c
Signature · 1 line
2.7.4
author maintainer
#10 lore raw

PATCH v2 1/2 SPI: Add SPI driver for Sunplus SP7021

Add SPI driver for Sunplus SP7021.

---
- Addressed all comments from Mr. Mark Brown
- Addressed all comments from Mr. Philipp Zabel
- Modified the structure and register access method.

 MAINTAINERS                      |    6 +
 drivers/spi/Kconfig              |   11 +
 drivers/spi/Makefile             |    1 +
 drivers/spi/spi-sunplus-sp7021.c | 1043 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 1061 insertions(+)
 create mode 100644 drivers/spi/spi-sunplus-sp7021.c
MAINTAINERS +6 -0
index 170bbbe..34868d0 100644
@@ -18189,6 +18189,12 @@ L:	[email protected]
 S:	Maintained
 F:	drivers/net/ethernet/dlink/sundance.c
 
+SUNPLUS SPI CONTROLLER INTERFACE DRIVER
+M:	LH Kuo <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	drivers/spi/spi-sunplus-sp7021.c
+
 SUPERH
 M:	Yoshinori Sato <[email protected]>
 M:	Rich Felker <[email protected]>
drivers/spi/Kconfig +11 -0
index 596705d..30ce0ed 100644
@@ -866,6 +866,17 @@ config SPI_SUN6I
 	help
 	  This enables using the SPI controller on the Allwinner A31 SoCs.
 
+config SPI_SUNPLUS_SP7021
+	tristate "Sunplus SP7021 SPI controller"
+	depends on SOC_SP7021
+	help
+	  This enable Sunplus SP7021 spi controller driver on the SP7021 SoCs.
+	  This driver can also be built as a module. If so, the module will be
+	  called as spi-sunplus-sp7021.
+
+	  If you have a  Sunplus SP7021 platform say Y here.
+	  If unsure, say N.
+
 config SPI_SYNQUACER
 	tristate "Socionext's SynQuacer HighSpeed SPI controller"
 	depends on ARCH_SYNQUACER || COMPILE_TEST
drivers/spi/Makefile +1 -0
index dd7393a..b455eaf 100644
@@ -119,6 +119,7 @@ obj-$(CONFIG_SPI_STM32_QSPI) 		+= spi-stm32-qspi.o
 obj-$(CONFIG_SPI_ST_SSC4)		+= spi-st-ssc4.o
 obj-$(CONFIG_SPI_SUN4I)			+= spi-sun4i.o
 obj-$(CONFIG_SPI_SUN6I)			+= spi-sun6i.o
+obj-$(CONFIG_SPI_SUNPLUS_SP7021)	+= spi-sunplus-sp7021.o
 obj-$(CONFIG_SPI_SYNQUACER)		+= spi-synquacer.o
 obj-$(CONFIG_SPI_TEGRA210_QUAD)		+= spi-tegra210-quad.o
 obj-$(CONFIG_SPI_TEGRA114)		+= spi-tegra114.o
drivers/spi/spi-sunplus-sp7021.c new file +1043 -0

1,043 lines not on this page · raw message

Signature · 1 line
2.7.4
maintainer
#11 lore raw

Re: [PATCH v2 1/2] SPI: Add SPI driver for Sunplus SP7021

On Tue, Nov 09, 2021 at 05:01:27PM +0800, LH.Kuo wrote:

A lot of my previous feedback on this driver still applies, while some of the issues have been addressed most of the major structural issues continue to apply here. A lot of the code is replicating code from the core or is really hard to explain, it's hard to see anything super unusual with the hardware here that would require such unusual code.

Please don't ignore review comments, people are generally making them for a reason and are likely to have the same concerns if issues remain unaddressed. Having to repeat the same comments can get repetitive and make people question the value of time spent reviewing. If you disagree with the review comments that's fine but you need to reply and discuss your concerns so that the reviewer can understand your decisions.

drivers/spi/spi-sunplus-sp7021.c line 158

Quoted 11 lines
drivers/spi/spi-sunplus-sp7021.c new file +11 -0
+static void sp7021_spi_set_cs(struct spi_device *_s, bool _on)
+{
+	if (_s->mode & SPI_NO_CS)
+		return;
+	if (!(_s->cs_gpiod))
+		return;
+	dev_dbg(&(_s->dev), "%d gpiod:%d", _on, desc_to_gpio(_s->cs_gpiod));
+	if (_s->mode & SPI_CS_HIGH)
+		_on = !_on;
+	gpiod_set_value_cansleep(_s->cs_gpiod, _on);
+}

This is *still* open coding a GPIO chip select, to repeat what I said last time this is not OK - use the core facilities to avoid introducing bugs like double application of SPI_CS_HIGH you have here.

drivers/spi/spi-sunplus-sp7021.c line 163

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+// spi slave irq handler
+static irqreturn_t sp7021_spi_sla_irq(int _irq, void *_dev)
+{
+	struct sp7021_spi_ctlr *pspim = (struct sp7021_spi_ctlr *)_dev;

If you need this cast something is very wrong, do you need it?

Quoted 1 line

+int sp7021_spi_sla_rw(struct spi_device *_s, struct spi_transfer *_t, int RW_phase)

Please use the normal kernel coding style, using _s for parameter names or mixed case symbol names isn't normal for the kernel. There's also issues with line lengths over 80 columns all over, while it's not a strict limit it's still good try to keep things to a reasonable length.

drivers/spi/spi-sunplus-sp7021.c line 194

Quoted 1 line
drivers/spi/spi-sunplus-sp7021.c new file +1 -0
+	if (RW_phase == SP7021_SLA_WRITE) {

This looks like a switch statement, though given how little code is shared it's not clear why this is all in one function.

drivers/spi/spi-sunplus-sp7021.c line 198

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+		if (_t->tx_dma == pspim->tx_dma_phy_base)
+			memcpy(pspim->tx_dma_vir_base, _t->tx_buf, _t->len);

Why are we copying data into a DMA transfer buffer, doesn't this defeat the point of DMA? I'd expect to DMA data directly. I'd also expect some synchronisation operations to ensure that everything has a consistent view of the memory.

drivers/spi/spi-sunplus-sp7021.c line 238

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+// spi master irq handler
+static irqreturn_t sp7021_spi_mas_irq_dma(int _irq, void *_dev)
+{
+	struct sp7021_spi_ctlr *pspim = (struct sp7021_spi_ctlr *)_dev;
+
+	spin_lock_irq(&pspim->lock);

Why are we using spin_lock_irq() when we're already in an interrupt handler?

drivers/spi/spi-sunplus-sp7021.c line 255

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+	}
+}
+void sp7021spi_wb(struct sp7021_spi_ctlr *_m, u8 _len)

Blank lines between functions.

drivers/spi/spi-sunplus-sp7021.c line 322

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+fin_irq:
+	if (isrdone)
+		complete(&pspim->isr_done);
+	spin_unlock_irqrestore(&pspim->lock, flags);
+	return IRQ_HANDLED;
+}

This unconditionally reports IRQ_HANDLED even if we didn't actually see any interrupt status flagged, this will break shared interrupts and reduce the ability of the interrupt core to handle errors.

drivers/spi/spi-sunplus-sp7021.c line 385

Quoted 8 lines
drivers/spi/spi-sunplus-sp7021.c new file +8 -0
+	for (i = 0; i < transfers_cnt; i++) {
+		if (t->tx_buf)
+			memcpy(&pspim->tx_data_buf[data_len], t->tx_buf, t->len);
+		if (t->rx_buf)
+			xfer_rx = true;
+		data_len += t->len;
+		t = list_entry(t->transfer_list.next, struct spi_transfer, transfer_list);
+	}

This is still copying all data for no apparent reason as highlighted last time.

drivers/spi/spi-sunplus-sp7021.c line 392

Quoted 7 lines
drivers/spi/spi-sunplus-sp7021.c new file +7 -0
+	dev_dbg(&(_c->dev), "data_len %d xfer_rx %d", data_len, xfer_rx);
+
+	// set SPI FIFO data for full duplex (SPI_FD fifo_data)  91.13
+	if (pspim->tx_cur_len < data_len) {
+		len_temp = min(pspim->data_unit, data_len);
+		sp7021spi_wb(pspim, len_temp);
+	}

Is the device full duplex or half duplex? The code immediately above this treats both transmit and recieve buffers as optional. If the device does actually need to be full duplex then the driver should flag it as such.

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+// called when child device is registering on the bus
+static int sp7021_spi_dev_setup(struct spi_device *_s)
+{
+	struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(_s->controller);
+	int ret;

drivers/spi/spi-sunplus-sp7021.c line 545

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+
+	ret = pm_runtime_get_sync(pspim->dev);
+		if (ret < 0)
+			return 0;
+
+	pm_runtime_put(pspim->dev);
+
+	return 0;
+
+}

This function does nothing except bounce the power on the device, this is obviously not useful and should be removed.

drivers/spi/spi-sunplus-sp7021.c line 599

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+static int sp7021_spi_controller_unprepare_message(struct spi_controller *_c,
+				    struct spi_message *msg)
+{
+	return 0;
+}

Remove empty functions.

drivers/spi/spi-sunplus-sp7021.c line 604

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+static size_t sp7021_spi_max_length(struct spi_device *spi)
+{
+	return SP7021_SPI_MSG_SIZE;
+}

Is there any actual limit in the hardware? This looks very much like it's a completely artificial limit in the driver for no obvious reason.

drivers/spi/spi-sunplus-sp7021.c line 689

Quoted 11 lines
drivers/spi/spi-sunplus-sp7021.c new file +11 -0
+static int sp7021_spi_mas_transfer_one_message(struct spi_controller *_c, struct spi_message *m)
+{
+	struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(_c);
+	struct spi_device *spi = m->spi;
+	unsigned int xfer_cnt = 0, total_len = 0;
+	bool start_xfer = false;
+	struct spi_transfer *xfer, *first_xfer = NULL;
+	int ret;
+	bool keep_cs = false;
+
+	pm_runtime_get_sync(pspim->dev);

To repeat the feedback from last time do not open code runtime PM, use the core support.

drivers/spi/spi-sunplus-sp7021.c line 696

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+	sp7021_spi_set_cs(spi, true);
+
+	list_for_each_entry(xfer, &m->transfers, transfer_list) {
+		if (!first_xfer)
+			first_xfer = xfer;
+		total_len +=  xfer->len;

To further repeat my prior feedback I can't see any reason why this driver doesn't just use transfer_one().

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#13 lore raw

Re: [PATCH v2 1/2] SPI: Add SPI driver for Sunplus SP7021

On Wed, Nov 10, 2021 at 02:42:01AM +0000, Lh Kuo 郭力豪 wrote:

Please don't send new patches in reply to old patches or serieses, this makes it harder for both people and tools to understand what is going on - it can bury things in mailboxes and make it difficult to keep track of what current patches are, both for the new patches and the old ones.

Quoted 8 lines
Quoted 3 lines

This is *still* open coding a GPIO chip select, to repeat what I said last time this is not OK - use the core facilities to avoid introducing bugs like double application of SPI_CS_HIGH you have here.

I try to find some function can replay this part.
EX:
Spi.c -> spi_set_cs but it is not EXPORT_SYMBOL_GPL and it looks not fit in the driver

Quoted 7 lines

Spi-gpio.c -> spi_gpio_chipselect it looks not fit in the driver.

Sorry maybe i misunderstood this issue

Or the problem is gpiod_set_value_cansleep can't be used in here ?

Which function can I use for GPIO_CS?

The same way other controllers do: by setting use_gpio_descriptors in the controller. The core will then request the GPIOs for the driver using the standard binding, this requires no further work on the part of the driver.

Quoted 7 lines
Quoted 5 lines

drivers/spi/spi-sunplus-sp7021.c line 163

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+// spi slave irq handler
+static irqreturn_t sp7021_spi_sla_irq(int _irq, void *_dev) {
+	struct sp7021_spi_ctlr *pspim = (struct sp7021_spi_ctlr *)_dev;

If you need this cast something is very wrong, do you need it?

So the vold* should be struct * spi_controller ??

No, interrupt handlers need to take an int and a void *. There should be no cast.

Quoted 6 lines
Quoted 4 lines

drivers/spi/spi-sunplus-sp7021.c line 194

Quoted 1 line
drivers/spi/spi-sunplus-sp7021.c new file +1 -0
+	if (RW_phase == SP7021_SLA_WRITE) {

This looks like a switch statement, though given how little code is shared it's not clear why this is all in one function.

It is easy to check the flow and setting for me

It's contributing to making the code hard for other people to follow.

Quoted 10 lines
Quoted 7 lines

drivers/spi/spi-sunplus-sp7021.c line 198

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+		if (_t->tx_dma == pspim->tx_dma_phy_base)
+			memcpy(pspim->tx_dma_vir_base, _t->tx_buf, _t->len);

Why are we copying data into a DMA transfer buffer, doesn't this defeat the point of DMA? I'd expect to DMA data directly. I'd also expect some synchronisation operations to ensure that everything has a consistent view of the memory.

It only happens when tx_dma = pspim->tx_dma_phy_base
And if it can't get dma-addr or wrong case. I will set tx_dma = pspim->tx_dma_phy_base.

What does that mean at a higher level - what is tx_dma here? Why does not being able to get an address to DMA mean that we need to memcpy() things? I can't see any reason for the memcpy() at all.

Quoted 9 lines
Quoted 7 lines

drivers/spi/spi-sunplus-sp7021.c line 238

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+// spi master irq handler
+static irqreturn_t sp7021_spi_mas_irq_dma(int _irq, void *_dev) {
+	struct sp7021_spi_ctlr *pspim = (struct sp7021_spi_ctlr *)_dev;
 
+	spin_lock_irq(&pspim->lock);

Why are we using spin_lock_irq() when we're already in an interrupt handler?

Yes it is in interrupt handler

Yes, I know it's an interrupt handler - to repeat my question why are we we using spin_lock_irq() in that case?

Quoted 8 lines
Quoted 6 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+	return IRQ_HANDLED;
+}

This unconditionally reports IRQ_HANDLED even if we didn't actually see any interrupt status flagged, this will break shared interrupts and reduce the ability of the interrupt core to handle errors.

Sorry I'm confuse. What should i do in this issue

Report IRQ_NONE if there was no interrupts reported by the hardware.

Quoted 5 lines
Quoted 1 line

This is still copying all data for no apparent reason as highlighted last time.

It is difference case. It is in master mode and and can only be transmitted through FIFO

And It is transmitting for one message and I need collect the all tx data first.

For what reason do you need to collect all the tx data? It really is not at all apparent from the code and seems especially unusual in the PIO case.

Quoted 7 lines
Quoted 3 lines

Is the device full duplex or half duplex? The code immediately above this treats both transmit and recieve buffers as optional. If the device does actually need to be full duplex then the driver should flag it as such.

You mean set the flsg of should be struct * spi_controller in probe function

Ctlr-flags = SPI_CONTROLLER_FULL_DUPLEX right ?

Yes.

Quoted 19 lines
Quoted 4 lines

Review

Quoted 3 lines
(quoted diff) +3 -0
+// called when child device is registering on the bus static int
+sp7021_spi_dev_setup(struct spi_device *_s) {
+	struct sp7021_spi_ctlr *pspim =

spi_controller_get_devdata(_s->controller);

Quoted 14 lines

drivers/spi/spi-sunplus-sp7021.c line 545

Quoted 11 lines
drivers/spi/spi-sunplus-sp7021.c new file +11 -0
+	int ret;
+
+	ret = pm_runtime_get_sync(pspim->dev);
+		if (ret < 0)
+			return 0;
+
+	pm_runtime_get_sync(pspim->dev);;
+
+	return 0;
+
+}

This function does nothing except bounce the power on the device, this is obviously not useful and should be removed.

Quoted 6 lines

You mean set the auto_runtime_pm of should be struct * spi_controller in probe function And remove pm_runtime_get_sync(pspim->dev);

pm_runtime_get_sync(pspim->dev);

even the pm_runtime in the probe should be remove . right ?

You should only take a runtime reference for the period that it's actually needed. Taking one in probe and then not dropping it before the end of probe would defeat the point of having runtime PM.

Quoted 9 lines
Quoted 6 lines

drivers/spi/spi-sunplus-sp7021.c line 604

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+static size_t sp7021_spi_max_length(struct spi_device *spi) {
+	return SP7021_SPI_MSG_SIZE;
+}

Is there any actual limit in the hardware? This looks very much like it's a completely artificial limit in the driver for no obvious reason.

The limit of the hardware is only 255 bytes . But more user need more than the limit.
So I try to extend by software that is one reason use one message transfer and use CS-GPIO

As ever *please* use the core features rather than open coding - if you specify a maximum transfer size the core already supports using a software controllable chip select to handle messages with transfers of arbatrary lengths. There is no need for the driver to do anything here other than providing a length, but that needs to be per transfer and not per message.

In general if you're doing something that doesn't interact directly with the hardware it shouldn't be in the driver, it's a pure software thing which will also apply to any other similar hardware and should therefore be done in the core.

Quoted 6 lines
Quoted 4 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	pm_runtime_get_sync(pspim->dev);

To repeat the feedback from last time do not open code runtime PM, use the core support.

Only set set the auto_runtime_pm of should be struct * spi_controller in probe function right ?

Yes.

Quoted 11 lines
Quoted 7 lines

drivers/spi/spi-sunplus-sp7021.c line 696

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+	list_for_each_entry(xfer, &m->transfers, transfer_list) {
+		if (!first_xfer)
+			first_xfer = xfer;
+		total_len +=  xfer->len;

To further repeat my prior feedback I can't see any reason why this driver doesn't just use transfer_one().

The FIFO only 16bytes for one action. I need push tx_data and pull rx_data as soon as possible. Use one message I can collect the data first and start transmitting
It is more efficient than transfer_one at real case.

That doesn't mean it's a good idea to just duplicate the core code, that means that you should look into improving the performance of the core code so any optimisation benefits everyone and the driver doesn't end up with some combination of bugs, missing features and reduced performance in the open coded version. Having small FIFOs isn't at all unusual so it seems unlikely that there's any need for anything here to be device specific, and any benefits from copying all the data into a linear buffer have got to be application specific, indeed it'll clearly make things worse in some common cases. For example with something like flash where we have frequent use of large transfers for data payloads the data is already mostly in large buffers the overhead of copying those buffers is going to be very noticable compared to any saving, especially given that there's only two transfers. On the other end of things when something like regmap is already linearising small writes into single transfers then the copy is just pure overhead.

There's definitely scope for improving things here, the main one being to pull advancing to the next transfer into spi_finalize_current_transfer() which would benefit DMA as well, that don't introduce these overheads and don't involve all this code duplication.

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#15 lore raw

Re: [PATCH v2 1/2] SPI: Add SPI driver for Sunplus SP7021

On Thu, Nov 11, 2021 at 08:32:39AM +0000, Lh Kuo 郭力豪 wrote:

Please fix your mail client to word wrap within paragraphs at something substantially less than 80 columns. Doing this makes your messages much easier to read and reply to.

Quoted 6 lines

#define SPI_CS_HIGH 0x04 /* chipselect active high? */
Is it mean?
CASE1 : standby, CS high => start transfer CS become low => transfer end CS become high and standby CASE2 : standby, CS low => start transfer CS become high => transfer end CS become low and standby

I think SPI_CS_HIGH means CASE2, But it is strange that more chipset work in CASE1 but drivers set SPI_CS_HIGH as defined.

SPI_CS_HIGH is case 2.

Quoted 4 lines

2. And in the CASE1 I should set
cs_gpios = <gpio 3 2 GPIO_ACTIVE_LOW>,
or
cs_gpios = <gpio 3 2 GPIO_ACTIVE_HIGH>,

_ACTIVE_HIGH if _CS_HIGH is specified, though the binding will try to sort things out either way.

Quoted 3 lines

3. If I did not set the max_transfer_size of spi_control
And use transfer_one set max_transfer_size and use_gpio_descriptors
Can it transmit data that exceeds FIFO max bytes (even exceed HW's one-time transfer) in one transmission activity?

Yes, if you don't set a maximum transfer size the driver might get any transfer size. If you set a maximum transfer size then the driver will not see any transfers that exceed the maximum transfer size.

Quoted 1 line

This is my concern, so I use Transfer_One_message

I can't understand how that would follow on. If there's a limit on the size of an individual transfer then tell the framework about that limit, that's all that needs doing. Why would it be preferable to not tell the core about the limit and instead open code things?

*Please* think about the lengthy explanation I provided in my last message about putting things that are not device specific in the framework not the driver.

Quoted 7 lines

Ex : Need to transmit 4000 bytes.
Then I set Ctlr->transfer_one and use_gpio_descriptors
ctlr->max_transfer_size = 255;
The CS of device is low active

When the transmission starts, I can see the signal gpio-CS changes from high to low
Ctlr->transfer_one will be triggered to execute 16 times, and transfer end gpio-CS changes from low to high.

This is exactly what will happen if you do as has been repeatedly suggested. Set a maximum *transfer* (not message) size, let the core handle the chip select GPIO and implement transfer_one().

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#17 lore raw

Re: [PATCH v2 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 10 lines · Lh Kuo 郭力豪

The main function are as follows

The sp7021_spi_mas_transfer_one is replace the transfer_one_message function.

static int sp7021_spi_mas_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi, struct spi_transfer *xfer)

{
	struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
	u32 reg_temp = 0;
	unsigned long timeout = msecs_to_jiffies(1000);

I'm still not clear why this needs to be transfer_one_message() and not just transfer_one()? The whole thing with copying everything into a buffer is a bit confusing to me.

Quoted 8 lines

The probe function is as follows.

static int sp7021_spi_controller_probe(struct platform_device *pdev)

{
	int ret;
	int mode;
	struct spi_controller *ctlr;
	struct sp7021_spi_ctlr *pspim;

This looks fine.

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#19 lore raw

Re: [PATCH v2 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 1 line · Lh Kuo 郭力豪

The driver made a lot of changes. Which function do you want to check first, or can i make a new patch ? And we can review on this basis.

It will be easiest to send a new patch. The bits you included here looked fine at first glance.

#20 lore raw

Re: [PATCH v2 1/2] SPI: Add SPI driver for Sunplus SP7021

In reply to LH.Kuo

drivers/spi/Kconfig config SPI_SUN6I · line 873

Quoted 13 lines · LH.Kuo
drivers/spi/Kconfig +5 -0
index 596705d..30ce0ed 100644
@@ -866,6 +866,17 @@ config SPI_SUN6I
  	help
  	  This enables using the SPI controller on the Allwinner A31 SoCs.
 
+config SPI_SUNPLUS_SP7021
+	tristate "Sunplus SP7021 SPI controller"
+	depends on SOC_SP7021
+	help
+	  This enable Sunplus SP7021 spi controller driver on the SP7021 SoCs.

enables the Sunplus SP021 SPI

drivers/spi/Kconfig config SPI_SUN6I · line 877

Quoted 4 lines
drivers/spi/Kconfig +4 -0
+	  This driver can also be built as a module. If so, the module will be
+	  called as spi-sunplus-sp7021.
+
+	  If you have a  Sunplus SP7021 platform say Y here.

have a Sunplus
(i.e., drop one space)

Quoted 1 line
drivers/spi/Kconfig +1 -0
+	  If unsure, say N.
Signature · 1 line
~Randy

A message that is not in the archive (sent off-list or not yet received): [email protected]

#22 lore raw

Re: [PATCH v2 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 41 lines · Lh Kuo 郭力豪

Hi

Quoted 35 lines

-----Original Message-----
From: Randy Dunlap <[email protected]>
Sent: Wednesday, November 10, 2021 12:55 AM
To: LH.Kuo <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Cc: [email protected]; [email protected]; Wells Lu 呂芳騰 <[email protected]>; Lh Kuo 郭力豪 <[email protected]>
Subject: Re: [PATCH v2 1/2] SPI: Add SPI driver for Sunplus SP7021

drivers/spi/Kconfig config SPI_SUN6I · line 873

Quoted 13 lines · LH.Kuo
drivers/spi/Kconfig index renamed from drivers/spi/Kconfig +0 -0

596705d..30ce0ed 100644

drivers/spi/Kconfig +5 -0
@@ -866,6 +866,17 @@ config SPI_SUN6I
   	help
   	  This enables using the SPI controller on the Allwinner A31 SoCs.
 
+config SPI_SUNPLUS_SP7021
+	tristate "Sunplus SP7021 SPI controller"
+	depends on SOC_SP7021
+	help
+	  This enable Sunplus SP7021 spi controller driver on the SP7021 SoCs.

enables the Sunplus SP021 SPI

drivers/spi/Kconfig config SPI_SUN6I · line 877

Quoted 4 lines
drivers/spi/Kconfig +4 -0
+	  This driver can also be built as a module. If so, the module will be
+	  called as spi-sunplus-sp7021.
+
+	  If you have a  Sunplus SP7021 platform say Y here.

have a Sunplus
(i.e., drop one space)

Quoted 3 lines

drivers/spi/Kconfig config SPI_SUN6I · line 878

Quoted 1 line
drivers/spi/Kconfig +1 -0
+	  If unsure, say N.
Quoted 7 lines

I will make change as below is it OK ?

config SPI_SUNPLUS_SP7021
tristate "Sunplus SP7021 SPI controller"
depends on SOC_SP7021
help
This enable Sunplus SP7021 spi controller driver on the SP7021 SoCs.

enables SPI

Quoted 4 lines

This driver can also be built as a module. If so, the module will be called as spi-sunplus-sp7021.

If you have a Sunplus SP7021 platform say Y here.

drop one space: a Sunplus

Quoted 5 lines

If unsure, say N.

Quoted 2 lines

--
~Randy

Signature · 1 line
~Randy
author maintainer
#23 lore raw

PATCH v2 2/2 devicetree bindings SPI Add bindings doc for Sunplus SP7021

In reply to LH.Kuo

Add devicetree bindings SPI Add bindings doc for Sunplus SP7021

---
- Addressed all comments from Mr. Mark Brown
- Addressed all comments from Mr. Philipp Zabel
- Modified the structure and register access method.

 .../bindings/spi/spi-sunplus-sp7021.yaml           | 95 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 96 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +95 -0
new file mode 100644
index 0000000..5502f15
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-sunplus-sp7021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus sp7021 SPI controller
+
+allOf:
+  - $ref: "spi-controller.yaml"
+
+maintainers:
+  - lh.kuo <[email protected]>
+
+properties:
+  compatible:
+    enum:
+      - sunplus,sp7021-spi-controller
+
+  reg:
+    items:
+      - description: Base address and length of the SPI master registers
+      - description: Base address and length of the SPI slave registers
+
+  reg-names:
+    items:
+      - const: spi_master
+      - const: spi_slave
+
+  interrupt-names:
+    items:
+      - const: dma_w_intr
+      - const: mas_risc_intr
+      - const: slave_risc_intr
+
+  interrupts:
+    minItems: 3
+
+  clocks:
+    maxItems: 1
+
+  clocks-names:
+    items:
+      - const: sys_pll
+
+  resets:
+    maxItems: 1
+
+  pinctrl-names:
+    description:
+      A pinctrl state named "default" must be defined.
+    const: default
+
+  pinctrl-0:
+    description:
+      A phandle to the default pinctrl state.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clocks-names
+  - resets
+  - pinctrl-names
+  - pinctrl-0
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/sp-sp7021.h>
+    #include <dt-bindings/reset/sp-sp7021.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi@9C002D80 {
+        compatible = "sunplus,sp7021-spi-controller";
+        reg = <0x9C002D80 0x80>, <0x9C002E00 0x80>;
+        reg-names = "spi_master", "spi_slave";
+        interrupt-parent = <&intc>;
+        interrupt-names = "dma_w_intr",
+                          "mas_risc_intr",
+                          "slave_risc_intr";
+        interrupts = <144 IRQ_TYPE_LEVEL_HIGH>,
+                     <146 IRQ_TYPE_LEVEL_HIGH>,
+                     <145 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clkc SPI_COMBO_0>;
+        clocks-names = "sys_pll";
+        resets = <&rstc RST_SPI_COMBO_0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pins_spi0>;
+    };
+...
MAINTAINERS +1 -0
index 34868d0..ef416a2 100644
@@ -18193,6 +18193,7 @@ SUNPLUS SPI CONTROLLER INTERFACE DRIVER
 M:	LH Kuo <[email protected]>
 L:	[email protected]
 S:	Maintained
+F:	Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
 F:	drivers/spi/spi-sunplus-sp7021.c
 
 SUPERH
Signature · 1 line
2.7.4
maintainer
#24 lore raw

Re: [PATCH v2 2/2] devicetree bindings SPI Add bindings doc for Sunplus SP7021

Quoted 1 line · LH.Kuo

Add devicetree bindings SPI Add bindings doc for Sunplus SP7021

Please submit patches using subject lines reflecting the style for the subsystem, this makes it easier for people to identify relevant patches. Look at what existing commits in the area you're changing are doing and make sure your subject lines visually resemble what they're doing. There's no need to resubmit to fix this alone.

Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml line 29

Quoted 9 lines
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +9 -0
+  reg:
+    items:
+      - description: Base address and length of the SPI master registers
+      - description: Base address and length of the SPI slave registers
+
+  reg-names:
+    items:
+      - const: spi_master
+      - const: spi_slave

What exactly is the physical overlap between the two controllers - is it just the pinmux?

A message that is not in the archive (sent off-list or not yet received): [email protected]

maintainer
#26 lore raw

Re: [PATCH v2 2/2] devicetree bindings SPI Add bindings doc for Sunplus SP7021

Quoted 11 lines · Lh Kuo 郭力豪
Quoted 7 lines

Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml line 29

Quoted 4 lines
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +4 -0
+  reg-names:
+    items:
+      - const: spi_master
+      - const: spi_slave

What exactly is the physical overlap between the two controllers - is it just the pinmux?

According to the designer not only pinmux, The power source and more design are overlap.

That is why I hope set it in one driver.

The power source just sounds like a power domain which doesn't need a shared driver, and shared elements in the design aren't really relevant if they're not visible in the usage of the device which given the very limited code sharing there seems to be in the driver doesn't seem to be the case here.

author maintainer
#27 lore raw

v3 cover Add SPI control driver for Sunplus SP7021 SoC

In reply to LH.Kuo

This is a patch series for SPI driver for Sunplus SP7021 SoC.

Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates many peripherals (ex: UART, I2C, SPI, SDIO, eMMC, USB, SD card and etc.) into a single chip. It is designed for industrial control.

Refer to:
https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
https://tibbo.com/store/plus1.html

LH.Kuo (2):
SPI: Add SPI driver for Sunplus SP7021
devicetree: bindings SPI Add bindings doc for Sunplus SP7021

 .../bindings/spi/spi-sunplus-sp7021.yaml           |  95 +++
 MAINTAINERS                                        |   7 +
 drivers/spi/Kconfig                                |  11 +
 drivers/spi/Makefile                               |   1 +
 drivers/spi/spi-sunplus-sp7021.c                   | 706 +++++++++++++++++++++
 5 files changed, 820 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
 create mode 100644 drivers/spi/spi-sunplus-sp7021.c
Signature · 1 line
2.7.4
author maintainer
#28 lore raw

PATCH v3 1/2 SPI: Add SPI driver for Sunplus SP7021

Add SPI driver for Sunplus SP7021.

---
Changes in v3:
- Addressed all comments from Mr. Mark Brown
- Addressed all comments from Mr. Philipp Zabel
- Addressed all comments from Mr. Rob Herring
- remove spi transfer_one_message

 MAINTAINERS                      |   6 +
 drivers/spi/Kconfig              |  11 +
 drivers/spi/Makefile             |   1 +
 drivers/spi/spi-sunplus-sp7021.c | 706 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 724 insertions(+)
 create mode 100644 drivers/spi/spi-sunplus-sp7021.c
MAINTAINERS +6 -0
index 5250298..75fa7d5 100644
@@ -18216,6 +18216,12 @@ L:	[email protected]
 S:	Maintained
 F:	drivers/net/ethernet/dlink/sundance.c
 
+SUNPLUS SPI CONTROLLER INTERFACE DRIVER
+M:	LH Kuo <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	drivers/spi/spi-sunplus-sp7021.c
+
 SUPERH
 M:	Yoshinori Sato <[email protected]>
 M:	Rich Felker <[email protected]>
drivers/spi/Kconfig +11 -0
index 596705d..30ce0ed 100644
@@ -866,6 +866,17 @@ config SPI_SUN6I
 	help
 	  This enables using the SPI controller on the Allwinner A31 SoCs.
 
+config SPI_SUNPLUS_SP7021
+	tristate "Sunplus SP7021 SPI controller"
+	depends on SOC_SP7021
+	help
+	  This enable Sunplus SP7021 spi controller driver on the SP7021 SoCs.
+	  This driver can also be built as a module. If so, the module will be
+	  called as spi-sunplus-sp7021.
+
+	  If you have a  Sunplus SP7021 platform say Y here.
+	  If unsure, say N.
+
 config SPI_SYNQUACER
 	tristate "Socionext's SynQuacer HighSpeed SPI controller"
 	depends on ARCH_SYNQUACER || COMPILE_TEST
drivers/spi/Makefile +1 -0
index dd7393a..b455eaf 100644
@@ -119,6 +119,7 @@ obj-$(CONFIG_SPI_STM32_QSPI) 		+= spi-stm32-qspi.o
 obj-$(CONFIG_SPI_ST_SSC4)		+= spi-st-ssc4.o
 obj-$(CONFIG_SPI_SUN4I)			+= spi-sun4i.o
 obj-$(CONFIG_SPI_SUN6I)			+= spi-sun6i.o
+obj-$(CONFIG_SPI_SUNPLUS_SP7021)	+= spi-sunplus-sp7021.o
 obj-$(CONFIG_SPI_SYNQUACER)		+= spi-synquacer.o
 obj-$(CONFIG_SPI_TEGRA210_QUAD)		+= spi-tegra210-quad.o
 obj-$(CONFIG_SPI_TEGRA114)		+= spi-tegra114.o
drivers/spi/spi-sunplus-sp7021.c new file +706 -0

706 lines not on this page · raw message

Signature · 1 line
2.7.4
#29 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 2 lines · LH.Kuo

Add SPI driver for Sunplus SP7021.

Much better, but needs more work to be good enough, see my comments below.

...

drivers/spi/Kconfig config SPI_SUN6I · line 873

Quoted 5 lines
drivers/spi/Kconfig +5 -0
+config SPI_SUNPLUS_SP7021
+       tristate "Sunplus SP7021 SPI controller"
+       depends on SOC_SP7021
+       help
+         This enable Sunplus SP7021 spi controller driver on the SP7021 SoCs.

enables
SPI

Quoted 5 lines
drivers/spi/Kconfig +5 -0
+         This driver can also be built as a module. If so, the module will be
+         called as spi-sunplus-sp7021.
+
+         If you have a  Sunplus SP7021 platform say Y here.
+         If unsure, say N.

...

drivers/spi/spi-sunplus-sp7021.c line 2

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+// SPDX-License-Identifier: GPL-2.0-only
 
+//

Do you need this line?

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+// Copyright (c) 2021 Sunplus Inc.
+// Author: LH Kuo <[email protected]>

...

drivers/spi/spi-sunplus-sp7021.c line 18

Quoted 13 lines
drivers/spi/spi-sunplus-sp7021.c new file +13 -0
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>

Sort them, please.

...

Quoted 1 line

+#define SLAVE_INT_IN

What's this?

...

drivers/spi/spi-sunplus-sp7021.c line 26

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+#define SP7021_MAS_REG_NAME "spi_master"
+#define SP7021_SLA_REG_NAME "spi_slave"
+
+#define SP7021_MAS_IRQ_NAME "mas_risc_intr"
+#define SP7021_SLA_IRQ_NAME "slave_risc_intr"

Why do you need these?

...

Quoted 1 line

+#define SP7021_CLR_MAS_INT (1<<6)

Make use of BIT() and GENMASK() here and below.

drivers/spi/spi-sunplus-sp7021.c line 37

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+#define SP7021_SLA_DMA_READ (0xd)
+#define SP7021_SLA_SW_RST (1<<1)
+#define SP7021_SLA_DMA_WRITE (0x4d)
+#define SP7021_SLA_DMA_W_INT (1<<8)
+#define SP7021_SLA_CLR_INT (1<<8)
+#define SP7021_SLA_DATA_RDY (1<<0)

This is a mess. Make sure they are sorted by the value.
Also it's visible that bit 6 defines READ vs. WRITE (at least for DMA).

Quoted 43 lines
drivers/spi/spi-sunplus-sp7021.c new file +43 -0
+#define SP7021_CLR_MAS_W_INT (1<<7)
+
+#define SP7021_TOTAL_LENGTH(x) (x<<24)
+#define SP7021_TX_LENGTH(x) (x<<16)
+#define SP7021_GET_LEN(x)     ((x>>24)&0xFF)
+#define SP7021_GET_TX_LEN(x)  ((x>>16)&0xFF)
+#define SP7021_GET_RX_CNT(x)  ((x>>12)&0x0F)
+#define SP7021_GET_TX_CNT(x)  ((x>>8)&0x0F)
+
+#define SP7021_FINISH_FLAG (1<<6)
+#define SP7021_FINISH_FLAG_MASK (1<<15)
+#define SP7021_RX_FULL_FLAG (1<<5)
+#define SP7021_RX_FULL_FLAG_MASK (1<<14)
+#define SP7021_RX_EMP_FLAG (1<<4)
+#define SP7021_TX_EMP_FLAG (1<<2)
+#define SP7021_TX_EMP_FLAG_MASK (1<<11)
+#define SP7021_SPI_START_FD (1<<0)
+#define SP7021_FD_SEL (1<<6)
+#define SP7021_LSB_SEL (1<<4)
+#define SP7021_WRITE_BYTE(x) (x<<9)
+#define SP7021_READ_BYTE(x) (x<<7)
+#define SP7021_CLEAN_RW_BYTE (~0x780)
+#define SP7021_CLEAN_FLUG_MASK (~0xF800)
+
+#define SP7021_CPOL_FD (1<<0)
+#define SP7021_CPHA_R (1<<1)
+#define SP7021_CPHA_W (1<<2)
+#define SP7021_CS_POR (1<<5)
+
+#define SP7021_FD_SW_RST (1<<1)
+#define SP7021_FIFO_DATA_BITS (16*8)    // 16 BYTES
+#define SP7021_INT_BYPASS (1<<3)
+
+#define SP7021_FIFO_REG 0x0034
+#define SP7021_SPI_STATUS_REG 0x0038
+#define SP7021_SPI_CONFIG_REG 0x003c
+#define SP7021_INT_BUSY_REG 0x004c
+#define SP7021_DMA_CTRL_REG 0x0050
+
+#define SP7021_DATA_RDY_REG 0x0044
+#define SP7021_SLV_DMA_CTRL_REG 0x0048
+#define SP7021_SLV_DMA_LENGTH_REG 0x004c
+#define SP7021_SLV_DMA_ADDR_REG 0x004c

...

Quoted 1 line

+enum SPI_MODE {

Besides unneeded names, which may collide with generic definitions...

drivers/spi/spi-sunplus-sp7021.c line 86

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+       SP7021_SLA_READ = 0,
+       SP7021_SLA_WRITE = 1,
+       SP7021_SPI_IDLE = 2

...add a comma here, since it doesn't look like a terminator.

Quoted 1 line

+};

...

drivers/spi/spi-sunplus-sp7021.c line 92

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+enum {
+       SP7021_MASTER_MODE,
+       SP7021_SLAVE_MODE,
+};

Is it related to hardware? Then assign proper values explicitly.

...

drivers/spi/spi-sunplus-sp7021.c line 95

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+struct sp7021_spi_ctlr {
 
+

Redundant blank line.

drivers/spi/spi-sunplus-sp7021.c line 101

Quoted 6 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+       struct device *dev;
+       int mode;
+       struct spi_controller *ctlr;
 
+       void __iomem *mas_base;
+       void __iomem *sla_base;

Why do you need this to be separated?

drivers/spi/spi-sunplus-sp7021.c line 106

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+       u32 xfer_conf;
 
+       int mas_irq;
+       int sla_irq;

Ditto.

drivers/spi/spi-sunplus-sp7021.c line 115

Quoted 8 lines
drivers/spi/spi-sunplus-sp7021.c new file +8 -0
+       struct clk *spi_clk;
+       struct reset_control *rstc;
+
+       spinlock_t lock;
+       struct mutex buf_lock;
+
+       struct completion isr_done;
+       struct completion sla_isr;

Ditto.

Quoted 8 lines
drivers/spi/spi-sunplus-sp7021.c new file +8 -0
+       unsigned int  rx_cur_len;
+       unsigned int  tx_cur_len;
+
+       const u8 *tx_buf;
+       u8 *rx_buf;
+
+       unsigned int  data_unit;
+};

...

Quoted 1 line

+// spi slave irq handler

Useless comments.

...

Quoted 1 line

+// slave only. usually called on driver remove

Why is it so?
Also find use of proper English grammar (capitalization, periods, etc. Ditto for all your comments.

...

Quoted 1 line

+// slave R/W, called from S_transfer_one() only

Ditto here and for all similar comments. If you point out that something is called from something either explain why or drop useless comments since anybody can see what function called from which function (even indirectly).

...

drivers/spi/spi-sunplus-sp7021.c line 154

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+int sp7021_spi_sla_tx(struct spi_device *spi, struct spi_transfer *xfer)
+{
+       struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller);
 
+       struct device *devp = &(spi->dev);

Here and everywhere else, first of all we are using dev for struct device pointers, second there are too many parentheses.

Quoted 1 line

+ int err = 0;

What's the use? See below...

drivers/spi/spi-sunplus-sp7021.c line 168

Quoted 12 lines
drivers/spi/spi-sunplus-sp7021.c new file +11 -0
+       mutex_lock(&pspim->buf_lock);
+
+       reinit_completion(&pspim->sla_isr);
+
+       writel_relaxed(SP7021_SLA_DMA_WRITE, pspim->sla_base + SP7021_SLV_DMA_CTRL_REG);
+       writel_relaxed(xfer->len, pspim->sla_base + SP7021_SLV_DMA_LENGTH_REG);
+       writel_relaxed(xfer->tx_dma, pspim->sla_base + SP7021_SLV_DMA_ADDR_REG);
+       writel(readl(pspim->sla_base + SP7021_DATA_RDY_REG) | SP7021_SLA_DATA_RDY,
+                       pspim->sla_base + SP7021_DATA_RDY_REG);
 
+       if (wait_for_completion_interruptible(&pspim->sla_isr))
+               dev_err(devp, "%s() wait_for_completion timeout\n", __func__);

...seems you missed to assign proper error code.

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+       mutex_unlock(&pspim->buf_lock);
+       return err;
+}

...

Quoted 1 line

+exit_spi_slave_rw:

Make names of goto labels meaningful, what does above mean? What it should mean is what will be done when goto to it, i.e. out_unlock: in this case.

drivers/spi/spi-sunplus-sp7021.c line 173

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+       mutex_unlock(&pspim->buf_lock);
+       return err;
 
+

You need to clean up your code before submission. So, let's see -50 LOCs next time, I see it's achievable.

Quoted 1 line

+}

...

Quoted 11 lines
drivers/spi/spi-sunplus-sp7021.c new file +11 -0
+void sp7021_spi_mas_rb(struct sp7021_spi_ctlr *pspim, u8 len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               pspim->rx_buf[pspim->rx_cur_len] =
+                       readl(pspim->mas_base + SP7021_FIFO_REG);
+               pspim->rx_cur_len++;
+       }
+}
+

drivers/spi/spi-sunplus-sp7021.c line 222

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+void sp7021_spi_mas_wb(struct sp7021_spi_ctlr *pspim, u8 len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               writel(pspim->tx_buf[pspim->tx_cur_len],
+                       pspim->mas_base + SP7021_FIFO_REG);
+               pspim->tx_cur_len++;
+       }
+}

Are these NIH of readsl() / writesl()?

...

drivers/spi/spi-sunplus-sp7021.c line 230

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+       unsigned long flags;
+       struct sp7021_spi_ctlr *pspim = dev;
+       u32 fd_status = 0;
+       unsigned int tx_len, rx_cnt, tx_cnt, total_len;
+       bool isrdone = false;

Reversed xmas tree order here and everywhere else.

...

drivers/spi/spi-sunplus-sp7021.c line 277

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+               writel(readl(pspim->mas_base + SP7021_INT_BUSY_REG)
+                       | SP7021_CLR_MAS_INT, pspim->mas_base + SP7021_INT_BUSY_REG);

Use a temporary variable instead of this mess.

...

drivers/spi/spi-sunplus-sp7021.c line 291

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+static void sp7021_prep_transfer(struct spi_controller *ctlr,
+                       struct spi_device *spi)

One line?

...

drivers/spi/spi-sunplus-sp7021.c line 314

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+       // set clock
+       clk_rate = clk_get_rate(pspim->spi_clk);
+       div = clk_rate / xfer->speed_hz;
+
+       clk_sel = (div / 2) - 1;

When div == 0 is it okay to have this value for clk_sel?

...

Quoted 1 line

+ // set full duplex (bit 6) and fd freq (bits 31:16)

Useless, and use GENMASK()

drivers/spi/spi-sunplus-sp7021.c line 317

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+       rc = SP7021_FD_SEL | (0xffff << 16);
+       rs = SP7021_FD_SEL | ((clk_sel & 0xffff) << 16);

What' the point of having SP7021_FD_SEL in rc and rs simultaneously?

Quoted 1 line

+ writel((pspim->xfer_conf & ~rc) | rs, pspim->mas_base + SP7021_SPI_CONFIG_REG);

...

drivers/spi/spi-sunplus-sp7021.c line 331

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+       writel(readl(pspim->mas_base + SP7021_SPI_STATUS_REG) | SP7021_FD_SW_RST,
+                                       pspim->mas_base + SP7021_SPI_STATUS_REG);

Introduce proper IO accessors as other drivers do.

drivers/spi/spi-sunplus-sp7021.c line 334

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+       //set up full duplex frequency and enable  full duplex
+       rs = SP7021_FD_SEL | ((0xffff) << 16);

Seems like déjà-vu to me. Perhaps it makes sense to have a dedicated definition.

...

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+       unsigned long timeout = msecs_to_jiffies(1000);
+       unsigned int i;
+       int ret;
+       unsigned int xfer_cnt, xfer_len, last_len;

...

drivers/spi/spi-sunplus-sp7021.c line 374

Quoted 3 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+       for (i = 0; i <= xfer_cnt; i++) {
 
+

Redundant. As I said you have a lot of this kind of blank lines sparse over the code.

drivers/spi/spi-sunplus-sp7021.c line 385

Quoted 11 lines
drivers/spi/spi-sunplus-sp7021.c new file +11 -0
+               mutex_lock(&pspim->buf_lock);
+
+               sp7021_prep_transfer(ctlr, spi);
+               sp7021_spi_setup_transfer(spi, ctlr, xfer);
+
+               reinit_completion(&pspim->isr_done);
+
+               if (i == xfer_cnt)
+                       xfer_len = last_len;
+               else
+                       xfer_len = SP7021_SPI_DATA_SIZE;

If xfer_len == 0 does it make any sense to go via the entire loop?

...

drivers/spi/spi-sunplus-sp7021.c line 410

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+               if (!wait_for_completion_interruptible_timeout(&pspim->isr_done,
+                                                              timeout)){

One line? Also check wrong spacing.

...

Review

Quoted 2 lines
(quoted diff) +2 -0
+free_maste_xfer:
+       return ret;

Useless label. You may return directly. Actually the entire function needs a bit of care.

...

drivers/spi/spi-sunplus-sp7021.c line 479

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+                       dma_unmap_single(dev, xfer->tx_dma,
+                               xfer->len, DMA_TO_DEVICE);

One line

...

drivers/spi/spi-sunplus-sp7021.c line 483

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+                       dma_unmap_single(dev, xfer->rx_dma,
+                               xfer->len, DMA_FROM_DEVICE);

Ditto.

...

Quoted 1 line

+ pdev->id = 0;

Why?

...

drivers/spi/spi-sunplus-sp7021.c line 503

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+       if (pdev->dev.of_node) {
+               pdev->id = of_alias_get_id(pdev->dev.of_node, "sp_spi");

Ditto.

...

drivers/spi/spi-sunplus-sp7021.c line 505

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+               if (of_property_read_bool(pdev->dev.of_node, "spi-slave"))
+                       mode = SP7021_SLAVE_MODE;

There is no need to check of_node for this call.

...

Quoted 1 line

+ dev_dbg(&pdev->dev, "pdev->id = %d\n", pdev->id);

Useless.

...

Quoted 1 line

+ ctlr->dev.of_node = pdev->dev.of_node;

Use device_set_node().

...

drivers/spi/spi-sunplus-sp7021.c line 549

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+       pspim->mas_base = devm_platform_ioremap_resource_byname
+               (pdev, SP7021_MAS_REG_NAME);
+       pspim->sla_base = devm_platform_ioremap_resource_byname
+               (pdev, SP7021_SLA_REG_NAME);

Something is wrong with the indentation.

...

Quoted 1 line

+ dev_dbg(&pdev->dev, "mas_base 0x%x\n", (unsigned int)pspim->mas_base);

Redundant.

...

drivers/spi/spi-sunplus-sp7021.c line 555

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +3 -0
+       pspim->mas_irq = platform_get_irq_byname(pdev, SP7021_MAS_IRQ_NAME);
+       if (pspim->mas_irq < 0) {
 
+               dev_err(&pdev->dev, "failed to get %s\n", SP7021_MAS_IRQ_NAME);

Duplicate message printing.

drivers/spi/spi-sunplus-sp7021.c line 561

Quoted 7 lines
drivers/spi/spi-sunplus-sp7021.c new file +6 -0
+               return pspim->mas_irq;
+       }
+
+       pspim->sla_irq = platform_get_irq_byname(pdev, SP7021_SLA_IRQ_NAME);
+       if (pspim->sla_irq < 0) {
 
+               dev_err(&pdev->dev, "failed to get %s\n", SP7021_SLA_IRQ_NAME);

Ditto.

Quoted 2 lines
(quoted diff) +2 -0
+               return pspim->sla_irq;
+       }

...

Quoted 1 line

+ // clk

Meaningless.

...

Quoted 1 line

+ dev_dbg(&pdev->dev, "pspim->rstc : 0x%x\n", (unsigned int)pspim->rstc);

Get rid of the debugging like this, it's not for production use at all.

...

drivers/spi/spi-sunplus-sp7021.c line 599

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+               return dev_err_probe(&pdev->dev, PTR_ERR(pspim->rstc),
+                                    "devm_rst_get fail\n");

One line.

...

drivers/spi/spi-sunplus-sp7021.c line 605

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+               return dev_err_probe(&pdev->dev, ret,
+                       "failed to enable clk\n");

Ditto. And so on...
To make lines shorter, utilize a temporary variable for struct device *dev.

...

Quoted 1 line

+ dev_dbg(&pdev->dev, "pm init done\n");

Redundant.

Quoted 1 line

+ dev_dbg(&pdev->dev, "spi_master_probe done\n");

Redundant.

...

Quoted 1 line

+ dev_dbg(dev, "devid:%d\n", dev->id);

Redundant.

...

Quoted 1 line

+ dev_dbg(dev, "devid:%d\n", dev->id);

Ditto.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
maintainer
#30 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 7 lines · Andy Shevchenko
Quoted 1 line · LH.Kuo

+// slave only. usually called on driver remove

Why is it so?
Also find use of proper English grammar (capitalization, periods, etc. Ditto for all your comments.

Please don't go overboard on changes you're requesting, the important thing with comments is that they're intelligible. People have different levels of skill with English and that's totally fine, it's much better that people feel able to write comments than that they stop doing so because they are concerned about issues with their foreign language skills.

Quoted 7 lines

drivers/spi/spi-sunplus-sp7021.c line 230

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+       unsigned long flags;
+       struct sp7021_spi_ctlr *pspim = dev;
+       u32 fd_status = 0;
+       unsigned int tx_len, rx_cnt, tx_cnt, total_len;
+       bool isrdone = false;

Reversed xmas tree order here and everywhere else.

Again, please don't go overboard - this isn't a general requirement for kernel code, some parts of the kernel do want it but outside of those areas it's not something that we should be asking for (and TBH even when it is required you should explain what it is, it's not as easy to search for as it could be). I certainly don't care.

Quoted 4 lines

drivers/spi/spi-sunplus-sp7021.c line 505

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+               if (of_property_read_bool(pdev->dev.of_node, "spi-slave"))
+                       mode = SP7021_SLAVE_MODE;

There is no need to check of_node for this call.

OTOH if we are checking it anyway it doesn't hurt to have all the property reads in the check for of_node. Either way it doesn't fundamentally matter.

#31 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 9 lines · Mark Brown
Quoted 7 lines · Andy Shevchenko
Quoted 1 line · LH.Kuo

+// slave only. usually called on driver remove

Why is it so?
Also find use of proper English grammar (capitalization, periods, etc. Ditto for all your comments.

Quoted 6 lines

Please don't go overboard on changes you're requesting, the important thing with comments is that they're intelligible. People have different levels of skill with English and that's totally fine, it's much better that people feel able to write comments than that they stop doing so because they are concerned about issues with their foreign language skills.

Shame on me! I'm also bad at English (okay, sometimes).

...

Quoted 6 lines
Quoted 5 lines
Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+       unsigned long flags;
+       struct sp7021_spi_ctlr *pspim = dev;
+       u32 fd_status = 0;
+       unsigned int tx_len, rx_cnt, tx_cnt, total_len;
+       bool isrdone = false;
Quoted 7 lines
Quoted 1 line

Reversed xmas tree order here and everywhere else.

Again, please don't go overboard - this isn't a general requirement for kernel code, some parts of the kernel do want it but outside of those areas it's not something that we should be asking for (and TBH even when it is required you should explain what it is, it's not as easy to search for as it could be). I certainly don't care.

Here it is. The "reversed xmas tree order" implies that longer lines in the definition block, where one puts all variables that are being used locally in the given function, are going first followed by shorter ones. This makes it a bit easier to read the code. There are also additional rules that may be applied, such as defines with assignments _usually_ go before anything else, error code variable separately and last. That said, the above might look better in the following form:

       struct sp7021_spi_ctlr *pspim = dev;
       unsigned int tx_len, total_len;
       unsigned int rx_cnt, tx_cnt;
       unsigned long flags;
       bool isrdone = false;
       u32 fd_status = 0;

...

Quoted 7 lines
Quoted 4 lines

drivers/spi/spi-sunplus-sp7021.c line 505

Quoted 2 lines
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+               if (of_property_read_bool(pdev->dev.of_node, "spi-slave"))
+                       mode = SP7021_SLAVE_MODE;

There is no need to check of_node for this call.

OTOH if we are checking it anyway it doesn't hurt to have all the property reads in the check for of_node.

I assumed that previous comment against SPI ID potentially will be addressed by removing that code which in the result gives unnecessary use of the of_node check above. So that's why I pointed this out.

Quoted 2 lines

Either way it doesn't
fundamentally matter.

True!

Signature · 2 lines
With Best Regards,
Andy Shevchenko

A message that is not in the archive (sent off-list or not yet received): [email protected]

#33 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 1 line · Lh Kuo 郭力豪

I have already modified most of the driver. And the probe function is as follows. Is it okay?

Can be done a bit better, see below (seems you missed few of the comments)

Quoted 7 lines

static int sp7021_spi_controller_probe(struct platform_device *pdev)

{
        int ret;
        int mode;
        struct spi_controller *ctlr;
        struct sp7021_spi_ctlr *pspim;
        struct device *dev = &pdev->dev;

Other way around, or i.o.w. "reversed tree".

Quoted 5 lines
        mode = SP7021_MASTER_MODE;
        pdev->id = of_alias_get_id(pdev->dev.of_node, "sp_spi");

        if (of_property_read_bool(pdev->dev.of_node, "spi-slave"))
                mode = SP7021_SLAVE_MODE;
         pdev->id = of_alias_get_id(pdev->dev.of_node, "sp_spi");

         mode = SP7021_MASTER_MODE;
         if (of_property_read_bool(pdev->dev.of_node, "spi-slave"))
                 mode = SP7021_SLAVE_MODE;
Quoted 31 lines
        if (mode == SP7021_SLAVE_MODE)
                ctlr = devm_spi_alloc_slave(dev, sizeof(*pspim));
        else
                ctlr = devm_spi_alloc_master(dev, sizeof(*pspim));
        if (!ctlr)
                return -ENOMEM;

        ctlr->dev.of_node = pdev->dev.of_node;
        ctlr->bus_num = pdev->id;
        ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
        ctlr->auto_runtime_pm = true;
        ctlr->prepare_message = sp7021_spi_controller_prepare_message;
        if (mode == SP7021_SLAVE_MODE) {
                ctlr->transfer_one = sp7021_spi_sla_transfer_one;
                ctlr->slave_abort = sp7021_spi_sla_abort;
                ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
        } else {
                ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
                ctlr->min_speed_hz = 40000;
                ctlr->max_speed_hz = 25000000;
                ctlr->use_gpio_descriptors = true;
                ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
                ctlr->transfer_one = sp7021_spi_mas_transfer_one;
        }
        platform_set_drvdata(pdev, ctlr);
        pspim = spi_controller_get_devdata(ctlr);
        pspim->ctlr = ctlr;
        pspim->dev = dev;
        spin_lock_init(&pspim->lock);
        mutex_init(&pspim->buf_lock);
        init_completion(&pspim->isr_done);
Quoted 8 lines
        init_completion(&pspim->sla_isr);
        pspim->mas_base = devm_platform_ioremap_resource_byname(pdev, "spi_master");
        pspim->sla_base = devm_platform_ioremap_resource_byname(pdev, "spi_slave");

        pspim->mas_irq = platform_get_irq_byname(pdev, "mas_risc_intr");
        if (pspim->mas_irq < 0) {

                dev_err(dev, "failed to get mas intr\n");

Dup. No need to repeat what's done by platform core.

Quoted 7 lines
                return pspim->mas_irq;
        }

        pspim->sla_irq = platform_get_irq_byname(pdev, "slave_risc_intr");
        if (pspim->sla_irq < 0) {

                dev_err(dev, "failed to get sla intr\n");

Dup.

Quoted 5 lines
                return pspim->sla_irq;
        }

        ret = devm_request_irq(dev, pspim->mas_irq, sp7021_spi_mas_irq
                                                , IRQF_TRIGGER_RISING, pdev->name, pspim);

Ugly indentation.

Quoted 7 lines
        if (ret) {
                dev_err(dev, "mas intr devm_request_irq fail\n");
                return ret;
        }

        ret = devm_request_irq(dev, pspim->sla_irq, sp7021_spi_sla_irq
                                                , IRQF_TRIGGER_RISING, pdev->name, pspim);

Ditto.

Quoted 10 lines
        if (ret) {
                dev_err(dev, "slave intr devm_request_irq fail\n");
                return ret;
        }

        pspim->spi_clk = devm_clk_get(dev, NULL);

        if (IS_ERR(pspim->spi_clk)) {
                return dev_err_probe(dev, PTR_ERR(pspim->spi_clk), "clk get fail\n");
        }

Does checkpatch compains on this?
Hint: {} around a single statement shouldn't be added.

Quoted 3 lines
        pspim->rstc = devm_reset_control_get_exclusive(dev, NULL);
        if (IS_ERR(pspim->rstc)) {
                return dev_err_probe(dev, PTR_ERR(pspim->rstc), "rst get fail\n");

Ditto.

Quoted 7 lines
        }

        ret = clk_prepare_enable(pspim->spi_clk);
        if (ret)

                return dev_err_probe(dev, ret,
                        "failed to enable clk\n");

One line

Quoted 4 lines
        ret = reset_control_deassert(pspim->rstc);
        if (ret) {
                dev_err_probe(dev, ret,
                        "failed to deassert reset\n");

One line.

Quoted 3 lines
                goto free_reset_assert;

Really, pay attention to a stray blank line here and there.

Quoted 5 lines
        }

        pm_runtime_enable(dev);

        ret = devm_spi_register_controller(dev, ctlr);

You can't mix non-devm with devm APIs. Either all non-devm, or devm followed by non-devm.

Quoted 15 lines
        if (ret) {
                dev_err(dev, "spi_register_master fail\n");
                goto err_disable_pm_runtime;
        }

        return ret;

err_disable_pm_runtime:

        pm_runtime_disable(dev);
free_reset_assert:
        reset_control_assert(pspim->rstc);
        clk_disable_unprepare(pspim->spi_clk);

        return ret;
}
Signature · 2 lines
With Best Regards,
Andy Shevchenko

A message that is not in the archive (sent off-list or not yet received): [email protected]

#35 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

On Fri, Nov 26, 2021 at 9:49 AM Lh Kuo 郭力豪 <[email protected]> wrote:

(Uncommented is okay)

...

Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
        ret = devm_request_irq(dev, pspim->mas_irq, sp7021_spi_mas_irq
                                                , IRQF_TRIGGER_RISING,

pdev->name, pspim);

Ugly indentation.

Quoted 6 lines

Amended as follows, is it okay?

        ret = devm_request_irq(dev, pspim->mas_irq, sp7021_spi_mas_irq
                        , IRQF_TRIGGER_RISING, pdev->name, pspim);
        if (ret)
                return ret;

Still not okay. Have you seen this style somewhere in the kernel?
Hint: something is really wrong with comma's location.

...

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
        pm_runtime_enable(dev);

        ret = devm_spi_register_controller(dev, ctlr);

You can't mix non-devm with devm APIs. Either all non-devm, or devm followed by non-devm.

I don't understand so I need to change to spi_register_controller(ctlr)? why?

I haven't told you that. What I'm saying is this:
1) all calls are devm_*() - OK!
2) all calls are non-devm_*() OK!
3) devm_*() followed by non-devm_*() OK!
4) non-devm_*() call followed by devm_*() call NOT okay!

You need to fulfil your homework (see plenty of the examples in the Linux kernel source tree on how to proceed).

Quoted 1 line

I modified the remove-function as follows. I think devm_spi_register_controller(dev, ctlr); should be no problem in the probe funciton.

It has ordering issues. That's why 4) above is not okay.

Quoted 12 lines

static int sp7021_spi_controller_remove(struct platform_device *pdev)

{
        struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
        struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);

        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
        reset_control_assert(pspim->rstc);
        clk_disable_unprepare(pspim->spi_clk);

        return 0;
}
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#36 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

In reply to a message not in the archive

Hi LH,

On Fri, 2021-11-26 at 07:40 +0000, Lh Kuo 郭力豪 wrote:
[...]

Quoted 6 lines

Amended as follows, is it okay?

	ret = devm_request_irq(dev, pspim->mas_irq, sp7021_spi_mas_irq
			, IRQF_TRIGGER_RISING, pdev->name, pspim);
	if (ret)
		return ret;

Comma at the end of the line and align the next line with the opening parenthesis:

	ret = devm_request_irq(dev, pspim->mas_irq, sp7021_spi_mas_irq,
			       IRQF_TRIGGER_RISING, pdev->name, pspim);

You can use scripts/checkpatch --strict to find these issues before review.

Quoted 11 lines
Quoted 5 lines
Quoted 4 lines

        pspim->rstc = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(pspim->rstc)) {
                return dev_err_probe(dev, PTR_ERR(pspim->rstc), "rst get fail\n");

Amended as follows, is it okay?

	pspim->rstc = devm_reset_control_get_exclusive(dev, NULL);
	if (IS_ERR(pspim->rstc))
		return dev_err_probe(dev, PTR_ERR(pspim->rstc), "rst get fail\n");

Yes.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

        ret = devm_spi_register_controller(dev, ctlr);

You can't mix non-devm with devm APIs. Either all non-devm, or devm followed by non-devm.

  I don't understand so I need to change to spi_register_controller(ctlr)? why?

devm_spi_register_controller() shouldn't be called after pm_runtime_enable().

You could either switch to devm_pm_runtime_enable() or move the pm_runtime_enable() after the devm_spi_register_controller() call if possible, or switch to spi_register_controller().

Quoted 7 lines

I modified the remove-function as follows. I think devm_spi_register_controller(dev, ctlr); should be no problem in the probe funciton. static int sp7021_spi_controller_remove(struct platform_device *pdev)

{
	struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
	struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);

	pm_runtime_disable(&pdev->dev);

I'm not sure if the SPI framework requires the spi_controller to be unregistered before hardware is powered off, maybe it is enough to call spi_controller_suspend() in the right place?

Quoted 6 lines
	pm_runtime_set_suspended(&pdev->dev);
	reset_control_assert(pspim->rstc);
	clk_disable_unprepare(pspim->spi_clk);

	return 0;
}

regards
Philipp

maintainer
#37 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 5 lines · Philipp Zabel
Quoted 1 line
	pm_runtime_disable(&pdev->dev);

I'm not sure if the SPI framework requires the spi_controller to be unregistered before hardware is powered off, maybe it is enough to call spi_controller_suspend() in the right place?

It would *probably* do the right thing but the expectation really is that you'll unregister before making the controller stop working, that should be much more robust..

A message that is not in the archive (sent off-list or not yet received): [email protected]

#39 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 1 line · Lh Kuo 郭力豪

Feel sorry. I haven't found any devm PM API use in the SPI driver, and I didn't realize that PM function also has devm API. So I was confused before. I will move the pm_runtime_enable() after the devm_spi_register_controller() . I have rewritten the Probe and Remove functions as shown below.

Neither you found APIs for clock and reset, Try to grep for devm_add_action_or_reset().

So, for PM it is probably good to leave it last, but you still have the issue.

Quoted 1 line

And sp7021_spi_controller driver is modified and the code cleaned more than -50 LOCs. If the Probe and Remove functions is OK I will start next submission.

No, it's not okay.. yet, but we are closer. See my comments above and below.

Quoted 19 lines

Thanks for all comments

static int sp7021_spi_controller_probe(struct platform_device *pdev)

{
        struct device *dev = &pdev->dev;
        struct sp7021_spi_ctlr *pspim;
        struct spi_controller *ctlr;
        int mode;
        int ret;

        dev_info(dev, "sp7021_spi_controller_probe\n");

        mode = SP7021_MASTER_MODE;
        pdev->id = of_alias_get_id(pdev->dev.of_node, "sp_spi");

        if (of_property_read_bool(pdev->dev.of_node, "spi-slave"))
                mode = SP7021_SLAVE_MODE;

        if (mode == SP7021_SLAVE_MODE)
Quoted 8 lines
                ctlr = devm_spi_alloc_slave(dev, sizeof(*pspim));
        else
                ctlr = devm_spi_alloc_master(dev, sizeof(*pspim));
        if (!ctlr)
                return -ENOMEM;


        ctlr->dev.of_node = pdev->dev.of_node;

device_set_node()

Quoted 19 lines
        ctlr->bus_num = pdev->id;
        ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
        ctlr->auto_runtime_pm = true;
        ctlr->prepare_message = sp7021_spi_controller_prepare_message;
        if (mode == SP7021_SLAVE_MODE) {
                ctlr->transfer_one = sp7021_spi_sla_transfer_one;
                ctlr->slave_abort = sp7021_spi_sla_abort;
                ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
        } else {
                ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
                ctlr->min_speed_hz = 40000;
                ctlr->max_speed_hz = 25000000;
                ctlr->use_gpio_descriptors = true;
                ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
                ctlr->transfer_one = sp7021_spi_mas_transfer_one;
        }
        platform_set_drvdata(pdev, ctlr);
        pspim = spi_controller_get_devdata(ctlr);
        pspim->ctlr = ctlr;
Quoted 8 lines
        pspim->dev = dev;
        spin_lock_init(&pspim->lock);
        mutex_init(&pspim->buf_lock);
        init_completion(&pspim->isr_done);
        init_completion(&pspim->sla_isr);

        pspim->mas_base = devm_platform_ioremap_resource_byname(pdev, "master");
        pspim->sla_base = devm_platform_ioremap_resource_byname(pdev, "slave");

Where are the error checks?

Quoted 27 lines
        pspim->mas_irq = platform_get_irq_byname(pdev, "mas_risc");
        if (pspim->mas_irq < 0)
                return pspim->mas_irq;

        pspim->sla_irq = platform_get_irq_byname(pdev, "slave_risc");
        if (pspim->sla_irq < 0)
                return pspim->sla_irq;

        ret = devm_request_irq(dev, pspim->mas_irq, sp7021_spi_mas_irq,
                                                IRQF_TRIGGER_RISING, pdev->name, pspim);
        if (ret)
                return ret;

        ret = devm_request_irq(dev, pspim->sla_irq, sp7021_spi_sla_irq,
                                                IRQF_TRIGGER_RISING, pdev->name, pspim);
        if (ret)
                return ret;

        pspim->spi_clk = devm_clk_get(dev, NULL);
        if (IS_ERR(pspim->spi_clk))
                return dev_err_probe(dev, PTR_ERR(pspim->spi_clk), "clk get fail\n");

        pspim->rstc = devm_reset_control_get_exclusive(dev, NULL);
        if (IS_ERR(pspim->rstc))
                return dev_err_probe(dev, PTR_ERR(pspim->rstc), "rst get fail\n");

        ret = clk_prepare_enable(pspim->spi_clk);
Quoted 8 lines
        if (ret)
                return dev_err_probe(dev, ret, "failed to enable clk\n");

        ret = reset_control_deassert(pspim->rstc);
        if (ret) {
                dev_err_probe(dev, ret, "failed to deassert reset\n");
                goto err_free_reset;
        }

These two need to be wrapped as I explained above.

Quoted 7 lines
        ret = devm_spi_register_controller(dev, ctlr);
        pm_runtime_enable(dev);
        if (ret) {


                dev_err(dev, "spi_register_master fail\n");
                goto err_disable_pm_runtime;
  pm_runtime_disable();
  return dev_err_probe();
Quoted 13 lines
        }

        return ret;

err_disable_pm_runtime:

        pm_runtime_disable(dev);
err_free_reset:
        reset_control_assert(pspim->rstc);
        clk_disable_unprepare(pspim->spi_clk);

        return ret;
}
Quoted 6 lines

static int sp7021_spi_controller_remove(struct platform_device *pdev)

{
        struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
        struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);

        spi_unregister_controller(ctlr);

Lukas already explained to you why this is wrong.

Quoted 5 lines
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);

        reset_control_assert(pspim->rstc);
        clk_disable_unprepare(pspim->spi_clk);

This has the same ordering issue as already discussed.

Quoted 2 lines
        return 0;
}
Signature · 2 lines
With Best Regards,
Andy Shevchenko

A message that is not in the archive (sent off-list or not yet received): [email protected]

#41 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

Quoted 6 lines · Lh Kuo 郭力豪
Quoted 3 lines
Quoted 1 line
        ctlr->dev.of_node = pdev->dev.of_node;

device_set_node()

Is this funciton set as follows?

        device_set_node(&ctlr->dev, of_fwnode_handle(pdev->dev.fwnode));

Can you please do something?
For example, figuring out yourself (Elixir is a very good service for that): https://elixir.bootlin.com/linux/latest/A/ident/device_set_node

...

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
        pspim->mas_base = devm_platform_ioremap_resource_byname(pdev, "master");
        pspim->sla_base = devm_platform_ioremap_resource_byname(pdev,

"slave");

Where are the error checks?

The changes are as follows? is this correct?

Almost, but not enough. Please run checkpatch.

Quoted 9 lines
        pspim->mas_base = devm_platform_ioremap_resource_byname(pdev, "master");
        if (IS_ERR(pspim->mas_base)) {
                return dev_err_probe(dev, PTR_ERR(pspim->mas_base), "mas_base get fail\n");
        }

        pspim->sla_base = devm_platform_ioremap_resource_byname(pdev, "slave");
        if (IS_ERR(pspim->sla_base)) {
                return dev_err_probe(dev, PTR_ERR(pspim->sla_base), "sla_base get fail\n");
        }

...

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
        if (ret) {
                dev_err_probe(dev, ret, "failed to deassert reset\n");
                goto err_free_reset;
        }

These two need to be wrapped as I explained above.

I think these changes are depend on remove-function.

No, it's the other way around: ->remove() implementation depends on these changes.

Quoted 1 line

These settings are as follows? is this correct?

No.

Quoted 6 lines
        pspim->spi_clk = devm_clk_get(dev, NULL);
        if (IS_ERR(pspim->spi_clk))
                return dev_err_probe(dev, PTR_ERR(pspim->spi_clk), "clk get fail\n");

        pspim->rstc = devm_reset_control_get_exclusive(dev, NULL);
        if (IS_ERR(pspim->rstc))
Quoted 8 lines
                return dev_err_probe(dev, PTR_ERR(pspim->rstc), "rst get fail\n");

        ret = clk_prepare_enable(pspim->spi_clk);
        if (ret)
                return dev_err_probe(dev, ret, "failed to enable clk\n");

        devm_add_action_or_reset(dev, (void(*)(void *))clk_disable_unprepare,
                        pspim->spi_clk);

Please, find other drivers as examples of how to do that and take care about possible errors.

Quoted 6 lines
        ret = reset_control_deassert(pspim->rstc);
        if (ret)
                return dev_err_probe(dev, ret, "failed to deassert reset\n");

        devm_add_action_or_reset(dev, (void(*)(void *))reset_control_assert,
                        pspim->rstc);

Ditto.

Quoted 1 line
        ret = spi_register_controller(ctlr);

Read what Lukas said.

Quoted 19 lines
        pm_runtime_enable(dev);
        if (ret) {
                pm_runtime_disable(dev);
                return dev_err_probe(dev, ret, "spi_register_master fail\n");
        }

        return ret;

}

static int sp7021_spi_controller_remove(struct platform_device *pdev)

{
        struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);

        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);

        return 0;
}
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#42 lore raw

Re: [PATCH v3 1/2] SPI: Add SPI driver for Sunplus SP7021

In reply to LH.Kuo
Quoted 2 lines · LH.Kuo
drivers/spi/spi-sunplus-sp7021.c new file +2 -0
+static int sp7021_spi_controller_probe(struct platform_device *pdev)
+{

[...]

drivers/spi/spi-sunplus-sp7021.c line 585

Quoted 5 lines
drivers/spi/spi-sunplus-sp7021.c new file +5 -0
+	ret = devm_spi_register_controller(&pdev->dev, ctlr);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "spi_register_master fail\n");
+		goto disable_runtime_pm;
+	}

You need to use spi_register_controller() here (*not* the devm_ variant) because you're using spi_unregister_controller() in sp7021_spi_controller_remove().

Quoted 18 lines
drivers/spi/spi-sunplus-sp7021.c new file +18 -0
+
+	// clk
+	pspim->spi_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pspim->spi_clk)) {
+		return dev_err_probe(&pdev->dev, PTR_ERR(pspim->spi_clk),
+				     "devm_clk_get fail\n");
+	}
+
+	// reset
+	pspim->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+	dev_dbg(&pdev->dev, "pspim->rstc : 0x%x\n", (unsigned int)pspim->rstc);
+	if (IS_ERR(pspim->rstc)) {
+		return dev_err_probe(&pdev->dev, PTR_ERR(pspim->rstc),
+				     "devm_rst_get fail\n");
+	}
+
+	ret = clk_prepare_enable(pspim->spi_clk);
+	if (ret)

drivers/spi/spi-sunplus-sp7021.c line 613

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+		return dev_err_probe(&pdev->dev, ret,
+			"failed to enable clk\n");
+
+	ret = reset_control_deassert(pspim->rstc);
+	if (ret) {
+		dev_err_probe(&pdev->dev, ret,
+			"failed to deassert reset\n");
+		goto free_reset_assert;
+
+	}

You need to move the above steps *before* the call to spi_register_controller(). Once spi_register_controller() returns, it must be able to perform SPI transactions. So you have to enable all required clocks before calling it. You also have to perform the reset step before registration to avoid interfering with an ongoing transaction. The order of these steps must mirror the order in sp7021_spi_controller_remove(): There you're unregistering the controller *before* disabling the clock and asserting reset, so the order must be inverted here.

Quoted 4 lines
drivers/spi/spi-sunplus-sp7021.c new file +4 -0
+static int sp7021_spi_controller_remove(struct platform_device *pdev)
+{
+	struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
+	struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);

drivers/spi/spi-sunplus-sp7021.c line 642

Quoted 10 lines
drivers/spi/spi-sunplus-sp7021.c new file +10 -0
+
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
+
+	spi_unregister_controller(pspim->ctlr);
+	clk_disable_unprepare(pspim->spi_clk);
+	reset_control_assert(pspim->rstc);
+
+	return 0;
+}

I think the two calls to pm_runtime_* should be moved after spi_unregister_controller() but that's probably not critical.

Thanks,

Lukas

author maintainer
#43 lore raw

PATCH v3 2/2 devicetree: bindings SPI Add bindings doc for Sunplus SP7021

In reply to LH.Kuo

Add devicetree bindings SPI Add bindings doc for Sunplus SP7021

---
Changes in v3:
- Addressed all comments from Mr. Mark Brown
- Addressed all comments from Mr. Philipp Zabel
- Addressed all comments from Mr. Rob Herring
- remove spi transfer_one_message

 .../bindings/spi/spi-sunplus-sp7021.yaml           | 95 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 96 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +95 -0
new file mode 100644
index 0000000..5502f15
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-sunplus-sp7021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus sp7021 SPI controller
+
+allOf:
+  - $ref: "spi-controller.yaml"
+
+maintainers:
+  - lh.kuo <[email protected]>
+
+properties:
+  compatible:
+    enum:
+      - sunplus,sp7021-spi-controller
+
+  reg:
+    items:
+      - description: Base address and length of the SPI master registers
+      - description: Base address and length of the SPI slave registers
+
+  reg-names:
+    items:
+      - const: spi_master
+      - const: spi_slave
+
+  interrupt-names:
+    items:
+      - const: dma_w_intr
+      - const: mas_risc_intr
+      - const: slave_risc_intr
+
+  interrupts:
+    minItems: 3
+
+  clocks:
+    maxItems: 1
+
+  clocks-names:
+    items:
+      - const: sys_pll
+
+  resets:
+    maxItems: 1
+
+  pinctrl-names:
+    description:
+      A pinctrl state named "default" must be defined.
+    const: default
+
+  pinctrl-0:
+    description:
+      A phandle to the default pinctrl state.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clocks-names
+  - resets
+  - pinctrl-names
+  - pinctrl-0
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/sp-sp7021.h>
+    #include <dt-bindings/reset/sp-sp7021.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi@9C002D80 {
+        compatible = "sunplus,sp7021-spi-controller";
+        reg = <0x9C002D80 0x80>, <0x9C002E00 0x80>;
+        reg-names = "spi_master", "spi_slave";
+        interrupt-parent = <&intc>;
+        interrupt-names = "dma_w_intr",
+                          "mas_risc_intr",
+                          "slave_risc_intr";
+        interrupts = <144 IRQ_TYPE_LEVEL_HIGH>,
+                     <146 IRQ_TYPE_LEVEL_HIGH>,
+                     <145 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clkc SPI_COMBO_0>;
+        clocks-names = "sys_pll";
+        resets = <&rstc RST_SPI_COMBO_0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pins_spi0>;
+    };
+...
MAINTAINERS +1 -0
index 75fa7d5..88f3747 100644
@@ -18220,6 +18220,7 @@ SUNPLUS SPI CONTROLLER INTERFACE DRIVER
 M:	LH Kuo <[email protected]>
 L:	[email protected]
 S:	Maintained
+F:	Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
 F:	drivers/spi/spi-sunplus-sp7021.c
 
 SUPERH
Signature · 1 line
2.7.4
maintainer
#44 lore raw

Re: [PATCH v3 2/2] devicetree: bindings SPI Add bindings doc for Sunplus SP7021

Quoted 3 lines · LH.Kuo

Add devicetree bindings SPI Add bindings doc for Sunplus SP7021

Again, From and S-o-b must match.

Quoted 27 lines

---
Changes in v3:
- Addressed all comments from Mr. Mark Brown
- Addressed all comments from Mr. Philipp Zabel
- Addressed all comments from Mr. Rob Herring
- remove spi transfer_one_message

 .../bindings/spi/spi-sunplus-sp7021.yaml           | 95 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 96 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +9 -0
new file mode 100644
index 0000000..5502f15
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-sunplus-sp7021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus sp7021 SPI controller
+

Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml line 19

Quoted 10 lines
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +10 -0
+allOf:
+  - $ref: "spi-controller.yaml"
+
+maintainers:
+  - lh.kuo <[email protected]>
+
+properties:
+  compatible:
+    enum:
+      - sunplus,sp7021-spi-controller

I think you can drop '-controller'.

Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml line 24

Quoted 5 lines
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +5 -0
+
+  reg:
+    items:
+      - description: Base address and length of the SPI master registers
+      - description: Base address and length of the SPI slave registers

Drop 'Base address and length of '. The rest is sufficient.

Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml line 29

Quoted 5 lines
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +5 -0
+
+  reg-names:
+    items:
+      - const: spi_master
+      - const: spi_slave

Drop 'spi_'.

Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml line 35

Quoted 6 lines
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +6 -0
+
+  interrupt-names:
+    items:
+      - const: dma_w_intr
+      - const: mas_risc_intr
+      - const: slave_risc_intr

Drop '_intr', it's redundant.

Quoted 76 lines
Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml new file +60 -0
+
+  interrupts:
+    minItems: 3
+
+  clocks:
+    maxItems: 1
+
+  clocks-names:
+    items:
+      - const: sys_pll
+
+  resets:
+    maxItems: 1
+
+  pinctrl-names:
+    description:
+      A pinctrl state named "default" must be defined.
+    const: default
+
+  pinctrl-0:
+    description:
+      A phandle to the default pinctrl state.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clocks-names
+  - resets
+  - pinctrl-names
+  - pinctrl-0
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/sp-sp7021.h>
+    #include <dt-bindings/reset/sp-sp7021.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi@9C002D80 {
+        compatible = "sunplus,sp7021-spi-controller";
+        reg = <0x9C002D80 0x80>, <0x9C002E00 0x80>;
+        reg-names = "spi_master", "spi_slave";
+        interrupt-parent = <&intc>;
+        interrupt-names = "dma_w_intr",
+                          "mas_risc_intr",
+                          "slave_risc_intr";
+        interrupts = <144 IRQ_TYPE_LEVEL_HIGH>,
+                     <146 IRQ_TYPE_LEVEL_HIGH>,
+                     <145 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clkc SPI_COMBO_0>;
+        clocks-names = "sys_pll";
+        resets = <&rstc RST_SPI_COMBO_0>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pins_spi0>;
+    };
+...
MAINTAINERS +1 -0
index 75fa7d5..88f3747 100644
@@ -18220,6 +18220,7 @@ SUNPLUS SPI CONTROLLER INTERFACE DRIVER
 M:	LH Kuo <[email protected]>
 L:	[email protected]
 S:	Maintained
+F:	Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
 F:	drivers/spi/spi-sunplus-sp7021.c
 
 SUPERH
Signature · 1 line
2.7.4
maintainer
#45 lore raw
In reply to LH.Kuo
Quoted 5 lines · LH.Kuo

This is a patch series for SPI driver for Sunplus SP7021 SoC.

Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates many peripherals (ex: UART, I2C, SPI, SDIO, eMMC, USB, SD card and etc.) into a single chip. It is designed for industrial control.

The structure of the driver now looks good, but there are some smaller issues remaining - I don't think I saw anything that Andy and Lukas didn't already raise.