Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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 void spi_slave_time_remove(struct spi_device *spi)
110{
111	struct spi_slave_time_priv *priv = spi_get_drvdata(spi);
112
113	spi_target_abort(spi);
114	wait_for_completion(&priv->finished);
115}
116
117static struct spi_driver spi_slave_time_driver = {
118	.driver = {
119		.name	= "spi-slave-time",
120	},
121	.probe		= spi_slave_time_probe,
122	.remove		= spi_slave_time_remove,
123};
124module_spi_driver(spi_slave_time_driver);
125
126MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
127MODULE_DESCRIPTION("SPI slave reporting uptime at previous SPI message");
128MODULE_LICENSE("GPL v2");