]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/mfd/cros_ec_spi.c
Merge tag 'for-linus-20140127' of git://git.infradead.org/linux-mtd
[karo-tx-linux.git] / drivers / mfd / cros_ec_spi.c
index d64d88a9e247a1bbac7ad3911fca430f936390d5..84af8d7a429544e7369daf66d2dbedb578cb12a1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/mfd/cros_ec.h>
 #include <linux/mfd/cros_ec_commands.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
  * @spi: SPI device we are connected to
  * @last_transfer_ns: time that we last finished a transfer, or 0 if there
  *     if no record
+ * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that
+ *      is sent when we want to turn off CS at the end of a transaction.
  */
 struct cros_ec_spi {
        struct spi_device *spi;
        s64 last_transfer_ns;
+       unsigned int end_of_msg_delay;
 };
 
 static void debug_packet(struct device *dev, const char *name, u8 *ptr,
@@ -108,7 +112,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
        /* Receive data until we see the header byte */
        deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
        do {
-               memset(&trans, '\0', sizeof(trans));
+               memset(&trans, 0, sizeof(trans));
                trans.cs_change = 1;
                trans.rx_buf = ptr = ec_dev->din;
                trans.len = EC_MSG_PREAMBLE_COUNT;
@@ -160,7 +164,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
                dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n",
                        todo, need_len, ptr - ec_dev->din);
 
-               memset(&trans, '\0', sizeof(trans));
+               memset(&trans, 0, sizeof(trans));
                trans.cs_change = 1;
                trans.rx_buf = ptr;
                trans.len = todo;
@@ -220,7 +224,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
 
        /* Transmit phase - send our message */
        debug_packet(ec_dev->dev, "out", ec_dev->dout, len);
-       memset(&trans, '\0', sizeof(trans));
+       memset(&trans, 0, sizeof(trans));
        trans.tx_buf = ec_dev->dout;
        trans.len = len;
        trans.cs_change = 1;
@@ -238,6 +242,17 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
 
        /* turn off CS */
        spi_message_init(&msg);
+
+       if (ec_spi->end_of_msg_delay) {
+               /*
+                * Add delay for last transaction, to ensure the rising edge
+                * doesn't come too soon after the end of the data.
+                */
+               memset(&trans, 0, sizeof(trans));
+               trans.delay_usecs = ec_spi->end_of_msg_delay;
+               spi_message_add_tail(&trans, &msg);
+       }
+
        final_ret = spi_sync(ec_spi->spi, &msg);
        ktime_get_ts(&ts);
        ec_spi->last_transfer_ns = timespec_to_ns(&ts);
@@ -284,6 +299,17 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
        return 0;
 }
 
+static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       u32 val;
+       int ret;
+
+       ret = of_property_read_u32(np, "google,cros-ec-spi-msg-delay", &val);
+       if (!ret)
+               ec_spi->end_of_msg_delay = val;
+}
+
 static int cros_ec_spi_probe(struct spi_device *spi)
 {
        struct device *dev = &spi->dev;
@@ -305,6 +331,9 @@ static int cros_ec_spi_probe(struct spi_device *spi)
        if (!ec_dev)
                return -ENOMEM;
 
+       /* Check for any DT properties */
+       cros_ec_spi_dt_probe(ec_spi, dev);
+
        spi_set_drvdata(spi, ec_dev);
        ec_dev->name = "SPI";
        ec_dev->dev = dev;