Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * SPI slave handler reporting uptime at reception of previous SPI message
0003  *
0004  * This SPI slave handler sends the time of reception of the last SPI message
0005  * as two 32-bit unsigned integers in binary format and in network byte order,
0006  * representing the number of seconds and fractional seconds (in microseconds)
0007  * since boot up.
0008  *
0009  * Copyright (C) 2016-2017 Glider bvba
0010  *
0011  * This file is subject to the terms and conditions of the GNU General Public
0012  * License.  See the file "COPYING" in the main directory of this archive
0013  * for more details.
0014  *
0015  * Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote
0016  * system):
0017  *
0018  *   # spidev_test -D /dev/spidev2.0 -p dummy-8B
0019  *   spi mode: 0x0
0020  *   bits per word: 8
0021  *   max speed: 500000 Hz (500 KHz)
0022  *   RX | 00 00 04 6D 00 09 5B BB ...
0023  *      ^^^^^    ^^^^^^^^
0024  *      seconds  microseconds
0025  */
0026 
0027 #include <linux/completion.h>
0028 #include <linux/module.h>
0029 #include <linux/sched/clock.h>
0030 #include <linux/spi/spi.h>
0031 
0032 
0033 struct spi_slave_time_priv {
0034     struct spi_device *spi;
0035     struct completion finished;
0036     struct spi_transfer xfer;
0037     struct spi_message msg;
0038     __be32 buf[2];
0039 };
0040 
0041 static int spi_slave_time_submit(struct spi_slave_time_priv *priv);
0042 
0043 static void spi_slave_time_complete(void *arg)
0044 {
0045     struct spi_slave_time_priv *priv = arg;
0046     int ret;
0047 
0048     ret = priv->msg.status;
0049     if (ret)
0050         goto terminate;
0051 
0052     ret = spi_slave_time_submit(priv);
0053     if (ret)
0054         goto terminate;
0055 
0056     return;
0057 
0058 terminate:
0059     dev_info(&priv->spi->dev, "Terminating\n");
0060     complete(&priv->finished);
0061 }
0062 
0063 static int spi_slave_time_submit(struct spi_slave_time_priv *priv)
0064 {
0065     u32 rem_us;
0066     int ret;
0067     u64 ts;
0068 
0069     ts = local_clock();
0070     rem_us = do_div(ts, 1000000000) / 1000;
0071 
0072     priv->buf[0] = cpu_to_be32(ts);
0073     priv->buf[1] = cpu_to_be32(rem_us);
0074 
0075     spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
0076 
0077     priv->msg.complete = spi_slave_time_complete;
0078     priv->msg.context = priv;
0079 
0080     ret = spi_async(priv->spi, &priv->msg);
0081     if (ret)
0082         dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret);
0083 
0084     return ret;
0085 }
0086 
0087 static int spi_slave_time_probe(struct spi_device *spi)
0088 {
0089     struct spi_slave_time_priv *priv;
0090     int ret;
0091 
0092     priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
0093     if (!priv)
0094         return -ENOMEM;
0095 
0096     priv->spi = spi;
0097     init_completion(&priv->finished);
0098     priv->xfer.tx_buf = priv->buf;
0099     priv->xfer.len = sizeof(priv->buf);
0100 
0101     ret = spi_slave_time_submit(priv);
0102     if (ret)
0103         return ret;
0104 
0105     spi_set_drvdata(spi, priv);
0106     return 0;
0107 }
0108 
0109 static void spi_slave_time_remove(struct spi_device *spi)
0110 {
0111     struct spi_slave_time_priv *priv = spi_get_drvdata(spi);
0112 
0113     spi_slave_abort(spi);
0114     wait_for_completion(&priv->finished);
0115 }
0116 
0117 static struct spi_driver spi_slave_time_driver = {
0118     .driver = {
0119         .name   = "spi-slave-time",
0120     },
0121     .probe      = spi_slave_time_probe,
0122     .remove     = spi_slave_time_remove,
0123 };
0124 module_spi_driver(spi_slave_time_driver);
0125 
0126 MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
0127 MODULE_DESCRIPTION("SPI slave reporting uptime at previous SPI message");
0128 MODULE_LICENSE("GPL v2");