aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert+renesas@glider.be>2017-05-22 09:11:44 -0400
committerMark Brown <broonie@kernel.org>2017-05-26 08:12:04 -0400
commit29f9ffa0e1f9a17c866c04a01acfc9976d78f29a (patch)
tree93a0373ecab30962f97a0e42e274d38e3c2d1447
parentaa2ea9115bc3f0735aa65b833076cc5fe3da1489 (diff)
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>
-rw-r--r--drivers/spi/Kconfig6
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-slave-time.c129
3 files changed, 136 insertions, 0 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index df8ddec24b5d..ade542c5bfd8 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -796,6 +796,12 @@ config SPI_SLAVE
796 796
797if SPI_SLAVE 797if SPI_SLAVE
798 798
799config 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
799endif # SPI_SLAVE 805endif # SPI_SLAVE
800 806
801endif # SPI 807endif # SPI
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e50852c6fcb8..fb078693dbe4 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -107,3 +107,4 @@ obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
107obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o 107obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o
108 108
109# SPI slave protocol handlers 109# SPI slave protocol handlers
110obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o
diff --git a/drivers/spi/spi-slave-time.c b/drivers/spi/spi-slave-time.c
new file mode 100644
index 000000000000..f2e07a392d68
--- /dev/null
+++ b/drivers/spi/spi-slave-time.c
@@ -0,0 +1,129 @@
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
33struct 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
41static int spi_slave_time_submit(struct spi_slave_time_priv *priv);
42
43static 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
58terminate:
59 dev_info(&priv->spi->dev, "Terminating\n");
60 complete(&priv->finished);
61}
62
63static 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
87static 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
109static 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
118static 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};
125module_spi_driver(spi_slave_time_driver);
126
127MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
128MODULE_DESCRIPTION("SPI slave reporting uptime at previous SPI message");
129MODULE_LICENSE("GPL v2");