linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] SPI controller driver for Netlogic XLP SoCs
@ 2015-08-19  5:09 kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
       [not found] ` <1439960957-4213-1-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: kamlakant.patel-dY08KVG/lbpWk0Htik3J/w @ 2015-08-19  5:09 UTC (permalink / raw)
  To: Mark Brown
  Cc: Kamlakant Patel, linux-spi-u79uwXL29TY76Z2rM5mHXA, Jonathan Corbet

From: Kamlakant Patel <kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

This patch set adds support for SPI controller driver on Netlogic
XLP MIPS64 SOCs.

Kamlakant Patel (2):
  spi/xlp: SPI controller driver for Netlogic XLP SoCs
  spi: Add DT bindings documentation for Netlogic XLP SPI controller

 Documentation/devicetree/bindings/spi/spi-xlp.txt |   40 ++
 drivers/spi/Kconfig                               |   11 +
 drivers/spi/Makefile                              |    1 +
 drivers/spi/spi-xlp.c                             |  454 +++++++++++++++++++++
 4 files changed, 506 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-xlp.txt
 create mode 100644 drivers/spi/spi-xlp.c

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

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

* [PATCH 1/2] spi/xlp: SPI controller driver for Netlogic XLP SoCs
       [not found] ` <1439960957-4213-1-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
@ 2015-08-19  5:09   ` kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
       [not found]     ` <1439960957-4213-2-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  2015-08-19  5:09   ` [PATCH 2/2] spi: Add DT bindings documentation for Netlogic XLP SPI controller kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
  1 sibling, 1 reply; 6+ messages in thread
From: kamlakant.patel-dY08KVG/lbpWk0Htik3J/w @ 2015-08-19  5:09 UTC (permalink / raw)
  To: Mark Brown; +Cc: Kamlakant Patel, linux-spi-u79uwXL29TY76Z2rM5mHXA

From: Kamlakant Patel <kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

Add SPI Master controller driver for the SPI interface on XLP8XX,
XLP3XX, XLP2XX, XLP9XX and XLP5XX family of Netlogic XLP MIPS64 processors.

Signed-off-by: Kamlakant Patel <kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/spi/Kconfig   |   11 ++
 drivers/spi/Makefile  |    1 +
 drivers/spi/spi-xlp.c |  454 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 466 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/spi-xlp.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b0f30fb..2543f69 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -598,6 +598,17 @@ config SPI_XILINX
 
 	  Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
 
+config SPI_XLP
+        tristate "Netlogic XLP SPI controller driver"
+        depends on CPU_XLP
+        help
+	  Enable support for the SPI controller on the Netlogic XLP SoCs.
+	  Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX
+	  and XLP5XX.
+
+	  If you have a Netlogic XLP platform say Y here.
+	  If unsure, say N.
+
 config SPI_XTENSA_XTFPGA
 	tristate "Xtensa SPI controller for xtfpga"
 	depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 1154dba..87d43c7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -88,5 +88,6 @@ obj-$(CONFIG_SPI_TOPCLIFF_PCH)		+= spi-topcliff-pch.o
 obj-$(CONFIG_SPI_TXX9)			+= spi-txx9.o
 obj-$(CONFIG_SPI_XCOMM)		+= spi-xcomm.o
 obj-$(CONFIG_SPI_XILINX)		+= spi-xilinx.o
+obj-$(CONFIG_SPI_XLP)			+= spi-xlp.o
 obj-$(CONFIG_SPI_XTENSA_XTFPGA)		+= spi-xtensa-xtfpga.o
 obj-$(CONFIG_SPI_ZYNQMP_GQSPI)		+= spi-zynqmp-gqspi.o
diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c
new file mode 100644
index 0000000..70fd194
--- /dev/null
+++ b/drivers/spi/spi-xlp.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2003-2015 Broadcom Corporation
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (GPL v2)
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/of.h>
+#include <linux/interrupt.h>
+
+/* SPI Configuration Register */
+#define XLP_SPI_CONFIG			0x00
+#define XLP_SPI_CPHA			BIT(0)
+#define XLP_SPI_CPOL			BIT(1)
+#define XLP_SPI_CS_POL			BIT(2)
+#define XLP_SPI_TXMISO_EN		BIT(3)
+#define XLP_SPI_TXMOSI_EN		BIT(4)
+#define XLP_SPI_RXMISO_EN		BIT(5)
+#define XLP_SPI_CS_LSBFE		BIT(10)
+#define XLP_SPI_RXCAP_EN		BIT(11)
+
+/* SPI Frequency Divider Register */
+#define XLP_SPI_FDIV			0x04
+
+/* SPI Command Register */
+#define XLP_SPI_CMD			0x08
+#define XLP_SPI_CMD_IDLE_MASK		0x0
+#define XLP_SPI_CMD_TX_MASK		0x1
+#define XLP_SPI_CMD_RX_MASK		0x2
+#define XLP_SPI_CMD_TXRX_MASK		0x3
+#define XLP_SPI_CMD_CONT		BIT(4)
+#define XLP_SPI_XFR_BITCNT_SHIFT	16
+
+/* SPI Status Register */
+#define XLP_SPI_STATUS			0x0c
+#define XLP_SPI_XFR_PENDING		BIT(0)
+#define XLP_SPI_XFR_DONE		BIT(1)
+#define XLP_SPI_TX_TH_OV		BIT(2)
+#define XLP_SPI_RX_TH_OV		BIT(3)
+#define XLP_SPI_TX_UF			BIT(4)
+#define XLP_SPI_RX_OF			BIT(5)
+#define XLP_SPI_STAT_MASK		0x3f
+
+/* SPI Interrupt Enable Register */
+#define XLP_SPI_INTR_EN			0x10
+#define XLP_SPI_INTR_DONE		BIT(0)
+#define XLP_SPI_INTR_TXTH		BIT(1)
+#define XLP_SPI_INTR_RXTH		BIT(2)
+#define XLP_SPI_INTR_TXUF		BIT(3)
+#define XLP_SPI_INTR_RXOF		BIT(4)
+#define XLP_SPI_RXINTR_MASK		0x15
+#define XLP_SPI_TXINTR_MASK		0xb
+#define XLP_SPI_INTR_MASK		0x1f
+
+/* SPI FIFO Threshold Register */
+#define XLP_SPI_FIFO_THRESH		0x14
+#define XLP_SPI_RXFIFO_THRESH_SHIFT	0
+#define XLP_SPI_TXFIFO_THRESH_SHIFT	4
+
+/* SPI FIFO Word Count Register */
+#define XLP_SPI_FIFO_WCNT		0x18
+#define XLP_SPI_RXFIFO_WCNT_SHIFT	0
+#define XLP_SPI_TXFIFO_WCNT_SHIFT	4
+#define XLP_SPI_FIFO_WCNT_MASK		0xf
+
+/* SPI Transmit Data FIFO Register */
+#define XLP_SPI_TXDATA_FIFO		0x1c
+
+/* SPI Receive Data FIFO Register */
+#define XLP_SPI_RXDATA_FIFO		0x20
+
+/* SPI System Control Register */
+#define XLP_SPI_SYSCTRL			0x100
+#define XLP_SPI_SYS_RESET		BIT(0)
+#define XLP_SPI_SYS_CLKDIS		BIT(1)
+#define XLP_SPI_SYS_PMEN		BIT(8)
+
+#define SPI_CS_OFFSET			0x40
+#define XLP_SPI_TXRXTH			0x80
+#define XLP_SPI_FIFO_SIZE		8
+#define XLP_SPI_MAX_CS			4
+#define XLP_SPI_DEFAULT_FREQ		133333333
+#define XLP_SPI_FDIV_MIN		4
+#define XLP_SPI_FDIV_MAX		65535
+/*
+ * SPI can transfer only 28 bytes properly at a time. So split the
+ * transfer into 28 bytes size.
+ */
+#define XLP_SPI_XFER_SIZE		28
+
+struct xlp_spi_priv {
+	struct device		dev;		/* device structure */
+	void __iomem		*base;		/* spi registers base address */
+	const u8		*tx_buf;	/* tx data buffer */
+	u8			*rx_buf;	/* rx data buffer */
+	int			tx_len;		/* tx xfer length */
+	int			rx_len;		/* rx xfer length */
+	int			txerrors;	/* TXFIFO underflow count */
+	int			rxerrors;	/* RXFIFO overflow count */
+	int			cs;		/* slave device chip select */
+	u32			spi_clk;	/* spi clock frequency */
+	bool			cmd_cont;	/* cs active */
+	struct completion	done;		/* completion notification */
+};
+
+static inline u32 xlp_spi_reg_read(struct xlp_spi_priv *priv,
+				int cs, int regoff)
+{
+	return readl(priv->base + regoff + cs * SPI_CS_OFFSET);
+}
+
+static inline void xlp_spi_reg_write(struct xlp_spi_priv *priv, int cs,
+				int regoff, u32 val)
+{
+	writel(val, priv->base + regoff + cs * SPI_CS_OFFSET);
+}
+
+static inline void xlp_spi_sysctl_write(struct xlp_spi_priv *priv,
+				int regoff, u32 val)
+{
+	writel(val, priv->base + regoff);
+}
+
+/*
+ * Setup global SPI_SYSCTRL register for all SPI channels.
+ */
+static void xlp_spi_sysctl_setup(struct xlp_spi_priv *xspi)
+{
+	int cs;
+
+	for (cs = 0; cs < XLP_SPI_MAX_CS; cs++)
+		xlp_spi_sysctl_write(xspi, XLP_SPI_SYSCTRL,
+				XLP_SPI_SYS_RESET << cs);
+	xlp_spi_sysctl_write(xspi, XLP_SPI_SYSCTRL, XLP_SPI_SYS_PMEN);
+}
+
+static int xlp_spi_setup(struct spi_device *spi)
+{
+	struct xlp_spi_priv *xspi;
+	u32 fdiv, cfg;
+	int cs;
+
+	if (!spi->bits_per_word)
+		spi->bits_per_word = 8;
+
+	xspi = spi_master_get_devdata(spi->master);
+	cs = spi->chip_select;
+	/*
+	 * The value of fdiv must be between 4 and 65535.
+	 */
+	fdiv = DIV_ROUND_UP(xspi->spi_clk, spi->max_speed_hz);
+	fdiv = fdiv < XLP_SPI_FDIV_MIN ? XLP_SPI_FDIV_MIN : fdiv;
+	fdiv = fdiv > XLP_SPI_FDIV_MAX ? XLP_SPI_FDIV_MAX : fdiv;
+
+	xlp_spi_reg_write(xspi, cs, XLP_SPI_FDIV, fdiv);
+	xlp_spi_reg_write(xspi, cs, XLP_SPI_FIFO_THRESH, XLP_SPI_TXRXTH);
+	cfg = xlp_spi_reg_read(xspi, cs, XLP_SPI_CONFIG);
+	if (spi->mode & SPI_CPHA)
+		cfg |= XLP_SPI_CPHA;
+	else
+		cfg &= ~XLP_SPI_CPHA;
+	if (spi->mode & SPI_CPOL)
+		cfg |= XLP_SPI_CPOL;
+	else
+		cfg &= ~XLP_SPI_CPOL;
+	if (!(spi->mode & SPI_CS_HIGH))
+		cfg |= XLP_SPI_CS_POL;
+	else
+		cfg &= ~XLP_SPI_CS_POL;
+	if (spi->mode & SPI_LSB_FIRST)
+		cfg |= XLP_SPI_CS_LSBFE;
+	else
+		cfg &= ~XLP_SPI_CS_LSBFE;
+
+	cfg |= XLP_SPI_TXMOSI_EN | XLP_SPI_RXMISO_EN;
+	if (fdiv == 4)
+		cfg |= XLP_SPI_RXCAP_EN;
+	xlp_spi_reg_write(xspi, cs, XLP_SPI_CONFIG, cfg);
+
+	return 0;
+}
+
+static void xlp_spi_read_rxfifo(struct xlp_spi_priv *xspi)
+{
+	u32 rx_data, rxfifo_cnt;
+	int i, j, nbytes;
+
+	rxfifo_cnt = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_FIFO_WCNT);
+	rxfifo_cnt &= XLP_SPI_FIFO_WCNT_MASK;
+	while (rxfifo_cnt) {
+		rx_data = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_RXDATA_FIFO);
+		j = 0;
+		nbytes = xspi->rx_len > 4 ? 4 : xspi->rx_len;
+		for (i = nbytes - 1; i >= 0; i--, j++)
+			xspi->rx_buf[i] = (rx_data >> (j * 8)) & 0xff;
+
+		xspi->rx_len -= nbytes;
+		xspi->rx_buf += nbytes;
+		rxfifo_cnt--;
+	}
+}
+
+static void xlp_spi_fill_txfifo(struct xlp_spi_priv *xspi)
+{
+	u32 tx_data, txfifo_cnt;
+	int i, j, nbytes;
+
+	txfifo_cnt = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_FIFO_WCNT);
+	txfifo_cnt >>= XLP_SPI_TXFIFO_WCNT_SHIFT;
+	txfifo_cnt &= XLP_SPI_FIFO_WCNT_MASK;
+	while (xspi->tx_len && (txfifo_cnt < XLP_SPI_FIFO_SIZE)) {
+		j = 0;
+		tx_data = 0;
+		nbytes = xspi->tx_len > 4 ? 4 : xspi->tx_len;
+		for (i = nbytes - 1; i >= 0; i--, j++)
+			tx_data |= xspi->tx_buf[i] << (j * 8);
+
+		xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_TXDATA_FIFO, tx_data);
+		xspi->tx_len -= nbytes;
+		xspi->tx_buf += nbytes;
+		txfifo_cnt++;
+	}
+}
+
+static irqreturn_t xlp_spi_interrupt(int irq, void *dev_id)
+{
+	struct xlp_spi_priv *xspi = dev_id;
+	u32 stat;
+
+	stat = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_STATUS);
+	if (xspi->tx_len) {
+		if (stat & XLP_SPI_TX_TH_OV)
+			xlp_spi_fill_txfifo(xspi);
+		if (stat & XLP_SPI_TX_UF)
+			xspi->txerrors++;
+	}
+	if (xspi->rx_len) {
+		if (stat & XLP_SPI_RX_TH_OV)
+			xlp_spi_read_rxfifo(xspi);
+		if (stat & XLP_SPI_RX_OF)
+			xspi->rxerrors++;
+	}
+	/* ACK all interrupts */
+	xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_STATUS,
+				(stat & XLP_SPI_STAT_MASK));
+	if (stat & XLP_SPI_XFR_DONE)
+		complete(&xspi->done);
+
+	return IRQ_HANDLED;
+}
+
+static void xlp_spi_send_cmd(struct xlp_spi_priv *xspi, int xfer_len,
+			int cmd_cont)
+{
+	u32 cmd = 0;
+
+	if (xspi->tx_buf)
+		cmd |= XLP_SPI_CMD_TX_MASK;
+	if (xspi->rx_buf)
+		cmd |= XLP_SPI_CMD_RX_MASK;
+	if (cmd_cont)
+		cmd |= XLP_SPI_CMD_CONT;
+	cmd |= ((xfer_len * 8 - 1) << XLP_SPI_XFR_BITCNT_SHIFT);
+	xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_CMD, cmd);
+}
+
+static int xlp_spi_xfer_block(struct  xlp_spi_priv *xs,
+		const unsigned char *tx_buf,
+		unsigned char *rx_buf, int xfer_len, int cmd_cont)
+{
+	int timeout;
+
+	xs->tx_buf = tx_buf;
+	xs->rx_buf = rx_buf;
+	xs->tx_len = (xs->tx_buf == NULL) ? 0 : xfer_len;
+	xs->rx_len = (xs->rx_buf == NULL) ? 0 : xfer_len;
+	xs->txerrors = xs->rxerrors = 0;
+	/* fill TXDATA_FIFO, then send the CMD */
+	if (xs->tx_len)
+		xlp_spi_fill_txfifo(xs);
+
+	xlp_spi_send_cmd(xs, xfer_len, cmd_cont);
+	if (xs->tx_len)
+		xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN,
+				XLP_SPI_INTR_MASK);
+	else
+		xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN,
+				XLP_SPI_RXINTR_MASK);
+
+	timeout = wait_for_completion_timeout(&xs->done,
+				msecs_to_jiffies(1000));
+	/* Disable interrupts */
+	xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, 0x0);
+	if (!timeout) {
+		dev_err(&xs->dev, "xfer timedout!\n");
+		goto out;
+	}
+	if (xs->txerrors || xs->rxerrors)
+		dev_err(&xs->dev, "Over/Underflow rx %d tx %d xfer %d!\n",
+				xs->rxerrors, xs->txerrors, xfer_len);
+
+	return xfer_len;
+out:
+	return -ETIMEDOUT;
+}
+
+static int xlp_spi_txrx_bufs(struct xlp_spi_priv *xs, struct spi_transfer *t)
+{
+	int bytesleft, sz;
+	unsigned char *rx_buf;
+	const unsigned char *tx_buf;
+
+	tx_buf = t->tx_buf;
+	rx_buf = t->rx_buf;
+	bytesleft = t->len;
+	while (bytesleft) {
+		if (bytesleft > XLP_SPI_XFER_SIZE)
+			sz = xlp_spi_xfer_block(xs, tx_buf, rx_buf,
+					XLP_SPI_XFER_SIZE, 1);
+		else
+			sz = xlp_spi_xfer_block(xs, tx_buf, rx_buf,
+					bytesleft, xs->cmd_cont);
+		if (sz < 0)
+			return sz;
+		bytesleft -= sz;
+		if (tx_buf)
+			tx_buf += sz;
+		if (rx_buf)
+			rx_buf += sz;
+	}
+	return t->len;
+}
+
+static int xlp_spi_transfer_one(struct spi_master *master,
+					struct spi_message *msg)
+{
+	struct spi_transfer *t;
+	struct spi_device *spi = msg->spi;
+	struct xlp_spi_priv *xspi = spi_master_get_devdata(spi->master);
+	int ret_len, status = 0;
+
+	xspi->cs = spi->chip_select;
+	xspi->dev = spi->dev;
+	list_for_each_entry(t, &msg->transfers, transfer_list) {
+		if (t->transfer_list.next == &msg->transfers)
+			xspi->cmd_cont = 0;
+		else
+			xspi->cmd_cont = 1;
+
+		ret_len = xlp_spi_txrx_bufs(xspi, t);
+		if (ret_len != t->len || ret_len < 0) {
+			status = -EIO;
+			goto err;
+		} else
+			msg->actual_length += ret_len;
+	}
+err:
+	msg->status = status;
+	spi_finalize_current_message(master);
+	return status;
+}
+
+static int xlp_spi_probe(struct platform_device *pdev)
+{
+	struct spi_master *master;
+	struct xlp_spi_priv *xspi;
+	struct resource *res;
+	int irq, err;
+
+	xspi = devm_kzalloc(&pdev->dev, sizeof(*xspi), GFP_KERNEL);
+	if (!xspi)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "can't get IOMEM resource\n");
+		return -ENODEV;
+	}
+	xspi->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(xspi->base))
+		return PTR_ERR(xspi->base);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "Failed to get IRQ\n");
+		return irq;
+	}
+	err = devm_request_irq(&pdev->dev, irq, xlp_spi_interrupt, 0,
+			pdev->name, xspi);
+	if (err) {
+		dev_err(&pdev->dev, "unable to request irq %d\n", irq);
+		return err;
+	}
+
+	err = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+				&xspi->spi_clk);
+	if (err)
+		xspi->spi_clk = XLP_SPI_DEFAULT_FREQ;
+
+	master = spi_alloc_master(&pdev->dev, 0);
+	if (!master) {
+		dev_err(&pdev->dev, "could not alloc master\n");
+		return -ENOMEM;
+	}
+
+	master->bus_num = 0;
+	master->num_chipselect = XLP_SPI_MAX_CS;
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+	master->setup = xlp_spi_setup;
+	master->transfer_one_message = xlp_spi_transfer_one;
+	master->dev.of_node = pdev->dev.of_node;
+
+	init_completion(&xspi->done);
+	spi_master_set_devdata(master, xspi);
+	xlp_spi_sysctl_setup(xspi);
+
+	/* register spi controller */
+	err = devm_spi_register_master(&pdev->dev, master);
+	if (err) {
+		dev_err(&pdev->dev, "spi register master failed!\n");
+		spi_master_put(master);
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id xlp_spi_dt_id[] = {
+	{ .compatible = "netlogic,xlp832-spi" },
+	{ },
+};
+
+static struct platform_driver xlp_spi_driver = {
+	.probe	= xlp_spi_probe,
+	.driver = {
+		.name	= "xlp-spi",
+		.of_match_table = xlp_spi_dt_id,
+	},
+};
+module_platform_driver(xlp_spi_driver);
+
+MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>");
+MODULE_DESCRIPTION("Netlogic XLP SPI controller driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.1

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

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

* [PATCH 2/2] spi: Add DT bindings documentation for Netlogic XLP SPI controller
       [not found] ` <1439960957-4213-1-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  2015-08-19  5:09   ` [PATCH 1/2] spi/xlp: " kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
@ 2015-08-19  5:09   ` kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
       [not found]     ` <1439960957-4213-3-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  1 sibling, 1 reply; 6+ messages in thread
From: kamlakant.patel-dY08KVG/lbpWk0Htik3J/w @ 2015-08-19  5:09 UTC (permalink / raw)
  To: Mark Brown
  Cc: Kamlakant Patel, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	Jonathan Corbet, linux-doc-u79uwXL29TY76Z2rM5mHXA

From: Kamlakant Patel <kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

Add DT bindings documentation for SPI controller driver used by
Netlogic XLP MIPS64 SoCs.

Signed-off-by: Kamlakant Patel <kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 Documentation/devicetree/bindings/spi/spi-xlp.txt |   40 +++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-xlp.txt

diff --git a/Documentation/devicetree/bindings/spi/spi-xlp.txt b/Documentation/devicetree/bindings/spi/spi-xlp.txt
new file mode 100644
index 0000000..a8bbca3
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-xlp.txt
@@ -0,0 +1,40 @@
+SPI Master controller for Netlogic XLP MIPS64 SOCs
+==================================================
+
+Currently this SPI controller driver is supported for the following
+Netlogic XLP SoCs:
+	XLP832, XLP316, XLP208, XLP980, XLP532
+
+Required properties:
+- compatible	: Should be "netlogic,xlp832-spi".
+- #address-cell	: Number of cells required to define a chip select address
+		  on the SPI bus.
+- #size-cells	: Should be zero.
+- reg:		: Should contain register location and length.
+- interrupts	: Interrupt number used by this controller.
+- interrupt-parent: Phandle of the parent interrupt controller.
+- clock-frequency : [OPTIONAL] Input clock frequency to the SPI block in Hz.
+		    Default is 133333333 Hz.
+
+SPI slave nodes must be children of the SPI master node and can contain
+properties described in Documentation/devicetree/bindings/spi/spi-bus.txt.
+
+Example:
+
+	spi: xlp_spi@3a100 {
+		compatible = "netlogic,xlp832-spi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0 0x3a100 0x100>;
+		clock-frequency = <133333333>;
+		interrupts = <34>;
+		interrupt-parent = <&pic>;
+
+		spi_nor@1 {
+			compatible = "spansion,s25sl12801";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <1>;	/* Chip Select */
+			spi-max-frequency = <40000000>;
+		};
+};
-- 
1.7.1

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

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

* Re: [PATCH 1/2] spi/xlp: SPI controller driver for Netlogic XLP SoCs
       [not found]     ` <1439960957-4213-2-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
