[PATCH RFC 1/5] spi: core: add support to work in Slave mode

From: jiada_wang
Date: Thu Apr 13 2017 - 08:15:43 EST


From: Jiada Wang <jiada_wang@xxxxxxxxxx>

Add support for SPI bus controller to work in slave mode using
the existing SPI master framework.
- SPI device on SPI bus controller with 'spi-slave' property
declared in DT node represents SPI controller itself to work
as a slave device and listening to external SPI master devices
- when SPI bus controller works in slave mode, 'chip_select' and
'max_speed_hz' are not required.
- SPI slave mode continue to use 'struct spi_master'

Signed-off-by: Jiada Wang <jiada_wang@xxxxxxxxxx>
---
Documentation/devicetree/bindings/spi/spi-bus.txt | 27 ++++++++++++++---------
Documentation/spi/spi-summary | 19 +++++++++++-----
drivers/spi/Kconfig | 14 +++++++++++-
drivers/spi/spi.c | 23 ++++++++++++++++++-
include/linux/spi/spi.h | 15 +++++++++++++
5 files changed, 80 insertions(+), 18 deletions(-)

diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
index 4b1d6e7..96e93ba 100644
--- a/Documentation/devicetree/bindings/spi/spi-bus.txt
+++ b/Documentation/devicetree/bindings/spi/spi-bus.txt
@@ -1,17 +1,20 @@
SPI (Serial Peripheral Interface) busses

-SPI busses can be described with a node for the SPI master device
-and a set of child nodes for each SPI slave on the bus. For this
-discussion, it is assumed that the system's SPI controller is in
-SPI master mode. This binding does not describe SPI controllers
-in slave mode.
+SPI busses can be described with a node for the SPI controller device
+and a set of child nodes for each SPI slave on the bus. The system's SPI
+controller can work either in master mode or in slave mode, based on the
+child node on it.

-The SPI master node requires the following properties:
+The SPI controller node requires the following properties:
+- compatible - name of SPI bus controller following generic names
+ recommended practice.
+
+In master mode, the SPI controller node requires the following additional
+properties:
- #address-cells - number of cells required to define a chip select
address on the SPI bus.
- #size-cells - should be zero.
-- compatible - name of SPI bus controller following generic names
- recommended practice.
+
No other properties are required in the SPI bus node. It is assumed
that a driver for an SPI bus device will understand that it is an SPI bus.
However, the binding does not attempt to define the specific method for
@@ -43,10 +46,11 @@ cs3 : &gpio1 2 0

SPI slave nodes must be children of the SPI master node and can
contain the following properties.
-- reg - (required) chip select address of device.
+- reg - (required, master mode only) chip select address of device.
- compatible - (required) name of SPI device following generic names
recommended practice.
-- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz.
+- spi-max-frequency - (required, master mode only) Maximum SPI clocking speed of
+ device in Hz.
- spi-cpol - (optional) Empty property indicating device requires
inverse clock polarity (CPOL) mode.
- spi-cpha - (optional) Empty property indicating device requires
@@ -63,6 +67,9 @@ contain the following properties.
used for MISO. Defaults to 1 if not present.
- spi-rx-delay-us - (optional) Microsecond delay after a read transfer.
- spi-tx-delay-us - (optional) Microsecond delay after a write transfer.
+- spi-slave - (optional) Empty property indicating SPI bus controller
+ itself works in slave mode to interface with external master
+ devices.

Some SPI controllers and devices support Dual and Quad SPI transfer mode.
It allows data in the SPI system to be transferred using 2 wires (DUAL) or 4
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index d1824b3..4c2ceaa 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -62,9 +62,8 @@ chips described as using "three wire" signaling: SCK, data, nCSx.
(That data line is sometimes called MOMI or SISO.)

Microcontrollers often support both master and slave sides of the SPI
-protocol. This document (and Linux) currently only supports the master
-side of SPI interactions.
-
+protocol. This document (and Linux) supports both the master and slave
+sides of SPI interactions.

Who uses it? On what kinds of systems?
---------------------------------------
@@ -154,9 +153,8 @@ control audio interfaces, present touchscreen sensors as input interfaces,
or monitor temperature and voltage levels during industrial processing.
And those might all be sharing the same controller driver.

-A "struct spi_device" encapsulates the master-side interface between
-those two types of driver. At this writing, Linux has no slave side
-programming interface.
+A "struct spi_device" encapsulates the controller-side interface between
+those two types of drivers.

There is a minimal core of SPI programming interfaces, focussing on
using the driver model to connect controller and protocol drivers using
@@ -168,12 +166,21 @@ shows up in sysfs in several locations:
/sys/devices/.../CTLR/spiB.C ... spi_device on bus "B",
chipselect C, accessed through CTLR.

+ /sys/devices/.../CTLR/spiB-slv ... SPI bus "B" controller itself as a
+ spi_device works in slave mode, accessed through CTRL.
+
/sys/bus/spi/devices/spiB.C ... symlink to that physical
.../CTLR/spiB.C device

