root/drivers/spi/spi-slave-system-control.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. spi_slave_system_control_complete
  2. spi_slave_system_control_submit
  3. spi_slave_system_control_probe
  4. spi_slave_system_control_remove

   1 /*
   2  * SPI slave handler controlling system state
   3  *
   4  * This SPI slave handler allows remote control of system reboot, power off,
   5  * halt, and suspend.
   6  *
   7  * Copyright (C) 2016-2017 Glider bvba
   8  *
   9  * This file is subject to the terms and conditions of the GNU General Public
  10  * License.  See the file "COPYING" in the main directory of this archive
  11  * for more details.
  12  *
  13  * Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote
  14  * system):
  15  *
  16  *   # reboot='\x7c\x50'
  17  *   # poweroff='\x71\x3f'
  18  *   # halt='\x38\x76'
  19  *   # suspend='\x1b\x1b'
  20  *   # spidev_test -D /dev/spidev2.0 -p $suspend # or $reboot, $poweroff, $halt
  21  */
  22 
  23 #include <linux/completion.h>
  24 #include <linux/module.h>
  25 #include <linux/reboot.h>
  26 #include <linux/suspend.h>
  27 #include <linux/spi/spi.h>
  28 
  29 /*
  30  * The numbers are chosen to display something human-readable on two 7-segment
  31  * displays connected to two 74HC595 shift registers
  32  */
  33 #define CMD_REBOOT      0x7c50  /* rb */
  34 #define CMD_POWEROFF    0x713f  /* OF */
  35 #define CMD_HALT        0x3876  /* HL */
  36 #define CMD_SUSPEND     0x1b1b  /* ZZ */
  37 
  38 struct spi_slave_system_control_priv {
  39         struct spi_device *spi;
  40         struct completion finished;
  41         struct spi_transfer xfer;
  42         struct spi_message msg;
  43         __be16 cmd;
  44 };
  45 
  46 static
  47 int spi_slave_system_control_submit(struct spi_slave_system_control_priv *priv);
  48 
  49 static void spi_slave_system_control_complete(void *arg)
  50 {
  51         struct spi_slave_system_control_priv *priv = arg;
  52         u16 cmd;
  53         int ret;
  54 
  55         if (priv->msg.status)
  56                 goto terminate;
  57 
  58         cmd = be16_to_cpu(priv->cmd);
  59         switch (cmd) {
  60         case CMD_REBOOT:
  61                 dev_info(&priv->spi->dev, "Rebooting system...\n");
  62                 kernel_restart(NULL);
  63                 break;
  64 
  65         case CMD_POWEROFF:
  66                 dev_info(&priv->spi->dev, "Powering off system...\n");
  67                 kernel_power_off();
  68                 break;
  69 
  70         case CMD_HALT:
  71                 dev_info(&priv->spi->dev, "Halting system...\n");
  72                 kernel_halt();
  73                 break;
  74 
  75         case CMD_SUSPEND:
  76                 dev_info(&priv->spi->dev, "Suspending system...\n");
  77                 pm_suspend(PM_SUSPEND_MEM);
  78                 break;
  79 
  80         default:
  81                 dev_warn(&priv->spi->dev, "Unknown command 0x%x\n", cmd);
  82                 break;
  83         }
  84 
  85         ret = spi_slave_system_control_submit(priv);
  86         if (ret)
  87                 goto terminate;
  88 
  89         return;
  90 
  91 terminate:
  92         dev_info(&priv->spi->dev, "Terminating\n");
  93         complete(&priv->finished);
  94 }
  95 
  96 static
  97 int spi_slave_system_control_submit(struct spi_slave_system_control_priv *priv)
  98 {
  99         int ret;
 100 
 101         spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
 102 
 103         priv->msg.complete = spi_slave_system_control_complete;
 104         priv->msg.context = priv;
 105 
 106         ret = spi_async(priv->spi, &priv->msg);
 107         if (ret)
 108                 dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret);
 109 
 110         return ret;
 111 }
 112 
 113 static int spi_slave_system_control_probe(struct spi_device *spi)
 114 {
 115         struct spi_slave_system_control_priv *priv;
 116         int ret;
 117 
 118         priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
 119         if (!priv)
 120                 return -ENOMEM;
 121 
 122         priv->spi = spi;
 123         init_completion(&priv->finished);
 124         priv->xfer.rx_buf = &priv->cmd;
 125         priv->xfer.len = sizeof(priv->cmd);
 126 
 127         ret = spi_slave_system_control_submit(priv);
 128         if (ret)
 129                 return ret;
 130 
 131         spi_set_drvdata(spi, priv);
 132         return 0;
 133 }
 134 
 135 static int spi_slave_system_control_remove(struct spi_device *spi)
 136 {
 137         struct spi_slave_system_control_priv *priv = spi_get_drvdata(spi);
 138 
 139         spi_slave_abort(spi);
 140         wait_for_completion(&priv->finished);
 141         return 0;
 142 }
 143 
 144 static struct spi_driver spi_slave_system_control_driver = {
 145         .driver = {
 146                 .name   = "spi-slave-system-control",
 147         },
 148         .probe          = spi_slave_system_control_probe,
 149         .remove         = spi_slave_system_control_remove,
 150 };
 151 module_spi_driver(spi_slave_system_control_driver);
 152 
 153 MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
 154 MODULE_DESCRIPTION("SPI slave handler controlling system state");
 155 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */