Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: slave: Add SPI slave handler reporting uptime at previous message

Add an example SPI slave handler responding with the uptime at the time
of reception of the last SPI message.

This can be used by an external microcontroller as a dead man's switch.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Geert Uytterhoeven and committed by
Mark Brown
29f9ffa0 aa2ea911

+136
+6
drivers/spi/Kconfig
··· 796 796 797 797 if SPI_SLAVE 798 798 799 + config SPI_SLAVE_TIME 800 + tristate "SPI slave handler reporting boot up time" 801 + help 802 + SPI slave handler responding with the time of reception of the last 803 + SPI message. 804 + 799 805 endif # SPI_SLAVE 800 806 801 807 endif # SPI
+1
drivers/spi/Makefile
··· 107 107 obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o 108 108 109 109 # SPI slave protocol handlers 110 + obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o
+129
drivers/spi/spi-slave-time.c
··· 1 + /* 2 + * SPI slave handler reporting uptime at reception of previous SPI message 3 + * 4 + * This SPI slave handler sends the time of reception of the last SPI message 5 + * as two 32-bit unsigned integers in binary format and in network byte order, 6 + * representing the number of seconds and fractional seconds (in microseconds) 7 + * since boot up. 8 + * 9 + * Copyright (C) 2016-2017 Glider bvba 10 + * 11 + * This file is subject to the terms and conditions of the GNU General Public 12 + * License. See the file "COPYING" in the main directory of this archive 13 + * for more details. 14 + * 15 + * Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote 16 + * system): 17 + * 18 + * # spidev_test -D /dev/spidev2.0 -p dummy-8B 19 + * spi mode: 0x0 20 + * bits per word: 8 21 + * max speed: 500000 Hz (500 KHz) 22 + * RX | 00 00 04 6D 00 09 5B BB ... 23 + * ^^^^^ ^^^^^^^^ 24 + * seconds microseconds 25 + */ 26 + 27 + #include <linux/completion.h> 28 + #include <linux/module.h> 29 + #include <linux/sched/clock.h> 30 + #include <linux/spi/spi.h> 31 + 32 + 33 + struct spi_slave_time_priv { 34 + struct spi_device *spi; 35 + struct completion finished; 36 + struct spi_transfer xfer; 37 + struct spi_message msg; 38 + __be32 buf[2]; 39 + }; 40 + 41 + static int spi_slave_time_submit(struct spi_slave_time_priv *priv); 42 + 43 + static void spi_slave_time_complete(void *arg) 44 + { 45 + struct spi_slave_time_priv *priv = arg; 46 + int ret; 47 + 48 + ret = priv->msg.status; 49 + if (ret) 50 + goto terminate; 51 + 52 + ret = spi_slave_time_submit(priv); 53 + if (ret) 54 + goto terminate; 55 + 56 + return; 57 + 58 + terminate: 59 + dev_info(&priv->spi->dev, "Terminating\n"); 60 + complete(&priv->finished); 61 + } 62 + 63 + static int spi_slave_time_submit(struct spi_slave_time_priv *priv) 64 + { 65 + u32 rem_us; 66 + int ret; 67 + u64 ts; 68 + 69 + ts = local_clock(); 70 + rem_us = do_div(ts, 1000000000) / 1000; 71 + 72 + priv->buf[0] = cpu_to_be32(ts); 73 + priv->buf[1] = cpu_to_be32(rem_us); 74 + 75 + spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1); 76 + 77 + priv->msg.complete = spi_slave_time_complete; 78 + priv->msg.context = priv; 79 + 80 + ret = spi_async(priv->spi, &priv->msg); 81 + if (ret) 82 + dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret); 83 + 84 + return ret; 85 + } 86 + 87 + static int spi_slave_time_probe(struct spi_device *spi) 88 + { 89 + struct spi_slave_time_priv *priv; 90 + int ret; 91 + 92 + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); 93 + if (!priv) 94 + return -ENOMEM; 95 + 96 + priv->spi = spi; 97 + init_completion(&priv->finished); 98 + priv->xfer.tx_buf = priv->buf; 99 + priv->xfer.len = sizeof(priv->buf); 100 + 101 + ret = spi_slave_time_submit(priv); 102 + if (ret) 103 + return ret; 104 + 105 + spi_set_drvdata(spi, priv); 106 + return 0; 107 + } 108 + 109 + static int spi_slave_time_remove(struct spi_device *spi) 110 + { 111 + struct spi_slave_time_priv *priv = spi_get_drvdata(spi); 112 + 113 + spi_slave_abort(spi); 114 + wait_for_completion(&priv->finished); 115 + return 0; 116 + } 117 + 118 + static struct spi_driver spi_slave_time_driver = { 119 + .driver = { 120 + .name = "spi-slave-time", 121 + }, 122 + .probe = spi_slave_time_probe, 123 + .remove = spi_slave_time_remove, 124 + }; 125 + module_spi_driver(spi_slave_time_driver); 126 + 127 + MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>"); 128 + MODULE_DESCRIPTION("SPI slave reporting uptime at previous SPI message"); 129 + MODULE_LICENSE("GPL v2");