@ 2015-08-19 17:48       ` Mark Brown
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2015-08-19 17:48 UTC (permalink / raw)
  To: kamlakant.patel-dY08KVG/lbpWk0Htik3J/w; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA

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

On Wed, Aug 19, 2015 at 10:39:16AM +0530, kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org wrote:

> +config SPI_XLP
> +        tristate "Netlogic XLP SPI controller driver"
> +        depends on CPU_XLP

Can we not have an || COMPILE_TEST here?  There's no headers included
that look like a problem.

It also looks like you have tab/space damage here.

> +static int xlp_spi_setup(struct spi_device *spi)
> +{
> +	struct xlp_spi_priv *xspi;
> +	u32 fdiv, cfg;
> +	int cs;
> +
> +	if (!spi->bits_per_word)
> +		spi->bits_per_word = 8;

The core will ensure that bits_per_word is always set, there is no need
to duplicate core functionality.

> +	/*
> +	 * The value of fdiv must be between 4 and 65535.
> +	 */
> +	fdiv = DIV_ROUND_UP(xspi->spi_clk, spi->max_speed_hz);
> +	fdiv = fdiv < XLP_SPI_FDIV_MIN ? XLP_SPI_FDIV_MIN : fdiv;
> +	fdiv = fdiv > XLP_SPI_FDIV_MAX ? XLP_SPI_FDIV_MAX : fdiv;

Please write if statements using the standard if construct, it's much
better for legibility.

> +	while (rxfifo_cnt) {
> +		rx_data = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_RXDATA_FIFO);
> +		j = 0;
> +		nbytes = xspi->rx_len > 4 ? 4 : xspi->rx_len;

This is another (probably more serious) example of the problems with the
ternery operator.

> +	txfifo_cnt = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_FIFO_WCNT);
> +	txfifo_cnt >>= XLP_SPI_TXFIFO_WCNT_SHIFT;
> +	txfifo_cnt &= XLP_SPI_FIFO_WCNT_MASK;

This is a bit surprising - I'd expect a _MASK define to define the mask
for the register field so we'd mask then shift rather than shift then
mask.

> +static irqreturn_t xlp_spi_interrupt(int irq, void *dev_id)
> +{
> +	struct xlp_spi_priv *xspi = dev_id;
> +	u32 stat;
> +
> +	stat = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_STATUS);
> +	if (xspi->tx_len) {
> +		if (stat & XLP_SPI_TX_TH_OV)
> +			xlp_spi_fill_txfifo(xspi);
> +		if (stat & XLP_SPI_TX_UF)
> +			xspi->txerrors++;
> +	}
> +	if (xspi->rx_len) {
> +		if (stat & XLP_SPI_RX_TH_OV)
> +			xlp_spi_read_rxfifo(xspi);
> +		if (stat & XLP_SPI_RX_OF)
> +			xspi->rxerrors++;

We should tell the user about errors more noticably to aid debugging -
I'd expect to see us printing an error message here.

> +	}
> +	/* ACK all interrupts */
> +	xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_STATUS,
> +				(stat & XLP_SPI_STAT_MASK));

This unconditionally acknowledges all interrupts even if we didn't
handle them.

> +	if (stat & XLP_SPI_XFR_DONE)
> +		complete(&xspi->done);
> +
> +	return IRQ_HANDLED;
> +}

We're also unconditionally reporting that we handled an interrupt even
if we didn't which will break if the interrupt is ever shared and
prevent the kernel interrupt subsystem error handling working.

> +	xlp_spi_send_cmd(xs, xfer_len, cmd_cont);
> +	if (xs->tx_len)
> +		xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN,
> +				XLP_SPI_INTR_MASK);
> +	else
> +		xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN,
> +				XLP_SPI_RXINTR_MASK);

So the device is single duplex?

> +static int xlp_spi_transfer_one(struct spi_master *master,
> +					struct spi_message *msg)
> +{

This is called transfer_one() but it's actually a transfer_one_message()
operation.  Though it looks like we should be able to convert it into a
transfer_one() operation and make greater use of core functionality.

> +		if (t->transfer_list.next == &msg->transfers)
> +			xspi->cmd_cont = 0;
> +		else
> +			xspi->cmd_cont = 1;

This is spi_tansfer_is_last() (and should've been using list_is_last()
anyway AFAICT).

> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "can't get IOMEM resource\n");
> +		return -ENODEV;
> +	}
> +	xspi->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(xspi->base))
> +		return PTR_ERR(xspi->base);

Just pass the resource to devm_ioremap_resource(), it'll handle a lookup
failure for you.

> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0) {
> +		dev_err(&pdev->dev, "Failed to get IRQ\n");
> +		return irq;
> +	}

Print any error codes you get to help users trying to fix problems.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH 2/2] spi: Add DT bindings documentation for Netlogic XLP SPI controller
       [not found]     ` <1439960957-4213-3-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
