Commit 01e73c89 authored by Rhyland Klein's avatar Rhyland Klein Committed by Lee Jones

mfd: cros ec: spi: Add delay for raising CS

The EC has specific timing it requires. Add support for an optional delay
after raising CS to fix timing issues. This is configurable based on
a DT property "google,cros-ec-spi-msg-delay".

If this property isn't set, then no delay will be added. However, if set
it will cause a delay equal to the value passed to it to be inserted at
the end of a transaction.
Signed-off-by: default avatarRhyland Klein <rklein@nvidia.com>
Reviewed-by: default avatarBernie Thompson <bhthompson@chromium.org>
Reviewed-by: default avatarAndrew Bresticker <abrestic@chromium.org>
Acked-by: default avatarMark Rutland <mark.rutland@arm.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
parent daf93d22
...@@ -17,6 +17,15 @@ Required properties (SPI): ...@@ -17,6 +17,15 @@ Required properties (SPI):
- compatible: "google,cros-ec-spi" - compatible: "google,cros-ec-spi"
- reg: SPI chip select - reg: SPI chip select
Optional properties (SPI):
- google,cros-ec-spi-msg-delay: Some implementations of the EC require some
additional processing time in order to accept new transactions. If the delay
between transactions is not long enough the EC may not be able to respond
properly to subsequent transactions and cause them to hang. This property
specifies the delay, in usecs, introduced between transactions to account
for the time required by the EC to get back into a state in which new data
can be accepted.
Required properties (LPC): Required properties (LPC):
- compatible: "google,cros-ec-lpc" - compatible: "google,cros-ec-lpc"
- reg: List of (IO address, size) pairs defining the interface uses - reg: List of (IO address, size) pairs defining the interface uses
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mfd/cros_ec.h> #include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h> #include <linux/mfd/cros_ec_commands.h>
#include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
...@@ -62,10 +63,13 @@ ...@@ -62,10 +63,13 @@
* @spi: SPI device we are connected to * @spi: SPI device we are connected to
* @last_transfer_ns: time that we last finished a transfer, or 0 if there * @last_transfer_ns: time that we last finished a transfer, or 0 if there
* if no record * 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 cros_ec_spi {
struct spi_device *spi; struct spi_device *spi;
s64 last_transfer_ns; s64 last_transfer_ns;
unsigned int end_of_msg_delay;
}; };
static void debug_packet(struct device *dev, const char *name, u8 *ptr, static void debug_packet(struct device *dev, const char *name, u8 *ptr,
...@@ -238,6 +242,17 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, ...@@ -238,6 +242,17 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
/* turn off CS */ /* turn off CS */
spi_message_init(&msg); 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); final_ret = spi_sync(ec_spi->spi, &msg);
ktime_get_ts(&ts); ktime_get_ts(&ts);
ec_spi->last_transfer_ns = timespec_to_ns(&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, ...@@ -284,6 +299,17 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
return 0; 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) static int cros_ec_spi_probe(struct spi_device *spi)
{ {
struct device *dev = &spi->dev; struct device *dev = &spi->dev;
...@@ -305,6 +331,9 @@ static int cros_ec_spi_probe(struct spi_device *spi) ...@@ -305,6 +331,9 @@ static int cros_ec_spi_probe(struct spi_device *spi)
if (!ec_dev) if (!ec_dev)
return -ENOMEM; return -ENOMEM;
/* Check for any DT properties */
cros_ec_spi_dt_probe(ec_spi, dev);
spi_set_drvdata(spi, ec_dev); spi_set_drvdata(spi, ec_dev);
ec_dev->name = "SPI"; ec_dev->name = "SPI";
ec_dev->dev = dev; ec_dev->dev = dev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment