brintos

brintos / linux-shallow public Read only

0
0
Text · 2.9 KiB · 8bb3070 Raw
129 lines · c
1/*2 * SPI slave handler reporting uptime at reception of previous SPI message3 *4 * This SPI slave handler sends the time of reception of the last SPI message5 * 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 bvba10 *11 * This file is subject to the terms and conditions of the GNU General Public12 * License.  See the file "COPYING" in the main directory of this archive13 * for more details.14 *15 * Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote16 * system):17 *18 *   # spidev_test -D /dev/spidev2.0 -p dummy-8B19 *   spi mode: 0x020 *   bits per word: 821 *   max speed: 500000 Hz (500 KHz)22 *   RX | 00 00 04 6D 00 09 5B BB ...23 *		^^^^^    ^^^^^^^^24 *		seconds  microseconds25 */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");129