summaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-slave-time.c
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 /drivers/spi/spi-slave-time.c
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>
Diffstat (limited to 'drivers/spi/spi-slave-time.c')
-rw-r--r--drivers/spi/spi-slave-time.c129
1 files changed, 129 insertions, 0 deletions
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");