Skip to contentSkip to conversation

Add SPI driver support for GENI based QUP

PATCH In review Dilip Kota 3 participants 10 messages Jul 20, 2018 – Jul 23, 2018

Subsystems (4)
lore
Share & tools
lore

Dilip Kota

author
#0 lore raw

PATCH v2 1/1 Add SPI driver support for GENI based QUP

This patch series adds SPI driver support for GENI based QUP. Also adding the device tree binding document for reference as per reviewers request which was merged in Linus tree.

Girish Mahadevan (1):
spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

 drivers/spi/Kconfig               |  12 +
 drivers/spi/Makefile              |   1 +
 drivers/spi/spi-geni-qcom.c       | 685 ++++++++++++++++++++++++++++++++++++++
 include/linux/spi/spi-geni-qcom.h |  14 +
 4 files changed, 712 insertions(+)
 create mode 100644 drivers/spi/spi-geni-qcom.c
 create mode 100644 include/linux/spi/spi-geni-qcom.h
Signature · 3 lines
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
author
#1 lore raw

PATCH v2 1/1 spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

From: Girish Mahadevan <[email protected]>

This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer.

---
 drivers/spi/Kconfig               |  12 +
 drivers/spi/Makefile              |   1 +
 drivers/spi/spi-geni-qcom.c       | 685 ++++++++++++++++++++++++++++++++++++++
 include/linux/spi/spi-geni-qcom.h |  14 +
 4 files changed, 712 insertions(+)
 create mode 100644 drivers/spi/spi-geni-qcom.c
 create mode 100644 include/linux/spi/spi-geni-qcom.h
drivers/spi/Kconfig +12 -0
index ad5d68e..d4aa755 100644
@@ -533,6 +533,18 @@ config SPI_QUP
 	  This driver can also be built as a module.  If so, the module
 	  will be called spi_qup.
 
+config SPI_QCOM_GENI
+	tristate "Qualcomm SPI controller with QUP interface"
+	depends on QCOM_GENI_SE
+	help
+	  This driver supports GENI serial engine based SPI controller in
+	  master mode on the Qualcomm Technologies Inc.'s SoCs. If you say
+	  yes to this option, support will be included for the built-in SPI
+	  interface on the Qualcomm Technologies Inc.'s SoCs.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called spi-geni-qcom.
+
 config SPI_S3C24XX
 	tristate "Samsung S3C24XX series SPI"
 	depends on ARCH_S3C24XX
drivers/spi/Makefile +1 -0
index cb1f437..98337cf 100644
@@ -74,6 +74,7 @@ obj-$(CONFIG_SPI_PPC4xx)		+= spi-ppc4xx.o
 spi-pxa2xx-platform-objs		:= spi-pxa2xx.o spi-pxa2xx-dma.o
 obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx-platform.o
 obj-$(CONFIG_SPI_PXA2XX_PCI)		+= spi-pxa2xx-pci.o
+obj-$(CONFIG_SPI_QCOM_GENI)		+= spi-geni-qcom.o
 obj-$(CONFIG_SPI_QUP)			+= spi-qup.o
 obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o
 obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
drivers/spi/spi-geni-qcom.c new file +685 -0

685 lines not on this page · raw message

include/linux/spi/spi-geni-qcom.h new file +14 -0
new file mode 100644
index 0000000..dc95764
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SPI_GENI_QCOM_HEADER___
+#define __SPI_GENI_QCOM_HEADER___
+
+struct spi_geni_qcom_ctrl_data {
+	u32 spi_cs_clk_delay;
+	u32 spi_inter_words_delay;
+};
+
+#endif /*__SPI_GENI_QCOM_HEADER___*/
Signature · 3 lines
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
#2 lore raw

Re: [PATCH V2] spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

Thank you for the patch! Perhaps something to improve:

Hi Girish,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on spi/for-next]
[also build test WARNING on v4.18-rc5 next-20180720]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Dilip-Kota/spi-spi-geni-qcom-Add-SPI-driver-support-for-GENI-based-QUP/20180721-034916
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: i386-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

In file included from drivers/spi/spi-geni-qcom.c:11:0:
drivers/spi/spi-geni-qcom.c: In function 'spi_geni_prepare_transfer_hardware':
include/linux/qcom-geni-se.h:238:9: error: 'version' undeclared (first use in this function); did you mean 'vm_region'?

     step = version & HW_VER_STEP_MASK; \
            ^
>> drivers/spi/spi-geni-qcom.c:256:3: note: in expansion of macro 'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/qcom-geni-se.h:238:9: note: each undeclared identifier is reported only once for each function it appears in
     step = version & HW_VER_STEP_MASK; \
            ^
>> drivers/spi/spi-geni-qcom.c:256:3: note: in expansion of macro 'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~

vim +/geni_se_get_wrapper_version +256 drivers/spi/spi-geni-qcom.c