@ 2015-08-19 17:53       ` Mark Brown
       [not found]         ` <20150826054301.GB10532@patelk@broadcom.com>
  0 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2015-08-19 17:53 UTC (permalink / raw)
  To: kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
  Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA, Jonathan Corbet,
	linux-doc-u79uwXL29TY76Z2rM5mHXA

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

On Wed, Aug 19, 2015 at 10:39:17AM +0530, kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org wrote:

> +- clock-frequency : [OPTIONAL] Input clock frequency to the SPI block in Hz.
> +		    Default is 133333333 Hz.

I would expect this to be specifying the input clock to the block via
the standard clock binding rather than just hard coding a number in
here.  This means the binding will continue to work for more complex
sysetems with programmable clocks and is generally more standard.  SoCs
can still specify hard coded fixed frequency clocks as fixed clocks in
the DT.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

* Re: [PATCH 2/2] spi: Add DT bindings documentation for Netlogic XLP SPI controller
       [not found]           ` <20150826054301.GB10532@patelk-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
@ 2015-08-26 10:22             ` Mark Brown
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2015-08-26 10:22 UTC (permalink / raw)
  To: Kamlakant Patel
  Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA, Jonathan Corbet,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	jchandra-dY08KVG/lbpWk0Htik3J/w

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

On Wed, Aug 26, 2015 at 11:13:01AM +0530, Kamlakant Patel wrote:
> On Wed, Aug 19, 2015 at 10:53:04AM -0700, Mark Brown wrote:
> > On Wed, Aug 19, 2015 at 10:39:17AM +0530, kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org wrote:

