diff options
author | Rhyland Klein <rklein@nvidia.com> | 2013-12-09 06:36:09 -0500 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2014-01-21 03:28:06 -0500 |
commit | 01e73c89cf03c020e586dc9e30d52a6e098853f6 (patch) | |
tree | daef78c50110f4fed3218742bf8c6560e3645639 /drivers/mfd | |
parent | daf93d2287ff8eb4a2f28224275fb02d623df2ab (diff) |
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: Rhyland Klein <rklein@nvidia.com>
Reviewed-by: Bernie Thompson <bhthompson@chromium.org>
Reviewed-by: Andrew Bresticker <abrestic@chromium.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/cros_ec_spi.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 005403643539..84af8d7a4295 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/mfd/cros_ec.h> | 19 | #include <linux/mfd/cros_ec.h> |
20 | #include <linux/mfd/cros_ec_commands.h> | 20 | #include <linux/mfd/cros_ec_commands.h> |
21 | #include <linux/of.h> | ||
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
23 | #include <linux/spi/spi.h> | 24 | #include <linux/spi/spi.h> |
@@ -62,10 +63,13 @@ | |||
62 | * @spi: SPI device we are connected to | 63 | * @spi: SPI device we are connected to |
63 | * @last_transfer_ns: time that we last finished a transfer, or 0 if there | 64 | * @last_transfer_ns: time that we last finished a transfer, or 0 if there |
64 | * if no record | 65 | * if no record |
66 | * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that | ||
67 | * is sent when we want to turn off CS at the end of a transaction. | ||
65 | */ | 68 | */ |
66 | struct cros_ec_spi { | 69 | struct cros_ec_spi { |
67 | struct spi_device *spi; | 70 | struct spi_device *spi; |
68 | s64 last_transfer_ns; | 71 | s64 last_transfer_ns; |
72 | unsigned int end_of_msg_delay; | ||
69 | }; | 73 | }; |
70 | 74 | ||
71 | static void debug_packet(struct device *dev, const char *name, u8 *ptr, | 75 | 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 | 242 | ||
239 | /* turn off CS */ | 243 | /* turn off CS */ |
240 | spi_message_init(&msg); | 244 | spi_message_init(&msg); |
245 | |||
246 | if (ec_spi->end_of_msg_delay) { | ||
247 | /* | ||
248 | * Add delay for last transaction, to ensure the rising edge | ||
249 | * doesn't come too soon after the end of the data. | ||
250 | */ | ||
251 | memset(&trans, 0, sizeof(trans)); | ||
252 | trans.delay_usecs = ec_spi->end_of_msg_delay; | ||
253 | spi_message_add_tail(&trans, &msg); | ||
254 | } | ||
255 | |||
241 | final_ret = spi_sync(ec_spi->spi, &msg); | 256 | final_ret = spi_sync(ec_spi->spi, &msg); |
242 | ktime_get_ts(&ts); | 257 | ktime_get_ts(&ts); |
243 | ec_spi->last_transfer_ns = timespec_to_ns(&ts); | 258 | 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 | return 0; | 299 | return 0; |
285 | } | 300 | } |
286 | 301 | ||
302 | static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev) | ||
303 | { | ||
304 | struct device_node *np = dev->of_node; | ||
305 | u32 val; | ||
306 | int ret; | ||
307 | |||
308 | ret = of_property_read_u32(np, "google,cros-ec-spi-msg-delay", &val); | ||
309 | if (!ret) | ||
310 | ec_spi->end_of_msg_delay = val; | ||
311 | } | ||
312 | |||
287 | static int cros_ec_spi_probe(struct spi_device *spi) | 313 | static int cros_ec_spi_probe(struct spi_device *spi) |
288 | { | 314 | { |
289 | struct device *dev = &spi->dev; | 315 | struct device *dev = &spi->dev; |
@@ -305,6 +331,9 @@ static int cros_ec_spi_probe(struct spi_device *spi) | |||
305 | if (!ec_dev) | 331 | if (!ec_dev) |
306 | return -ENOMEM; | 332 | return -ENOMEM; |
307 | 333 | ||
334 | /* Check for any DT properties */ | ||
335 | cros_ec_spi_dt_probe(ec_spi, dev); | ||
336 | |||
308 | spi_set_drvdata(spi, ec_dev); | 337 | spi_set_drvdata(spi, ec_dev); |
309 | ec_dev->name = "SPI"; | 338 | ec_dev->name = "SPI"; |
310 | ec_dev->dev = dev; | 339 | ec_dev->dev = dev; |