233
234 static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
235 {
236 struct spi_geni_master *mas = spi_master_get_devdata(spi);
237 struct geni_se *se = &mas->se;
238
239 if (!mas->setup) {
240 int proto = geni_se_read_proto(se);
241 unsigned int major;
242 unsigned int minor;
243 unsigned int step;
244
245 if (proto != GENI_SE_SPI) {
246 dev_err(mas->dev, "Invalid proto %d\n", proto);
247 return -ENXIO;
248 }
249 mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se);
250 mas->rx_fifo_depth = geni_se_get_rx_fifo_depth(se);
251 mas->tx_fifo_width = geni_se_get_tx_fifo_width(se);
252 geni_se_init(se, 0x0, (mas->tx_fifo_depth - 2));
253 mas->oversampling = 1;
254 /* Transmit an entire FIFO worth of data per IRQ */
255 mas->tx_wm = 1;

 > 256			geni_se_get_wrapper_version(se, major, minor, step);

257 if ((major == 1) && (minor == 0))
258 mas->oversampling = 2;
259 mas->setup = 1;
260 }
261 return 0;
262 }
263

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#3 lore raw

Re: [PATCH V2] spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

In reply to Dilip Kota
Quoted 1 line

Hi,

Quoted 7 lines · Dilip Kota

From: Girish Mahadevan <[email protected]>

This driver supports GENI based SPI Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including SPI. This driver supports SPI operations using FIFO mode of transfer.

Quoted 5 lines
Change-Id Ib2c7feba5a2fc4015bc83319b233b4356f7d3190

Why is Girish here twice? That doesn't seem right. This is also an awful lot of Signed-off-by tags. Did they all contribute code here? v1 of this patch only had girish.

Quoted 1 line

Rob may have reviewed the bindings, but that doesn't mean he's happy with the code. I'd suggest removing his Reviewed-by

Quoted 1 line

Are you certain that Stephen provided his Reviewed-by? I don't see it. ...and, as you can see below, it seems like you ignored most of Stephen's comments on v1.

Quoted 2 lines

---

I would have expected some version history here to say what changed from v1 to v2. See my comments on the cover letter and consider using patman <https://github.com/u-boot/u-boot/tree/master/tools/patman> to help you.

Quoted 2 lines
drivers/spi/Kconfig +2 -0
+config SPI_QCOM_GENI
+       tristate "Qualcomm SPI controller with QUP interface"
Quoted 3 lines · On v1 Stephen Boyd said:

This is the same help text as the SPI_QUP config up above. Please make it different somehow by adding GENI or something like that instead of QUP?

More explicitly, please change the line to:
tristate "Qualcomm SPI controller with GENI interface"

Quoted 5 lines
drivers/spi/Kconfig +5 -0
+       depends on QCOM_GENI_SE
+       help
+         This driver supports GENI serial engine based SPI controller in
+         master mode on the Qualcomm Technologies Inc.'s SoCs. If you say
+         yes to this option, support will be included for the built-in SPI
Quoted 11 lines · On v1 Stephen Boyd said:

Drop "built-in"?

drivers/spi/spi-geni-qcom.c new file +8 -0
+struct spi_geni_master {
+       struct geni_se se;
+       int irq;
+       struct device *dev;
+       int rx_fifo_depth;
+       int tx_fifo_depth;
+       int tx_fifo_width;
+       int tx_wm;
Quoted 6 lines · In v1 Stephen said:

All of these can be unsigned ints?

drivers/spi/spi-geni-qcom.c new file +3 -0
+       bool setup;
+       u32 cur_speed_hz;
+       int cur_word_len;
Quoted 8 lines · In v1 Stephen said:

unsigned?

drivers/spi/spi-geni-qcom.c new file +5 -0
+       unsigned int tx_rem_bytes;
+       unsigned int rx_rem_bytes;
+       struct spi_transfer *cur_xfer;
+       struct completion xfer_done;
+       int oversampling;
Quoted 4 lines · In v1 Stephen said:

unsigned?

+static int get_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas,

Quoted 6 lines · In v1 Stephen said:

Why a u32? And not unsigned int?

drivers/spi/spi-geni-qcom.c new file +3 -0
+       if (ret) {
+               dev_err(mas->dev, "%s: Failed(%d) to find src clk for 0x%x\n",
+                                               __func__, ret, speed_hz);
Quoted 1 line · In v1 Stephen said:

Frequency Hz printed in hex? I am not a hex computer! I hope!

...I'll further add that printing __func__ is generally discouraged for dev_xx printouts. They've already got the device name and that together with the string should be enough. Remove it.

Quoted 1 line

+static void spi_setup_word_len(struct spi_geni_master *mas, u32 mode,

Quoted 18 lines · In v1 Stephen said:

mode is only u16 in spi_device struct. Maybe it would be better to pass the spi_device struct here and then pick out the mode from there.

drivers/spi/spi-geni-qcom.c new file +14 -0
+static int setup_fifo_params(struct spi_device *spi_slv,
+                                       struct spi_master *spi)
+{
+       struct spi_geni_master *mas = spi_master_get_devdata(spi);
+       struct geni_se *se = &mas->se;
+       u16 mode = spi_slv->mode;
+       u32 loopback_cfg = readl_relaxed(se->base + SE_SPI_LOOPBACK);
+       u32 cpol = readl_relaxed(se->base + SE_SPI_CPOL);
+       u32 cpha = readl_relaxed(se->base + SE_SPI_CPHA);
+       u32 demux_sel = 0;
+       u32 demux_output_inv = 0;
+       u32 clk_sel = 0;
+       u32 m_clk_cfg = 0;
+       int ret = 0;
Quoted 5 lines · In v1 Stephen said:

Don't initialize variables and then overwrite them.

drivers/spi/spi-geni-qcom.c new file +2 -0
+       demux_sel = spi_slv->chip_select;
+       mas->cur_speed_hz = spi_slv->max_speed_hz;
Quoted 3 lines · In v1 Stephen said:

Why can't you use clk_get_rate() instead? Or call clk_set_rate() with the rate you want the master clk to run at and then divide that down from there?

...there was a bunch of arguments here and I'm not sure I followed all of them, but the net-net is that there should be no rate at the controller level. Each SPI slave should request its rate and that should take effect for each transfer. Basically just honor the rate of the transfer in setup_fifo_xfer and be done with it.

Quoted 10 lines
drivers/spi/spi-geni-qcom.c new file +10 -0
+       mas->cur_word_len = spi_slv->bits_per_word;
+
+       ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
+       if (ret) {
+               dev_err(mas->dev, "Err setting clks ret(%d) for %d\n",
+                                                       ret, mas->cur_speed_hz);
+               return ret;
+       }
+
+       clk_sel |= (idx & CLK_SEL_MSK);
Quoted 5 lines · In v1 Stephen said:

Just assign clk_sel instead of ORing it because it's initialized to 0 up above.

+ m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);

Quoted 7 lines · In v1 Stephen said:

Same story.

drivers/spi/spi-geni-qcom.c new file +4 -0
+               mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se);
+               mas->rx_fifo_depth = geni_se_get_rx_fifo_depth(se);
+               mas->tx_fifo_width = geni_se_get_tx_fifo_width(se);
+               geni_se_init(se, 0x0, (mas->tx_fifo_depth - 2));
Quoted 1 line · In v1 Stephen said:

Why 2? Drop extra parenthesis please.

Girish responded that the 2 is important and that he would add a detailed comment, which I don't see. I also still see parenthesis.

Quoted 4 lines
drivers/spi/spi-geni-qcom.c new file +4 -0
+               mas->oversampling = 1;
+               /* Transmit an entire FIFO worth of data per IRQ */
+               mas->tx_wm = 1;
+               geni_se_get_wrapper_version(se, major, minor, step);
Quoted 1 line · In v1 Stephen said:

Drop extra parenthesis.

I'll further add that I'd prefer it if you based your series atop
<https://patchwork.kernel.org/patch/10412417/> which changes the prototype here.

Quoted 13 lines
drivers/spi/spi-geni-qcom.c new file +13 -0
+       /*
+        * If CS change flag is set, then toggle the CS line in between
+        * transfers and keep CS asserted after the last transfer.
+        * Else if keep CS flag asserted in between transfers and de-assert
+        * CS after the last message.
+        */
+       if (xfer->cs_change) {
+               if (list_is_last(&xfer->transfer_list,
+                               &spi->cur_msg->transfers))
+                       m_param |= FRAGMENTATION;
+       } else {
+               if (!list_is_last(&xfer->transfer_list,
+                               &spi->cur_msg->transfers))
Quoted 17 lines · In v1 Stephen said:

Combine else and if here into an else if.

drivers/spi/spi-geni-qcom.c new file +14 -0
+       mas->cur_xfer = xfer;
+       if (m_cmd & SPI_TX_ONLY) {
+               mas->tx_rem_bytes = xfer->len;
+               writel_relaxed(trans_len, se->base + SE_SPI_TX_TRANS_LEN);
+       }
+
+       if (m_cmd & SPI_RX_ONLY) {
+               writel_relaxed(trans_len, se->base + SE_SPI_RX_TRANS_LEN);
+               mas->rx_rem_bytes = xfer->len;
+       }
+       writel_relaxed(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
+       geni_se_setup_m_cmd(se, m_cmd, m_param);
+       if (m_cmd & SPI_TX_ONLY)
+               writel_relaxed(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG);
Quoted 1 line · In v1 Stephen said:

This can't be combined with above m_cmd & SPI_TX_ONLY statement?

Girish said it can't. ...but IMO if it really can't then please add a comment in the code so someone doesn't later go back and try to combine.

Quoted 14 lines
drivers/spi/spi-geni-qcom.c new file +14 -0
+static void geni_spi_handle_tx(struct spi_geni_master *mas)
+{
+       int i = 0;
+       int tx_fifo_width = mas->tx_fifo_width / BITS_PER_BYTE;
+       int max_bytes = 0;
+       const u8 *tx_buf;
+       struct geni_se *se = &mas->se;
+
+       if (!mas->cur_xfer)
+               return;
+
+       /*
+        * For non-byte aligned bits-per-word values. (e.g 9)
+        * The FIFO packing is set to 1 SPI word per FIFO word.
Quoted 10 lines · In v1 Stephen said:

Decapitalize "The"

drivers/spi/spi-geni-qcom.c new file +7 -0
+        * Assumption is that each SPI word will be accomodated in
+        * ceil (bits_per_word / bits_per_byte)
+        * and the next SPI word starts at the next byte.
+        * In such cases, we can fit 1 SPI word per FIFO word so adjust the
+        * max byte that can be sent per IRQ accordingly.
+        */
+       if ((mas->tx_fifo_width % mas->cur_word_len))
Quoted 7 lines · In v1 Stephen said:

Drop extra parenthesis please.

drivers/spi/spi-geni-qcom.c new file +4 -0
+               max_bytes = (mas->tx_fifo_depth - mas->tx_wm) *
+                               ((mas->cur_word_len / BITS_PER_BYTE) + 1);
+       else
+               max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
Quoted 11 lines · In v1 Stephen said:

The above if else needs braces, or it could be written as:

  max_bytes = mas->tx_fifo_depth - mas->tx_wm;
  if (mas->tx_fifo_width % mas->cur_word_len) {
    max_bytes *= (mas->cur_word_len / BITS_PER_BYTE) + 1;
  else
    max_bytes *= tx_fifo_width;
drivers/spi/spi-geni-qcom.c new file +2 -0
+       tx_buf = mas->cur_xfer->tx_buf;
+       tx_buf += (mas->cur_xfer->len - mas->tx_rem_bytes);
Quoted 4 lines · In v1 Stephen said:

Drop parenthesis.

+ max_bytes = min_t(int, mas->tx_rem_bytes, max_bytes);

Quoted 11 lines · In v1 Stephen said:

Why isn't max_bytes unsigned?

drivers/spi/spi-geni-qcom.c new file +8 -0
+       while (i < max_bytes) {
+               int j;
+               u32 fifo_word = 0;
+               u8 *fifo_byte;
+               int bytes_per_fifo = tx_fifo_width;
+               int bytes_to_write = 0;
+
+               if ((mas->tx_fifo_width % mas->cur_word_len))
Quoted 6 lines · In v1 Stephen said:

Drop parenthesis.

drivers/spi/spi-geni-qcom.c new file +3 -0
+                       bytes_per_fifo =
+                               (mas->cur_word_len / BITS_PER_BYTE) + 1;
+               bytes_to_write = min_t(int, max_bytes - i, bytes_per_fifo);
Quoted 6 lines · In v1 Stephen said:

More things can be unsigned?

drivers/spi/spi-geni-qcom.c new file +3 -0
+               fifo_byte = (u8 *)&fifo_word;
+               for (j = 0; j < bytes_to_write; j++)
+                       fifo_byte[j] = tx_buf[i++];
Quoted 5 lines · In v1 Stephen said:

Why are we doing all this work to fill in a fifo byte at a time? tx_buf should be a buffer of bytes that we can iowrite32_rep() with directly. And then we could just run iowrite32_rep() with some count of bytes to write? I suppose we may run into problems with unaligned size buffers, but it sounds like that doesn't happen?

Girish had a response to this and Stephen had another question which was never answered. Specifically he asked:

Quoted 1 line

Have you tested out non-byte aligned word size transfers?

Please answer and also add a comment justifying why we're doing all this work to fill a fifo a byte at a time.

Quoted 12 lines
drivers/spi/spi-geni-qcom.c new file +12 -0
+static void geni_spi_handle_rx(struct spi_geni_master *mas)
+{
+       int i = 0;
+       struct geni_se *se = &mas->se;
+       int fifo_width = mas->tx_fifo_width / BITS_PER_BYTE;
+       u32 rx_fifo_status = readl_relaxed(se->base + SE_GENI_RX_FIFO_STATUS);
+       int rx_bytes = 0;
+       int rx_wc = 0;
+       u8 *rx_buf;
+
+       if (!mas->cur_xfer)
+               return;
Quoted 18 lines · In v1 Stephen said:

This is an error condition? We should return IRQ_NONE in such a case in the irq handler? Or somehow indicate this up that we actually handled an rx or not so the irqhandler can do the right thing.

drivers/spi/spi-geni-qcom.c new file +13 -0
+       /*
+        * For non-byte aligned bits-per-word values. (e.g 9)
+        * The FIFO packing is set to 1 SPI word per FIFO word.
+        * Assumption is that each SPI word will be accomodated in
+        * ceil (bits_per_word / bits_per_byte)
+        * and the next SPI word starts at the next byte.
+        */
+       if (!(mas->tx_fifo_width % mas->cur_word_len))
+               rx_bytes += rx_wc * fifo_width;
+       else
+               rx_bytes += rx_wc *
+                       ((mas->cur_word_len / BITS_PER_BYTE) + 1);
+       rx_bytes = min_t(int, mas->rx_rem_bytes, rx_bytes);
Quoted 4 lines · In v1 Stephen said:

min_t is preferably avoided.

+ rx_buf += (mas->cur_xfer->len - mas->rx_rem_bytes);

Quoted 11 lines · In v1 Stephen said:

Drop parenthesis.

drivers/spi/spi-geni-qcom.c new file +8 -0
+       while (i < rx_bytes) {
+               u32 fifo_word = 0;
+               u8 *fifo_byte;
+               int bytes_per_fifo = fifo_width;
+               int read_bytes = 0;
+               int j;
+
+               if ((mas->tx_fifo_width % mas->cur_word_len))
Quoted 15 lines · In v1 Stephen said:

Drop parenthesis.

drivers/spi/spi-geni-qcom.c new file +12 -0
+static int spi_geni_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct spi_master *spi;
+       struct spi_geni_master *spi_geni;
+       struct resource *res;
+       struct geni_se *se;
+
+       spi = spi_alloc_master(&pdev->dev, sizeof(struct spi_geni_master));
+       if (!spi) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "Failed to alloc spi struct\n");
Quoted 13 lines · In v1 Stephen said:

We don't need allocation error messages.

drivers/spi/spi-geni-qcom.c new file +9 -0
+       platform_set_drvdata(pdev, spi);
+       spi_geni = spi_master_get_devdata(spi);
+       spi_geni->dev = &pdev->dev;
+       spi_geni->se.dev = &pdev->dev;
+       spi_geni->se.wrapper = dev_get_drvdata(pdev->dev.parent);
+       se = &spi_geni->se;
+
+       spi->bus_num = -1;
+       spi->dev.of_node = pdev->dev.of_node;
Quoted 2 lines · In v1 Mark Brown said:

This is broken, the virtual SPI device does not exist in DT and this might break things.

...though I'm as confused as Girish was. It seems like all the drivers do what you're doing... I didn't dig into the code though.

Quoted 9 lines
drivers/spi/spi-geni-qcom.c new file +9 -0
+       spi_geni->se.clk = devm_clk_get(&pdev->dev, "se");
+       if (IS_ERR(spi_geni->se.clk)) {
+               ret = PTR_ERR(spi_geni->se.clk);
+               dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
+               goto spi_geni_probe_err;
+       }
+
+       if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
+                               &spi->max_speed_hz)) {
Quoted 1 line · In v1 Stephen said:

Why does this need to come from DT?

Please remove this concept. No other SPI driver has it.

Quoted 5 lines
drivers/spi/spi-geni-qcom.c new file +5 -0
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       se->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(se->base)) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "Err IO mapping iomem\n");
Quoted 9 lines · In v1 Stephen said:

We don't need these error messages. devm_ioremap_resource() already does it.

drivers/spi/spi-geni-qcom.c new file +5 -0
+       init_completion(&spi_geni->xfer_done);
+       pm_runtime_enable(&pdev->dev);
+       ret = devm_spi_register_master(&pdev->dev, spi);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register SPI master\n");

drivers/spi/spi-geni-qcom.c line 633

Quoted 10 lines · In v1 Stephen said:

Most likely spi_register_master() is going to print what went wrong so this print is not useful.

drivers/spi/spi-geni-qcom.c new file +6 -0
+static int spi_geni_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_geni_master *spi_geni = spi_master_get_devdata(master);
+
+       geni_se_resources_off(&spi_geni->se);

Why would you need to call geni_se_resources_off()? Isn't it handled by pm_runtime?

Quoted 1 line

+ pm_runtime_put_noidle(&pdev->dev);

I'm curious: why would you have a "put" here? Won't that result in an imbalance since you don't exit probe with "get"? ...or did pm_runtime throw me for a loop again?

Quoted 7 lines
include/linux/spi/spi-geni-qcom.h new file +1 -0
new file mode 100644
index 0000000..dc95764
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
Quoted 11 lines · In v1 Stephen said:

Why?

include/linux/spi/spi-geni-qcom.h new file +8 -0
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SPI_GENI_QCOM_HEADER___
+#define __SPI_GENI_QCOM_HEADER___
+
+struct spi_geni_qcom_ctrl_data {
Quoted 2 lines · In v1 Stephen said:

What's the point of this header file and structure? This driver supports board files? Isn't everything DT now?

There was a bunch of discussion in followup threads but no closure and I still don't understand why we need this. Please remove it.

One note is that Girish seemed to justify this by saying it's useful for "inter-transfer delays within a message". Isn't this just the "delay_usecs" within a transfer? I think the answer here is to remove the header file and structure and if you can later show where it's used then we can always add it back in.

include/linux/spi/spi-geni-qcom.h

Quoted 6 lines
include/linux/spi/spi-geni-qcom.h new file +5 -1
+       u32 spi_cs_clk_delay;
+       u32 spi_inter_words_delay;
+};
+
+#endif /*__SPI_GENI_QCOM_HEADER___*/
--

I'm not sure where to comment about this, so adding it to the end:

Between v1 and v2 you totally removed all the locking. Presumably this is because you didn't want to hold the lock in handle_fifo_timeout() while waiting for the completion. IMO taking the lock out was the wrong thing to do. You should keep it, but just drop the lock before wait_for_completion_timeout() and add it back afterwards. Specifically you _don't_ want the IRQ and timeout code stomping on each other.

---

I'll also mention that you just wasted quite a bit of reviewer resources for me to repeat the refrain "you didn't address comments from v1". Reviewer time is precious. It's better that you wasted my time than Mark's, but there are still better things for me to do. Please be more careful. I realize that this is your first patch posted but ignoring previous feedback is not a good start. If you want to see the v1 discussion, you can easily find it at:

https://patchwork.kernel.org/patch/10379299/

...since I spent so much time checking over what you did vs. v1, I didn't actually have a chance to review v2 on its own merits.

-Doug

#4 lore raw

Re: [PATCH V2] spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

Hi,

Quoted 5 lines · Doug Anderson

drivers/spi/spi-geni-qcom.c line 256

Quoted 4 lines
drivers/spi/spi-geni-qcom.c new file +4 -0
+               mas->oversampling = 1;
+               /* Transmit an entire FIFO worth of data per IRQ */
+               mas->tx_wm = 1;
+               geni_se_get_wrapper_version(se, major, minor, step);
Quoted 7 lines
Quoted 1 line · In v1 Stephen said:

Drop extra parenthesis.

I'll further add that I'd prefer it if you based your series atop
<https://patchwork.kernel.org/patch/10412417/> which changes the prototype here.

Whoops. Extra parenthesis was actually referring to the line below this one, AKA:

drivers/spi/spi-geni-qcom.c line 258

Quoted 2 lines
drivers/spi/spi-geni-qcom.c new file +2 -0
+               if ((major == 1) && (minor == 0))
+                       mas->oversampling = 2;

...that still applies. ...but then ignore my comment suggesting that you base your series atop Stephen's. You already did that. Certainly you should mention somewhere in your email that your patch is based on his.

-Doug

#5 lore raw

Re: [PATCH V2] spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

In reply to Dilip Kota
Thank you for the patch! Yet something to improve:

Hi Girish,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on spi/for-next]
[also build test ERROR on v4.18-rc5 next-20180720]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Dilip-Kota/spi-spi-geni-qcom-Add-SPI-driver-support-for-GENI-based-QUP/20180721-034916
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 8.1.0

reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=8.1.0 make.cross ARCH=ia64

All errors (new ones prefixed by >>):

In file included from drivers/spi/spi-geni-qcom.c:11:
drivers/spi/spi-geni-qcom.c: In function 'spi_geni_prepare_transfer_hardware':

>> include/linux/qcom-geni-se.h:238:9: error: 'version' undeclared (first use in this function); did you mean 'vm_region'?
     step = version & HW_VER_STEP_MASK; \
            ^~~~~~~
   drivers/spi/spi-geni-qcom.c:256:3: note: in expansion of macro 'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/qcom-geni-se.h:238:9: note: each undeclared identifier is reported only once for each function it appears in
     step = version & HW_VER_STEP_MASK; \
            ^~~~~~~
   drivers/spi/spi-geni-qcom.c:256:3: note: in expansion of macro 'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
--
   In file included from drivers//spi/spi-geni-qcom.c:11:
   drivers//spi/spi-geni-qcom.c: In function 'spi_geni_prepare_transfer_hardware':
>> include/linux/qcom-geni-se.h:238:9: error: 'version' undeclared (first use in this function); did you mean 'vm_region'?
     step = version & HW_VER_STEP_MASK; \
            ^~~~~~~
   drivers//spi/spi-geni-qcom.c:256:3: note: in expansion of macro 'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/qcom-geni-se.h:238:9: note: each undeclared identifier is reported only once for each function it appears in
     step = version & HW_VER_STEP_MASK; \
            ^~~~~~~
   drivers//spi/spi-geni-qcom.c:256:3: note: in expansion of macro 'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~

vim +238 include/linux/qcom-geni-se.h

eddac5af Karthikeyan Ramasubramanian 2018-03-30  231  
eddac5af Karthikeyan Ramasubramanian 2018-03-30  232  #define geni_se_get_wrapper_version(se, major, minor, step) do { \
eddac5af Karthikeyan Ramasubramanian 2018-03-30  233  	u32 ver; \
eddac5af Karthikeyan Ramasubramanian 2018-03-30  234  \
eddac5af Karthikeyan Ramasubramanian 2018-03-30  235  	ver = geni_se_get_qup_hw_version(se); \
eddac5af Karthikeyan Ramasubramanian 2018-03-30  236  	major = (ver & HW_VER_MAJOR_MASK) >> HW_VER_MAJOR_SHFT; \
eddac5af Karthikeyan Ramasubramanian 2018-03-30  237  	minor = (ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT; \

eddac5af Karthikeyan Ramasubramanian 2018-03-30 @238 step = version & HW_VER_STEP_MASK; \
eddac5af Karthikeyan Ramasubramanian 2018-03-30 239 } while (0) eddac5af Karthikeyan Ramasubramanian 2018-03-30 240

:::::: The code at line 238 was first introduced by commit
:::::: eddac5af06546d2e7a0730e3dc02dde3dc91098a soc: qcom: Add GENI based QUP Wrapper driver

:::::: TO: Karthikeyan Ramasubramanian <[email protected]> :::::: CC: Andy Gross <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#6 lore raw

Re: [PATCH V2] spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

Quoted 84 lines · kbuild test robot

Hi Girish,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on spi/for-next]
[also build test ERROR on v4.18-rc5 next-20180720]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:
https://github.com/0day-ci/linux/commits/Dilip-Kota/spi-spi-geni-qcom-Add-SPI-driver-support-for-GENI-based-QUP/20180721-034916
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 8.1.0 reproduce:
wget
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross
-O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree GCC_VERSION=8.1.0 make.cross ARCH=ia64

All errors (new ones prefixed by >>):

In file included from drivers/spi/spi-geni-qcom.c:11:
drivers/spi/spi-geni-qcom.c: In function
'spi_geni_prepare_transfer_hardware':

Quoted 1 line
Quoted 1 line

include/linux/qcom-geni-se.h:238:9: error: 'version' undeclared (first use in this function); did you mean 'vm_region'?

     step = version & HW_VER_STEP_MASK; \
            ^~~~~~~
   drivers/spi/spi-geni-qcom.c:256:3: note: in expansion of macro
'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/qcom-geni-se.h:238:9: note: each undeclared
identifier is reported only once for each function it appears in
     step = version & HW_VER_STEP_MASK; \
            ^~~~~~~
   drivers/spi/spi-geni-qcom.c:256:3: note: in expansion of macro
'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~

--
In file included from drivers//spi/spi-geni-qcom.c:11:
drivers//spi/spi-geni-qcom.c: In function
'spi_geni_prepare_transfer_hardware':

Quoted 1 line
Quoted 1 line

include/linux/qcom-geni-se.h:238:9: error: 'version' undeclared (first use in this function); did you mean 'vm_region'?

     step = version & HW_VER_STEP_MASK; \
            ^~~~~~~
   drivers//spi/spi-geni-qcom.c:256:3: note: in expansion of macro
'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/qcom-geni-se.h:238:9: note: each undeclared
identifier is reported only once for each function it appears in
     step = version & HW_VER_STEP_MASK; \
            ^~~~~~~
   drivers//spi/spi-geni-qcom.c:256:3: note: in expansion of macro
'geni_se_get_wrapper_version'
      geni_se_get_wrapper_version(se, major, minor, step);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~

vim +238 include/linux/qcom-geni-se.h

eddac5af Karthikeyan Ramasubramanian 2018-03-30 231 eddac5af Karthikeyan Ramasubramanian 2018-03-30 232 #define geni_se_get_wrapper_version(se, major, minor, step) do { \

eddac5af Karthikeyan Ramasubramanian 2018-03-30  233  	u32 ver; \
eddac5af Karthikeyan Ramasubramanian 2018-03-30  234  \
eddac5af Karthikeyan Ramasubramanian 2018-03-30  235  	ver =

geni_se_get_qup_hw_version(se); \
eddac5af Karthikeyan Ramasubramanian 2018-03-30 236 major = (ver &
HW_VER_MAJOR_MASK) >> HW_VER_MAJOR_SHFT; \
eddac5af Karthikeyan Ramasubramanian 2018-03-30 237 minor = (ver &
HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT; \
eddac5af Karthikeyan Ramasubramanian 2018-03-30 @238 step = version
& HW_VER_STEP_MASK; \
eddac5af Karthikeyan Ramasubramanian 2018-03-30 239 } while (0) eddac5af Karthikeyan Ramasubramanian 2018-03-30 240

:::::: The code at line 238 was first introduced by commit :::::: eddac5af06546d2e7a0730e3dc02dde3dc91098a soc: qcom: Add GENI based QUP Wrapper driver

Quoted 6 lines

:::::: TO: Karthikeyan Ramasubramanian <[email protected]> :::::: CC: Andy Gross <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

HI,

For now please ignore the PATCHSET 2. I will upload a new PATCHSET addressing all the comments of patchset 1 with detailed description. Sorry for the inconvenience.

Regards,
Dilip

author
#7 lore raw

PATCH v2 1/1 dt-bindings: soc: qcom: Add device tree binding for GENI SE

In reply to Dilip Kota

From: Karthikeyan Ramasubramanian <[email protected]>

Add device tree binding support for the QCOM GENI SE driver.

---
 .../devicetree/bindings/soc/qcom/qcom,geni-se.txt  | 119 +++++++++++++++++++++
 1 file changed, 119 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt
Documentation/devicetree/bindings/soc/qcom/qcom,geni-se.txt new file +119 -0
new file mode 100644
index 0000000..d330c73
@@ -0,0 +1,119 @@
+Qualcomm Technologies, Inc. GENI Serial Engine QUP Wrapper Controller
+
+Generic Interface (GENI) based Qualcomm Universal Peripheral (QUP) wrapper
+is a programmable module for supporting a wide range of serial interfaces
+like UART, SPI, I2C, I3C, etc. A single QUP module can provide upto 8 Serial
+Interfaces, using its internal Serial Engines. The GENI Serial Engine QUP
+Wrapper controller is modeled as a node with zero or more child nodes each
+representing a serial engine.
+
+Required properties:
+- compatible:		Must be "qcom,geni-se-qup".
+- reg:			Must contain QUP register address and length.
+- clock-names:		Must contain "m-ahb" and "s-ahb".
+- clocks:		AHB clocks needed by the device.
+
+Required properties if child node exists:
+- #address-cells: 	Must be <1> for Serial Engine Address
+- #size-cells: 		Must be <1> for Serial Engine Address Size
+- ranges: 		Must be present
+
+Properties for children:
+
+A GENI based QUP wrapper controller node can contain 0 or more child nodes
+representing serial devices.  These serial devices can be a QCOM UART, I2C
+controller, SPI controller, or some combination of aforementioned devices.
+Please refer below the child node definitions for the supported serial
+interface protocols.
+
+Qualcomm Technologies Inc. GENI Serial Engine based I2C Controller
+
+Required properties:
+- compatible:		Must be "qcom,geni-i2c".
+- reg: 			Must contain QUP register address and length.
+- interrupts: 		Must contain I2C interrupt.
+- clock-names: 		Must contain "se".
+- clocks: 		Serial engine core clock needed by the device.
+- #address-cells:	Must be <1> for I2C device address.
+- #size-cells:		Must be <0> as I2C addresses have no size component.
+
+Optional property:
+- clock-frequency:	Desired I2C bus clock frequency in Hz.
+			When missing default to 400000Hz.
+
+Child nodes should conform to I2C bus binding as described in i2c.txt.
+
+Qualcomm Technologies Inc. GENI Serial Engine based UART Controller
+
+Required properties:
+- compatible:		Must be "qcom,geni-debug-uart".
+- reg: 			Must contain UART register location and length.
+- interrupts: 		Must contain UART core interrupts.
+- clock-names:		Must contain "se".
+- clocks:		Serial engine core clock needed by the device.
+
+Qualcomm Technologies Inc. GENI Serial Engine based SPI Controller
+
+Required properties:
+- compatible:		Must contain "qcom,geni-spi".
+- reg:			Must contain SPI register location and length.
+- interrupts:		Must contain SPI controller interrupts.
+- clock-names:		Must contain "se".
+- clocks:		Serial engine core clock needed by the device.
+- spi-max-frequency:	Specifies maximum SPI clock frequency, units - Hz.
+- #address-cells:	Must be <1> to define a chip select address on
+			the SPI bus.
+- #size-cells:		Must be <0>.
+
+SPI slave nodes must be children of the SPI master node and conform to SPI bus
+binding as described in Documentation/devicetree/bindings/spi/spi-bus.txt.
+
+Example:
+	geniqup@8c0000 {
+		compatible = "qcom,geni-se-qup";
+		reg = <0x8c0000 0x6000>;
+		clock-names = "m-ahb", "s-ahb";
+		clocks = <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		i2c0: i2c@a94000 {
+			compatible = "qcom,geni-i2c";
+			reg = <0xa94000 0x4000>;
+			interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+			clock-names = "se";
+			clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>;
+			pinctrl-names = "default", "sleep";
+			pinctrl-0 = <&qup_1_i2c_5_active>;
+			pinctrl-1 = <&qup_1_i2c_5_sleep>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		uart0: serial@a88000 {
+			compatible = "qcom,geni-debug-uart";
+			reg = <0xa88000 0x7000>;
+			interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+			clock-names = "se";
+			clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>;
+			pinctrl-names = "default", "sleep";
+			pinctrl-0 = <&qup_1_uart_3_active>;
+			pinctrl-1 = <&qup_1_uart_3_sleep>;
+		};
+
+		spi0: spi@a84000 {
+			compatible = "qcom,geni-spi";
+			reg = <0xa84000 0x4000>;
+			interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+			clock-names = "se";
+			clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>;
+			pinctrl-names = "default", "sleep";
+			pinctrl-0 = <&qup_1_spi_2_active>;
+			pinctrl-1 = <&qup_1_spi_2_sleep>;
+			spi-max-frequency = <19200000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	}
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
#8 lore raw

Re: [PATCH V2] dt-bindings: soc: qcom: Add device tree binding for GENI SE

Hi,

Quoted 10 lines · Dilip Kota

From: Karthikeyan Ramasubramanian <[email protected]>

Add device tree binding support for the QCOM GENI SE driver.

Quoted 3 lines
---
 .../devicetree/bindings/soc/qcom/qcom,geni-se.txt  | 119 +++++++++++++++++++++
 1 file changed, 119 insertions(+)

Just a note to mention that this patch landed two months ago and can already be found in mainline Linux. See commit e9b02415565b ("dt-bindings: soc: qcom: Add device tree binding for GENI SE").

...I think Mark Brown made comments on v1 of the SPI driver that he was surprised about how the bindings landed, but that doesn't mean you should re-post a patch that is already in mainline--just point to the patch that landed by git hash. If something about the bindings needs to change then post a patch that changes them.

-Doug

#9 lore raw
In reply to Dilip Kota

Hi,

Quoted 7 lines · Dilip Kota

This patch series adds SPI driver support for GENI based QUP. Also adding the device tree binding document for reference as per reviewers request which was merged in Linus tree.

Girish Mahadevan (1):
spi: spi-geni-qcom: Add SPI driver support for GENI based QUP

Quoted 7 lines
 drivers/spi/Kconfig               |  12 +
 drivers/spi/Makefile              |   1 +
 drivers/spi/spi-geni-qcom.c       | 685 ++++++++++++++++++++++++++++++++++++++
 include/linux/spi/spi-geni-qcom.h |  14 +
 4 files changed, 712 insertions(+)
 create mode 100644 drivers/spi/spi-geni-qcom.c
 create mode 100644 include/linux/spi/spi-geni-qcom.h

This looks like it was supposed to be a cover letter. Typically that's labelled as "patch 0" in the series. Other handy traditions:

* The cover letter should contain a description of what changed between this patch and the last one

* You only want a cover letter for a patch series with more than one patch in it. In your case you only have one patch so you should have no cover letter.

* It's handy if your cover letter has prefixes that match the subsystem just like the patch itself. AKA: "spi: spi-geni-qcom:"

Personally I use "patman" to help me with sending out my patches. See
<https://github.com/u-boot/u-boot/tree/master/tools/patman>.

-Doug