Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d540b0d authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'spi/topic/master' into spi-next

parents 096bf6b7 8caab75f
Loading
Loading
Loading
Loading
+45 −31
Original line number Diff line number Diff line
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 may be described for use in SPI master mode or in SPI slave mode,
but not for both at the same time.

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.

In slave mode, the SPI controller node requires one additional property:
- spi-slave       - Empty property.

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
@@ -21,7 +27,7 @@ assumption that board specific platform code will be used to manage
chip selects.  Individual drivers can define additional properties to
support describing the chip select layout.

Optional properties:
Optional properties (master mode only):
- cs-gpios	  - gpios chip select.
- num-cs	  - total number of chipselects.

@@ -41,28 +47,36 @@ cs1 : native
cs2 : &gpio1 1 0
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.
- compatible      - (required) name of SPI device following generic names
		recommended practice.
- spi-max-frequency - (required) 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
		shifted clock phase (CPHA) mode.
- spi-cs-high     - (optional) Empty property indicating device requires
		chip select active high.
- spi-3wire       - (optional) Empty property indicating device requires
		3-wire mode.
- spi-lsb-first   - (optional) Empty property indicating device requires
		LSB first mode.
- spi-tx-bus-width - (optional) The bus width (number of data wires) that is
                      used for MOSI. Defaults to 1 if not present.
- spi-rx-bus-width - (optional) The bus width (number of data wires) that is
                      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 nodes must be children of the SPI controller node.

In master mode, one or more slave nodes (up to the number of chip selects) can
be present.  Required properties are:
- compatible      - Name of SPI device following generic names recommended
		    practice.
- reg             - Chip select address of device.
- spi-max-frequency - Maximum SPI clocking speed of device in Hz.

In slave mode, the (single) slave node is optional.
If present, it must be called "slave".  Required properties are:
- compatible      - Name of SPI device following generic names recommended
		    practice.

All slave nodes can contain the following optional properties:
- spi-cpol        - Empty property indicating device requires inverse clock
		    polarity (CPOL) mode.
- spi-cpha        - Empty property indicating device requires shifted clock
		    phase (CPHA) mode.
- spi-cs-high     - Empty property indicating device requires chip select
		    active high.
- spi-3wire       - Empty property indicating device requires 3-wire mode.
- spi-lsb-first   - Empty property indicating device requires LSB first mode.
- spi-tx-bus-width - The bus width (number of data wires) that is used for MOSI.
		    Defaults to 1 if not present.
- spi-rx-bus-width - The bus width (number of data wires) that is used for MISO.
		    Defaults to 1 if not present.
- spi-rx-delay-us - Microsecond delay after a read transfer.
- spi-tx-delay-us - Microsecond delay after a write transfer.

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
+20 −7
Original line number Diff line number Diff line
@@ -62,8 +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 +154,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
@@ -177,10 +176,24 @@ shows up in sysfs in several locations:
   /sys/bus/spi/drivers/D ... driver for one or more spi*.* devices

   /sys/class/spi_master/spiB ... symlink (or actual device node) to
	a logical node which could hold class related state for the
	controller managing bus "B".  All spiB.* devices share one
	a logical node which could hold class related state for the SPI
	master controller managing bus "B".  All spiB.* devices share one
	physical SPI bus segment, with SCLK, MOSI, and MISO.

   /sys/devices/.../CTLR/slave ... virtual file for (un)registering the
	slave device for an SPI slave controller.
	Writing the driver name of an SPI slave handler to this file
	registers the slave device; writing "(null)" unregisters the slave
	device.
	Reading from this file shows the name of the slave device ("(null)"
	if not registered).

   /sys/class/spi_slave/spiB ... symlink (or actual device node) to
	a logical node which could hold class related state for the SPI
	slave controller on bus "B".  When registered, a single spiB.*
	device is present here, possible sharing the physical SPI bus
	segment with other SPI slave devices.

Note that the actual location of the controller's class state depends
on whether you enabled CONFIG_SYSFS_DEPRECATED or not.  At this time,
the only class-specific state is the bus number ("B" in "spiB"), so
+25 −1
Original line number Diff line number Diff line
@@ -785,6 +785,30 @@ 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

config SPI_SLAVE_TIME
	tristate "SPI slave handler reporting boot up time"
	help
	  SPI slave handler responding with the time of reception of the last
	  SPI message.