+ /sys/bus/spi/devices/spiB-slv ... symlink to that physical
+ .../CTLR/spiB-slv device
+
/sys/devices/.../CTLR/spiB.C/modalias ... identifies the driver
that should be used with this device (for hotplug/coldplug)

+ /sys/devices/.../CTLR/spiB-slv/modalias ... identifies the driver
+ that should be used with this device (for hotplug/coldplug)
+
/sys/bus/spi/drivers/D ... driver for one or more spi*.* devices

/sys/class/spi_master/spiB ... symlink (or actual device node) to
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 25ae7f2e..1096c7d 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -784,6 +784,18 @@ config SPI_TLE62X0

endif # SPI_MASTER

-# (slave support would go here)
+#
+# SLAVE side ... listening to other SPI masters
+#
+
+config SPI_SLAVE
+ bool "SPI slave protocol handlers"
+ help
+ If your system has a slave-capable SPI controller, you can enable
+ slave protocol handlers.
+
+if SPI_SLAVE
+
+endif # SPI_SLAVE

endif # SPI
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 90b5b2e..3af26e2 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -475,6 +475,12 @@ static void spi_dev_set_name(struct spi_device *spi)
return;
}

+ if (spi->slave_mode) {
+ dev_set_name(&spi->dev, "%s-slv",
+ dev_name(&spi->master->dev));
+ return;
+ }
+
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
spi->chip_select);
}
@@ -484,6 +490,9 @@ static int spi_dev_check(struct device *dev, void *data)
struct spi_device *spi = to_spi_device(dev);
struct spi_device *new_spi = data;

+ if (spi->slave_mode)
+ return 0;
+
if (spi->master == new_spi->master &&
spi->chip_select == new_spi->chip_select)
return -EBUSY;
@@ -523,6 +532,9 @@ int spi_add_device(struct spi_device *spi)
*/
mutex_lock(&spi_add_lock);

+ if (spi->slave_mode)
+ goto setup_spi;
+
status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
if (status) {
dev_err(dev, "chipselect %d already in use\n",
@@ -533,6 +545,7 @@ int spi_add_device(struct spi_device *spi)
if (master->cs_gpios)
spi->cs_gpio = master->cs_gpios[spi->chip_select];

+setup_spi:
/* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
@@ -1511,6 +1524,14 @@ static int of_spi_parse_dt(struct spi_master *master, struct spi_device *spi,
u32 value;
int rc;

+ if (of_find_property(nc, "spi-slave", NULL)) {
+ if (!spi_controller_has_slavemode(master))
+ return -EINVAL;
+
+ spi->slave_mode = 1;
+ return 0;
+ }
+
/* Device address */
rc = of_property_read_u32(nc, "reg", &value);
if (rc) {
@@ -1961,7 +1982,7 @@ int spi_register_master(struct spi_master *master)
status = device_add(&master->dev);
if (status < 0)
goto done;
- dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
+ dev_dbg(dev, "registered controller %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : "");

/* If we're using a queued driver, start the queue */
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 75c6bd0..bb81425 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -115,6 +115,8 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
* This may be changed by the device's driver, or left at the
* default (0) indicating protocol words are eight bit bytes.
* The spi_transfer.bits_per_word can override this for each transfer.
+ * @slave_mode: indicates whether SPI controller works in master mode
+ * or slave mode to transfer data with external spi devices.
* @irq: Negative, or the number passed to request_irq() to receive
* interrupts from this device.
* @controller_state: Controller's runtime state
@@ -144,6 +146,7 @@ struct spi_device {
u8 chip_select;
u8 bits_per_word;
u16 mode;
+ u8 slave_mode;
#define SPI_CPHA 0x01 /* clock phase */
#define SPI_CPOL 0x02 /* clock polarity */
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
@@ -372,6 +375,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* transfer_one callback.
* @handle_err: the subsystem calls the driver to handle an error that occurs
* in the generic implementation of transfer_one_message().
+ * @has_slavemode: checks whether SPI Controller supports slave mode or not.
* @unprepare_message: undo any work done by prepare_message().
* @spi_flash_read: to support spi-controller hardwares that provide
* accelerated interface to read from flash devices.
@@ -549,6 +553,7 @@ struct spi_master {
struct spi_transfer *transfer);
void (*handle_err)(struct spi_master *master,
struct spi_message *message);
+ bool (*has_slavemode)(struct spi_master *master);

/* gpio chip select */
int *cs_gpios;
@@ -590,6 +595,16 @@ static inline void spi_master_put(struct spi_master *master)
put_device(&master->dev);
}

+
+static inline bool spi_controller_has_slavemode(struct spi_master *master)
+{
+#ifdef CONFIG_SPI_SLAVE
+ if (master->has_slavemode)
+ return master->has_slavemode(master);
+#endif
+ return false;
+}
+
/* PM calls that need to be issued by the driver */
extern int spi_master_suspend(struct spi_master *master);
extern int spi_master_resume(struct spi_master *master);
--
2.7.4