aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorDoug Anderson <dianders@chromium.org>2014-04-30 13:44:05 -0400
committerLee Jones <lee.jones@linaro.org>2014-06-03 03:11:46 -0400
commit362196e5d0832ce3c4e1df376c02cff812a2391b (patch)
tree3ef8f401d423fe0011e1bdfe573fea914feded82 /drivers/mfd
parent1fe368665b1499041919d78467147849989af7c9 (diff)
mfd: cros_ec: spi: Add mutex to cros_ec_spi
The main transfer function for cros_ec_spi can be called by more than one client at a time. Make sure that those clients don't stomp on each other by locking the bus for the duration of the transfer function. Signed-off-by: Doug Anderson <dianders@chromium.org> Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Andrew Bresticker <abrestic@chromium.org> Tested-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/cros_ec_spi.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c
index c185eb67943f..a2a605de79a7 100644
--- a/drivers/mfd/cros_ec_spi.c
+++ b/drivers/mfd/cros_ec_spi.c
@@ -65,11 +65,13 @@
65 * if no record 65 * if no record
66 * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that 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. 67 * is sent when we want to turn off CS at the end of a transaction.
68 * @lock: mutex to ensure only one user of cros_ec_command_spi_xfer at a time
68 */ 69 */
69struct cros_ec_spi { 70struct cros_ec_spi {
70 struct spi_device *spi; 71 struct spi_device *spi;
71 s64 last_transfer_ns; 72 s64 last_transfer_ns;
72 unsigned int end_of_msg_delay; 73 unsigned int end_of_msg_delay;
74 struct mutex lock;
73}; 75};
74 76
75static void debug_packet(struct device *dev, const char *name, u8 *ptr, 77static void debug_packet(struct device *dev, const char *name, u8 *ptr,
@@ -208,6 +210,13 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
208 int ret = 0, final_ret; 210 int ret = 0, final_ret;
209 struct timespec ts; 211 struct timespec ts;
210 212
213 /*
214 * We have the shared ec_dev buffer plus we do lots of separate spi_sync
215 * calls, so we need to make sure only one person is using this at a
216 * time.
217 */
218 mutex_lock(&ec_spi->lock);
219
211 len = cros_ec_prepare_tx(ec_dev, ec_msg); 220 len = cros_ec_prepare_tx(ec_dev, ec_msg);
212 dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); 221 dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
213 222
@@ -260,7 +269,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
260 ret = final_ret; 269 ret = final_ret;
261 if (ret < 0) { 270 if (ret < 0) {
262 dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); 271 dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
263 return ret; 272 goto exit;
264 } 273 }
265 274
266 /* check response error code */ 275 /* check response error code */
@@ -269,14 +278,16 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
269 dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", 278 dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n",
270 ec_msg->cmd, ptr[0]); 279 ec_msg->cmd, ptr[0]);
271 debug_packet(ec_dev->dev, "in_err", ptr, len); 280 debug_packet(ec_dev->dev, "in_err", ptr, len);
272 return -EINVAL; 281 ret = -EINVAL;
282 goto exit;
273 } 283 }
274 len = ptr[1]; 284 len = ptr[1];
275 sum = ptr[0] + ptr[1]; 285 sum = ptr[0] + ptr[1];
276 if (len > ec_msg->in_len) { 286 if (len > ec_msg->in_len) {
277 dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", 287 dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)",
278 len, ec_msg->in_len); 288 len, ec_msg->in_len);
279 return -ENOSPC; 289 ret = -ENOSPC;
290 goto exit;
280 } 291 }
281 292
282 /* copy response packet payload and compute checksum */ 293 /* copy response packet payload and compute checksum */
@@ -293,10 +304,14 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
293 dev_err(ec_dev->dev, 304 dev_err(ec_dev->dev,
294 "bad packet checksum, expected %02x, got %02x\n", 305 "bad packet checksum, expected %02x, got %02x\n",
295 sum, ptr[len + 2]); 306 sum, ptr[len + 2]);
296 return -EBADMSG; 307 ret = -EBADMSG;
308 goto exit;
297 } 309 }
298 310
299 return 0; 311 ret = 0;
312exit:
313 mutex_unlock(&ec_spi->lock);
314 return ret;
300} 315}
301 316
302static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev) 317static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev)
@@ -327,6 +342,7 @@ static int cros_ec_spi_probe(struct spi_device *spi)
327 if (ec_spi == NULL) 342 if (ec_spi == NULL)
328 return -ENOMEM; 343 return -ENOMEM;
329 ec_spi->spi = spi; 344 ec_spi->spi = spi;
345 mutex_init(&ec_spi->lock);
330 ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); 346 ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
331 if (!ec_dev) 347 if (!ec_dev)
332 return -ENOMEM; 348 return -ENOMEM;