> > > +- clock-frequency : [OPTIONAL] Input clock frequency to the SPI block in Hz.
> > > +		    Default is 133333333 Hz.

> > I would expect this to be specifying the input clock to the block via
> > the standard clock binding rather than just hard coding a number in
> > here.  This means the binding will continue to work for more complex
> > sysetems with programmable clocks and is generally more standard.  SoCs
> > can still specify hard coded fixed frequency clocks as fixed clocks in
> > the DT.

> We don't have our clock framework upstream yet, and don't have
> of_clk_init hook for Netlogic XLP platform to use fixed-clock. I will
> update the driver and dts to use standard clock framework but for now we
> will continue using "clock-frequency" and will update when clock framework
> is upstream.

No, you should leave it out - DT bindings are supposed to be permanent
so we don't want to have temporary bindings that are expected to be
removed quickly.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

end of thread, other threads:[~2015-08-26 10:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-19  5:09 [PATCH 0/2] SPI controller driver for Netlogic XLP SoCs kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
     [not found] ` <1439960957-4213-1-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2015-08-19  5:09   ` [PATCH 1/2] spi/xlp: " kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
     [not found]     ` <1439960957-4213-2-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2015-08-19 17:48       ` Mark Brown
2015-08-19  5:09   ` [PATCH 2/2] spi: Add DT bindings documentation for Netlogic XLP SPI controller kamlakant.patel-dY08KVG/lbpWk0Htik3J/w
     [not found]     ` <1439960957-4213-3-git-send-email-kamlakant.patel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2015-08-19 17:53       ` Mark Brown
     [not found]         ` <20150826054301.GB10532@patelk@broadcom.com>
     [not found]           ` <20150826054301.GB10532@patelk-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2015-08-26 10:22             ` Mark Brown

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