config SPI_SLAVE_SYSTEM_CONTROL
	tristate "SPI slave handler controlling system state"
	help
	  SPI slave handler to allow remote control of system reboot, power
	  off, halt, and suspend.

endif # SPI_SLAVE

endif # SPI
+4 −0
Original line number Diff line number Diff line
@@ -105,3 +105,7 @@ 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

# SPI slave protocol handlers
obj-$(CONFIG_SPI_SLAVE_TIME)		+= spi-slave-time.o
obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL)	+= spi-slave-system-control.o
+154 −0
Original line number Diff line number Diff line
/*
 * SPI slave handler controlling system state
 *
 * This SPI slave handler allows remote control of system reboot, power off,
 * halt, and suspend.
 *
 * Copyright (C) 2016-2017 Glider bvba
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote
 * system):
 *
 *   # reboot='\x7c\x50'
 *   # poweroff='\x71\x3f'
 *   # halt='\x38\x76'
 *   # suspend='\x1b\x1b'
 *   # spidev_test -D /dev/spidev2.0 -p $suspend # or $reboot, $poweroff, $halt
 */

#include <linux/completion.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/suspend.h>
#include <linux/spi/spi.h>

/*
 * The numbers are chosen to display something human-readable on two 7-segment
 * displays connected to two 74HC595 shift registers
 */
#define CMD_REBOOT	0x7c50	/* rb */
#define CMD_POWEROFF	0x713f	/* OF */
#define CMD_HALT	0x3876	/* HL */
#define CMD_SUSPEND	0x1b1b	/* ZZ */

struct spi_slave_system_control_priv {
	struct spi_device *spi;
	struct completion finished;
	struct spi_transfer xfer;
	struct spi_message msg;
	__be16 cmd;
};

static
int spi_slave_system_control_submit(struct spi_slave_system_control_priv *priv);

static void spi_slave_system_control_complete(void *arg)
{
	struct spi_slave_system_control_priv *priv = arg;
	u16 cmd;
	int ret;

	if (priv->msg.status)
		goto terminate;

	cmd = be16_to_cpu(priv->cmd);
	switch (cmd) {
	case CMD_REBOOT:
		dev_info(&priv->spi->dev, "Rebooting system...\n");
		kernel_restart(NULL);

	case CMD_POWEROFF:
		dev_info(&priv->spi->dev, "Powering off system...\n");
		kernel_power_off();
		break;

	case CMD_HALT:
		dev_info(&priv->spi->dev, "Halting system...\n");
		kernel_halt();
		break;

	case CMD_SUSPEND:
		dev_info(&priv->spi->dev, "Suspending system...\n");
		pm_suspend(PM_SUSPEND_MEM);
		break;

	default:
		dev_warn(&priv->spi->dev, "Unknown command 0x%x\n", cmd);
		break;
	}

	ret = spi_slave_system_control_submit(priv);
	if (ret)
		goto terminate;

	return;

terminate:
	dev_info(&priv->spi->dev, "Terminating\n");
	complete(&priv->finished);
}

static
int spi_slave_system_control_submit(struct spi_slave_system_control_priv *priv)
{
	int ret;

	spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);

	priv->msg.complete = spi_slave_system_control_complete;
	priv->msg.context = priv;

	ret = spi_async(priv->spi, &priv->msg);
	if (ret)
		dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret);

	return ret;
}

static int spi_slave_system_control_probe(struct spi_device *spi)
{
	struct spi_slave_system_control_priv *priv;
	int ret;

	priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->spi = spi;
	init_completion(&priv->finished);
	priv->xfer.rx_buf = &priv->cmd;
	priv->xfer.len = sizeof(priv->cmd);

	ret = spi_slave_system_control_submit(priv);
	if (ret)
		return ret;

	spi_set_drvdata(spi, priv);
	return 0;
}

static int spi_slave_system_control_remove(struct spi_device *spi)
{
	struct spi_slave_system_control_priv *priv = spi_get_drvdata(spi);

	spi_slave_abort(spi);
	wait_for_completion(&priv->finished);
	return 0;
}

static struct spi_driver spi_slave_system_control_driver = {
	.driver = {
		.name	= "spi-slave-system-control",
	},
	.probe		= spi_slave_system_control_probe,
	.remove		= spi_slave_system_control_remove,
};
module_spi_driver(spi_slave_system_control_driver);

MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
MODULE_DESCRIPTION("SPI slave handler controlling system state");
MODULE_LICENSE("GPL v2");
Loading