diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-04 12:01:07 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-04 12:01:07 -0700 |
commit | b39de277b02ffd8e3dccb01e9159bd45cb07b95d (patch) | |
tree | 0cfa6f87f308b0a17b3026dc09813a3eff888ae1 /drivers/spi/spi-slave-system-control.c | |
parent | d62eb5edf6643ede7e48b4d03ba972c0e8949acc (diff) | |
parent | 082f6968bb204d1a3d8b2da3c53d6b7a59bbd985 (diff) |
Merge tag 'spi-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"There's only one big change in this release but it's a very big
change: Geert Uytterhoeven has implemented support for SPI slave mode.
This feature has been on the cards since the subsystem was originally
merged back in the mists of time so it's great that Geert stepped up
and finally implemented it.
- SPI slave support, together with wholesale renaming of SPI
controllers from master to controller which went surprisingly
smoothly. This is already used with Renesas SoCs and support is in
the works for i.MX too.
- New drivers for Meson SPICC and ST STM32"
* tag 'spi-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (57 commits)
spi: loopback-test: Fix kfree() NULL pointer error.
spi: loopback-test: fix spelling mistake: "reruning" -> "rerunning"
spi: sirf: fix spelling mistake: "registerred" -> "registered"
spi: stm32: fix potential dereference null return value
spi: stm32: enhance DMA error management
spi: stm32: add runtime PM support
spi: stm32: use normal conditional statements instead of ternary operator
spi: stm32: replace st, spi-midi with st, spi-midi-ns to fit bindings
spi: stm32: fix example with st, spi-midi-ns property
spi: stm32: fix compatible to fit with new bindings
spi: stm32: use SoC specific compatible
spi: rockchip: Disable Runtime PM when chip select is asserted
spi: rockchip: Set GPIO_SS flag to enable Slave Select with GPIO CS
spi: atmel: fix corrupted data issue on SAM9 family SoCs
spi: stm32: fix error check on mbr being -ve
spi: add driver for STM32 SPI controller
spi: Document the STM32 SPI bindings
spi/bcm63xx: Fix checkpatch warnings
spi: imx: Check for allocation failure earlier
spi: mediatek: add spi support for mt2712 IC
...
Diffstat (limited to 'drivers/spi/spi-slave-system-control.c')
-rw-r--r-- | drivers/spi/spi-slave-system-control.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/drivers/spi/spi-slave-system-control.c b/drivers/spi/spi-slave-system-control.c new file mode 100644 index 000000000000..c0257e937995 --- /dev/null +++ b/drivers/spi/spi-slave-system-control.c @@ -0,0 +1,154 @@ +/* + * 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"); |