diff options
Diffstat (limited to 'drivers/spi/spi-fsl-espi.c')
-rw-r--r-- | drivers/spi/spi-fsl-espi.c | 45 |
1 files changed, 31 insertions, 14 deletions
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d0a73a09a9bd..80d245ac846f 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c | |||
@@ -359,14 +359,16 @@ static void fsl_espi_rw_trans(struct spi_message *m, | |||
359 | struct fsl_espi_transfer *trans, u8 *rx_buff) | 359 | struct fsl_espi_transfer *trans, u8 *rx_buff) |
360 | { | 360 | { |
361 | struct fsl_espi_transfer *espi_trans = trans; | 361 | struct fsl_espi_transfer *espi_trans = trans; |
362 | unsigned int n_tx = espi_trans->n_tx; | 362 | unsigned int total_len = espi_trans->len; |
363 | unsigned int n_rx = espi_trans->n_rx; | ||
364 | struct spi_transfer *t; | 363 | struct spi_transfer *t; |
365 | u8 *local_buf; | 364 | u8 *local_buf; |
366 | u8 *rx_buf = rx_buff; | 365 | u8 *rx_buf = rx_buff; |
367 | unsigned int trans_len; | 366 | unsigned int trans_len; |
368 | unsigned int addr; | 367 | unsigned int addr; |
369 | int i, pos, loop; | 368 | unsigned int tx_only; |
369 | unsigned int rx_pos = 0; | ||
370 | unsigned int pos; | ||
371 | int i, loop; | ||
370 | 372 | ||
371 | local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); | 373 | local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); |
372 | if (!local_buf) { | 374 | if (!local_buf) { |
@@ -374,36 +376,48 @@ static void fsl_espi_rw_trans(struct spi_message *m, | |||
374 | return; | 376 | return; |
375 | } | 377 | } |
376 | 378 | ||
377 | for (pos = 0, loop = 0; pos < n_rx; pos += trans_len, loop++) { | 379 | for (pos = 0, loop = 0; pos < total_len; pos += trans_len, loop++) { |
378 | trans_len = n_rx - pos; | 380 | trans_len = total_len - pos; |
379 | if (trans_len > SPCOM_TRANLEN_MAX - n_tx) | ||
380 | trans_len = SPCOM_TRANLEN_MAX - n_tx; | ||
381 | 381 | ||
382 | i = 0; | 382 | i = 0; |
383 | tx_only = 0; | ||
383 | list_for_each_entry(t, &m->transfers, transfer_list) { | 384 | list_for_each_entry(t, &m->transfers, transfer_list) { |
384 | if (t->tx_buf) { | 385 | if (t->tx_buf) { |
385 | memcpy(local_buf + i, t->tx_buf, t->len); | 386 | memcpy(local_buf + i, t->tx_buf, t->len); |
386 | i += t->len; | 387 | i += t->len; |
388 | if (!t->rx_buf) | ||
389 | tx_only += t->len; | ||
387 | } | 390 | } |
388 | } | 391 | } |
389 | 392 | ||
393 | /* Add additional TX bytes to compensate SPCOM_TRANLEN_MAX */ | ||
394 | if (loop > 0) | ||
395 | trans_len += tx_only; | ||
396 | |||
397 | if (trans_len > SPCOM_TRANLEN_MAX) | ||
398 | trans_len = SPCOM_TRANLEN_MAX; | ||
399 | |||
400 | /* Update device offset */ | ||
390 | if (pos > 0) { | 401 | if (pos > 0) { |
391 | addr = fsl_espi_cmd2addr(local_buf); | 402 | addr = fsl_espi_cmd2addr(local_buf); |
392 | addr += pos; | 403 | addr += rx_pos; |
393 | fsl_espi_addr2cmd(addr, local_buf); | 404 | fsl_espi_addr2cmd(addr, local_buf); |
394 | } | 405 | } |
395 | 406 | ||
396 | espi_trans->n_tx = n_tx; | 407 | espi_trans->len = trans_len; |
397 | espi_trans->n_rx = trans_len; | ||
398 | espi_trans->len = trans_len + n_tx; | ||
399 | espi_trans->tx_buf = local_buf; | 408 | espi_trans->tx_buf = local_buf; |
400 | espi_trans->rx_buf = local_buf; | 409 | espi_trans->rx_buf = local_buf; |
401 | fsl_espi_do_trans(m, espi_trans); | 410 | fsl_espi_do_trans(m, espi_trans); |
402 | 411 | ||
403 | memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len); | 412 | /* If there is at least one RX byte then copy it to rx_buf */ |
413 | if (tx_only < SPCOM_TRANLEN_MAX) | ||
414 | memcpy(rx_buf + rx_pos, espi_trans->rx_buf + tx_only, | ||
415 | trans_len - tx_only); | ||
416 | |||
417 | rx_pos += trans_len - tx_only; | ||
404 | 418 | ||
405 | if (loop > 0) | 419 | if (loop > 0) |
406 | espi_trans->actual_length += espi_trans->len - n_tx; | 420 | espi_trans->actual_length += espi_trans->len - tx_only; |
407 | else | 421 | else |
408 | espi_trans->actual_length += espi_trans->len; | 422 | espi_trans->actual_length += espi_trans->len; |
409 | } | 423 | } |
@@ -418,6 +432,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, | |||
418 | u8 *rx_buf = NULL; | 432 | u8 *rx_buf = NULL; |
419 | unsigned int n_tx = 0; | 433 | unsigned int n_tx = 0; |
420 | unsigned int n_rx = 0; | 434 | unsigned int n_rx = 0; |
435 | unsigned int xfer_len = 0; | ||
421 | struct fsl_espi_transfer espi_trans; | 436 | struct fsl_espi_transfer espi_trans; |
422 | 437 | ||
423 | list_for_each_entry(t, &m->transfers, transfer_list) { | 438 | list_for_each_entry(t, &m->transfers, transfer_list) { |
@@ -427,11 +442,13 @@ static int fsl_espi_do_one_msg(struct spi_master *master, | |||
427 | n_rx += t->len; | 442 | n_rx += t->len; |
428 | rx_buf = t->rx_buf; | 443 | rx_buf = t->rx_buf; |
429 | } | 444 | } |
445 | if ((t->tx_buf) || (t->rx_buf)) | ||
446 | xfer_len += t->len; | ||
430 | } | 447 | } |
431 | 448 | ||
432 | espi_trans.n_tx = n_tx; | 449 | espi_trans.n_tx = n_tx; |
433 | espi_trans.n_rx = n_rx; | 450 | espi_trans.n_rx = n_rx; |
434 | espi_trans.len = n_tx + n_rx; | 451 | espi_trans.len = xfer_len; |
435 | espi_trans.actual_length = 0; | 452 | espi_trans.actual_length = 0; |
436 | espi_trans.status = 0; | 453 | espi_trans.status = 0; |
437 | 454 | ||