diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/ieee802154/at86rf230.c | 157 |
1 files changed, 77 insertions, 80 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 5dbec64eb786..7a1a8e39b130 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c | |||
| @@ -74,6 +74,8 @@ struct at86rf230_state_change { | |||
| 74 | void (*complete)(void *context); | 74 | void (*complete)(void *context); |
| 75 | u8 from_state; | 75 | u8 from_state; |
| 76 | u8 to_state; | 76 | u8 to_state; |
| 77 | |||
| 78 | bool irq_enable; | ||
| 77 | }; | 79 | }; |
| 78 | 80 | ||
| 79 | struct at86rf230_local { | 81 | struct at86rf230_local { |
| @@ -292,10 +294,11 @@ struct at86rf230_local { | |||
| 292 | 294 | ||
| 293 | #define AT86RF2XX_NUMREGS 0x3F | 295 | #define AT86RF2XX_NUMREGS 0x3F |
| 294 | 296 | ||
| 295 | static int | 297 | static void |
| 296 | at86rf230_async_state_change(struct at86rf230_local *lp, | 298 | at86rf230_async_state_change(struct at86rf230_local *lp, |
| 297 | struct at86rf230_state_change *ctx, | 299 | struct at86rf230_state_change *ctx, |
| 298 | const u8 state, void (*complete)(void *context)); | 300 | const u8 state, void (*complete)(void *context), |
| 301 | const bool irq_enable); | ||
| 299 | 302 | ||
| 300 | static inline int | 303 | static inline int |
| 301 | __at86rf230_write(struct at86rf230_local *lp, | 304 | __at86rf230_write(struct at86rf230_local *lp, |
| @@ -452,7 +455,7 @@ at86rf230_async_error_recover(void *context) | |||
| 452 | struct at86rf230_state_change *ctx = context; | 455 | struct at86rf230_state_change *ctx = context; |
| 453 | struct at86rf230_local *lp = ctx->lp; | 456 | struct at86rf230_local *lp = ctx->lp; |
| 454 | 457 | ||
| 455 | at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL); | 458 | at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL, false); |
| 456 | } | 459 | } |
| 457 | 460 | ||
| 458 | static void | 461 | static void |
| @@ -462,21 +465,31 @@ at86rf230_async_error(struct at86rf230_local *lp, | |||
| 462 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | 465 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); |
| 463 | 466 | ||
| 464 | at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, | 467 | at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, |
| 465 | at86rf230_async_error_recover); | 468 | at86rf230_async_error_recover, false); |
| 466 | } | 469 | } |
| 467 | 470 | ||
| 468 | /* Generic function to get some register value in async mode */ | 471 | /* Generic function to get some register value in async mode */ |
| 469 | static int | 472 | static void |
| 470 | at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, | 473 | at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, |
| 471 | struct at86rf230_state_change *ctx, | 474 | struct at86rf230_state_change *ctx, |
| 472 | void (*complete)(void *context)) | 475 | void (*complete)(void *context), |
| 476 | const bool irq_enable) | ||
| 473 | { | 477 | { |
| 478 | int rc; | ||
| 479 | |||
| 474 | u8 *tx_buf = ctx->buf; | 480 | u8 *tx_buf = ctx->buf; |
| 475 | 481 | ||
| 476 | tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; | 482 | tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; |
| 477 | ctx->trx.len = 2; | 483 | ctx->trx.len = 2; |
| 478 | ctx->msg.complete = complete; | 484 | ctx->msg.complete = complete; |
| 479 | return spi_async(lp->spi, &ctx->msg); | 485 | ctx->irq_enable = irq_enable; |
| 486 | rc = spi_async(lp->spi, &ctx->msg); | ||
| 487 | if (rc) { | ||
| 488 | if (irq_enable) | ||
| 489 | enable_irq(lp->spi->irq); | ||
| 490 | |||
| 491 | at86rf230_async_error(lp, ctx, rc); | ||
| 492 | } | ||
| 480 | } | 493 | } |
| 481 | 494 | ||
| 482 | static void | 495 | static void |
| @@ -513,7 +526,8 @@ at86rf230_async_state_assert(void *context) | |||
| 513 | if (ctx->to_state == STATE_TX_ON) { | 526 | if (ctx->to_state == STATE_TX_ON) { |
| 514 | at86rf230_async_state_change(lp, ctx, | 527 | at86rf230_async_state_change(lp, ctx, |
| 515 | STATE_FORCE_TX_ON, | 528 | STATE_FORCE_TX_ON, |
| 516 | ctx->complete); | 529 | ctx->complete, |
| 530 | ctx->irq_enable); | ||
| 517 | return; | 531 | return; |
| 518 | } | 532 | } |
| 519 | } | 533 | } |
| @@ -536,7 +550,6 @@ at86rf230_async_state_delay(void *context) | |||
| 536 | struct at86rf230_local *lp = ctx->lp; | 550 | struct at86rf230_local *lp = ctx->lp; |
| 537 | struct at86rf2xx_chip_data *c = lp->data; | 551 | struct at86rf2xx_chip_data *c = lp->data; |
| 538 | bool force = false; | 552 | bool force = false; |
| 539 | int rc; | ||
| 540 | 553 | ||
| 541 | /* The force state changes are will show as normal states in the | 554 | /* The force state changes are will show as normal states in the |
| 542 | * state status subregister. We change the to_state to the | 555 | * state status subregister. We change the to_state to the |
| @@ -605,10 +618,9 @@ at86rf230_async_state_delay(void *context) | |||
| 605 | udelay(1); | 618 | udelay(1); |
| 606 | 619 | ||
| 607 | change: | 620 | change: |
| 608 | rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, | 621 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, |
| 609 | at86rf230_async_state_assert); | 622 | at86rf230_async_state_assert, |
| 610 | if (rc) | 623 | ctx->irq_enable); |
| 611 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | ||
| 612 | } | 624 | } |
| 613 | 625 | ||
| 614 | static void | 626 | static void |
| @@ -623,10 +635,9 @@ at86rf230_async_state_change_start(void *context) | |||
| 623 | /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ | 635 | /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ |
| 624 | if (trx_state == STATE_TRANSITION_IN_PROGRESS) { | 636 | if (trx_state == STATE_TRANSITION_IN_PROGRESS) { |
| 625 | udelay(1); | 637 | udelay(1); |
| 626 | rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, | 638 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, |
| 627 | at86rf230_async_state_change_start); | 639 | at86rf230_async_state_change_start, |
| 628 | if (rc) | 640 | ctx->irq_enable); |
| 629 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | ||
| 630 | return; | 641 | return; |
| 631 | } | 642 | } |
| 632 | 643 | ||
| @@ -648,20 +659,28 @@ at86rf230_async_state_change_start(void *context) | |||
| 648 | ctx->trx.len = 2; | 659 | ctx->trx.len = 2; |
| 649 | ctx->msg.complete = at86rf230_async_state_delay; | 660 | ctx->msg.complete = at86rf230_async_state_delay; |
| 650 | rc = spi_async(lp->spi, &ctx->msg); | 661 | rc = spi_async(lp->spi, &ctx->msg); |
| 651 | if (rc) | 662 | if (rc) { |
| 663 | if (ctx->irq_enable) | ||
| 664 | enable_irq(lp->spi->irq); | ||
| 665 | |||
| 666 | at86rf230_async_error(lp, &lp->state, rc); | ||
| 652 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | 667 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); |
| 668 | } | ||
| 653 | } | 669 | } |
| 654 | 670 | ||
| 655 | static int | 671 | static void |
| 656 | at86rf230_async_state_change(struct at86rf230_local *lp, | 672 | at86rf230_async_state_change(struct at86rf230_local *lp, |
| 657 | struct at86rf230_state_change *ctx, | 673 | struct at86rf230_state_change *ctx, |
| 658 | const u8 state, void (*complete)(void *context)) | 674 | const u8 state, void (*complete)(void *context), |
| 675 | const bool irq_enable) | ||
| 659 | { | 676 | { |
| 660 | /* Initialization for the state change context */ | 677 | /* Initialization for the state change context */ |
| 661 | ctx->to_state = state; | 678 | ctx->to_state = state; |
| 662 | ctx->complete = complete; | 679 | ctx->complete = complete; |
| 663 | return at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, | 680 | ctx->irq_enable = irq_enable; |
| 664 | at86rf230_async_state_change_start); | 681 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, |
| 682 | at86rf230_async_state_change_start, | ||
| 683 | irq_enable); | ||
| 665 | } | 684 | } |
| 666 | 685 | ||
| 667 | static void | 686 | static void |
| @@ -682,12 +701,9 @@ at86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state) | |||
| 682 | { | 701 | { |
| 683 | int rc; | 702 | int rc; |
| 684 | 703 | ||
| 685 | rc = at86rf230_async_state_change(lp, &lp->state, state, | 704 | at86rf230_async_state_change(lp, &lp->state, state, |
| 686 | at86rf230_sync_state_change_complete); | 705 | at86rf230_sync_state_change_complete, |
| 687 | if (rc) { | 706 | false); |
| 688 | at86rf230_async_error(lp, &lp->state, rc); | ||
| 689 | return rc; | ||
| 690 | } | ||
| 691 | 707 | ||
| 692 | rc = wait_for_completion_timeout(&lp->state_complete, | 708 | rc = wait_for_completion_timeout(&lp->state_complete, |
| 693 | msecs_to_jiffies(100)); | 709 | msecs_to_jiffies(100)); |
| @@ -714,12 +730,9 @@ at86rf230_tx_on(void *context) | |||
| 714 | { | 730 | { |
| 715 | struct at86rf230_state_change *ctx = context; | 731 | struct at86rf230_state_change *ctx = context; |
| 716 | struct at86rf230_local *lp = ctx->lp; | 732 | struct at86rf230_local *lp = ctx->lp; |
| 717 | int rc; | ||
| 718 | 733 | ||
| 719 | rc = at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON, | 734 | at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON, |
| 720 | at86rf230_tx_complete); | 735 | at86rf230_tx_complete, true); |
| 721 | if (rc) | ||
| 722 | at86rf230_async_error(lp, ctx, rc); | ||
| 723 | } | 736 | } |
| 724 | 737 | ||
| 725 | static void | 738 | static void |
| @@ -727,12 +740,9 @@ at86rf230_tx_trac_error(void *context) | |||
| 727 | { | 740 | { |
| 728 | struct at86rf230_state_change *ctx = context; | 741 | struct at86rf230_state_change *ctx = context; |
| 729 | struct at86rf230_local *lp = ctx->lp; | 742 | struct at86rf230_local *lp = ctx->lp; |
| 730 | int rc; | ||
| 731 | 743 | ||
| 732 | rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON, | 744 | at86rf230_async_state_change(lp, ctx, STATE_TX_ON, |
| 733 | at86rf230_tx_on); | 745 | at86rf230_tx_on, true); |
| 734 | if (rc) | ||
| 735 | at86rf230_async_error(lp, ctx, rc); | ||
| 736 | } | 746 | } |
| 737 | 747 | ||
| 738 | static void | 748 | static void |
| @@ -742,17 +752,14 @@ at86rf230_tx_trac_check(void *context) | |||
| 742 | struct at86rf230_local *lp = ctx->lp; | 752 | struct at86rf230_local *lp = ctx->lp; |
| 743 | const u8 *buf = ctx->buf; | 753 | const u8 *buf = ctx->buf; |
| 744 | const u8 trac = (buf[1] & 0xe0) >> 5; | 754 | const u8 trac = (buf[1] & 0xe0) >> 5; |
| 745 | int rc; | ||
| 746 | 755 | ||
| 747 | /* If trac status is different than zero we need to do a state change | 756 | /* If trac status is different than zero we need to do a state change |
| 748 | * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver | 757 | * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver |
| 749 | * state to TX_ON. | 758 | * state to TX_ON. |
| 750 | */ | 759 | */ |
| 751 | if (trac) { | 760 | if (trac) { |
| 752 | rc = at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, | 761 | at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, |
| 753 | at86rf230_tx_trac_error); | 762 | at86rf230_tx_trac_error, true); |
| 754 | if (rc) | ||
| 755 | at86rf230_async_error(lp, ctx, rc); | ||
| 756 | return; | 763 | return; |
| 757 | } | 764 | } |
| 758 | 765 | ||
| @@ -765,12 +772,9 @@ at86rf230_tx_trac_status(void *context) | |||
| 765 | { | 772 | { |
| 766 | struct at86rf230_state_change *ctx = context; | 773 | struct at86rf230_state_change *ctx = context; |
| 767 | struct at86rf230_local *lp = ctx->lp; | 774 | struct at86rf230_local *lp = ctx->lp; |
| 768 | int rc; | ||
| 769 | 775 | ||
| 770 | rc = at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx, | 776 | at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx, |
| 771 | at86rf230_tx_trac_check); | 777 | at86rf230_tx_trac_check, true); |
| 772 | if (rc) | ||
| 773 | at86rf230_async_error(lp, ctx, rc); | ||
| 774 | } | 778 | } |
| 775 | 779 | ||
| 776 | static void | 780 | static void |
| @@ -823,15 +827,21 @@ at86rf230_rx_read_frame_complete(void *context) | |||
| 823 | at86rf230_rx(lp, buf + 2, len); | 827 | at86rf230_rx(lp, buf + 2, len); |
| 824 | } | 828 | } |
| 825 | 829 | ||
| 826 | static int | 830 | static void |
| 827 | at86rf230_rx_read_frame(struct at86rf230_local *lp) | 831 | at86rf230_rx_read_frame(struct at86rf230_local *lp) |
| 828 | { | 832 | { |
| 833 | int rc; | ||
| 834 | |||
| 829 | u8 *buf = lp->irq.buf; | 835 | u8 *buf = lp->irq.buf; |
| 830 | 836 | ||
| 831 | buf[0] = CMD_FB; | 837 | buf[0] = CMD_FB; |
| 832 | lp->irq.trx.len = AT86RF2XX_MAX_BUF; | 838 | lp->irq.trx.len = AT86RF2XX_MAX_BUF; |
| 833 | lp->irq.msg.complete = at86rf230_rx_read_frame_complete; | 839 | lp->irq.msg.complete = at86rf230_rx_read_frame_complete; |
| 834 | return spi_async(lp->spi, &lp->irq.msg); | 840 | rc = spi_async(lp->spi, &lp->irq.msg); |
| 841 | if (rc) { | ||
| 842 | enable_irq(lp->spi->irq); | ||
| 843 | at86rf230_async_error(lp, &lp->irq, rc); | ||
| 844 | } | ||
| 835 | } | 845 | } |
| 836 | 846 | ||
| 837 | static void | 847 | static void |
| @@ -839,7 +849,6 @@ at86rf230_rx_trac_check(void *context) | |||
| 839 | { | 849 | { |
| 840 | struct at86rf230_state_change *ctx = context; | 850 | struct at86rf230_state_change *ctx = context; |
| 841 | struct at86rf230_local *lp = ctx->lp; | 851 | struct at86rf230_local *lp = ctx->lp; |
| 842 | int rc; | ||
| 843 | 852 | ||
| 844 | /* Possible check on trac status here. This could be useful to make | 853 | /* Possible check on trac status here. This could be useful to make |
| 845 | * some stats why receive is failed. Not used at the moment, but it's | 854 | * some stats why receive is failed. Not used at the moment, but it's |
| @@ -847,14 +856,10 @@ at86rf230_rx_trac_check(void *context) | |||
| 847 | * The programming guide say do it so. | 856 | * The programming guide say do it so. |
| 848 | */ | 857 | */ |
| 849 | 858 | ||
| 850 | rc = at86rf230_rx_read_frame(lp); | 859 | at86rf230_rx_read_frame(lp); |
| 851 | if (rc) { | ||
| 852 | enable_irq(lp->spi->irq); | ||
| 853 | at86rf230_async_error(lp, ctx, rc); | ||
| 854 | } | ||
| 855 | } | 860 | } |
| 856 | 861 | ||
| 857 | static int | 862 | static void |
| 858 | at86rf230_irq_trx_end(struct at86rf230_local *lp) | 863 | at86rf230_irq_trx_end(struct at86rf230_local *lp) |
| 859 | { | 864 | { |
| 860 | spin_lock(&lp->lock); | 865 | spin_lock(&lp->lock); |
| @@ -863,17 +868,19 @@ at86rf230_irq_trx_end(struct at86rf230_local *lp) | |||
| 863 | spin_unlock(&lp->lock); | 868 | spin_unlock(&lp->lock); |
| 864 | 869 | ||
| 865 | if (lp->tx_aret) | 870 | if (lp->tx_aret) |
| 866 | return at86rf230_async_state_change(lp, &lp->irq, | 871 | at86rf230_async_state_change(lp, &lp->irq, |
| 867 | STATE_FORCE_TX_ON, | 872 | STATE_FORCE_TX_ON, |
| 868 | at86rf230_tx_trac_status); | 873 | at86rf230_tx_trac_status, |
| 874 | true); | ||
| 869 | else | 875 | else |
| 870 | return at86rf230_async_state_change(lp, &lp->irq, | 876 | at86rf230_async_state_change(lp, &lp->irq, |
| 871 | STATE_RX_AACK_ON, | 877 | STATE_RX_AACK_ON, |
| 872 | at86rf230_tx_complete); | 878 | at86rf230_tx_complete, |
| 879 | true); | ||
| 873 | } else { | 880 | } else { |
| 874 | spin_unlock(&lp->lock); | 881 | spin_unlock(&lp->lock); |
| 875 | return at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq, | 882 | at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq, |
| 876 | at86rf230_rx_trac_check); | 883 | at86rf230_rx_trac_check, true); |
| 877 | } | 884 | } |
| 878 | } | 885 | } |
| 879 | 886 | ||
| @@ -884,12 +891,9 @@ at86rf230_irq_status(void *context) | |||
| 884 | struct at86rf230_local *lp = ctx->lp; | 891 | struct at86rf230_local *lp = ctx->lp; |
| 885 | const u8 *buf = lp->irq.buf; | 892 | const u8 *buf = lp->irq.buf; |
| 886 | const u8 irq = buf[1]; | 893 | const u8 irq = buf[1]; |
| 887 | int rc; | ||
| 888 | 894 | ||
| 889 | if (irq & IRQ_TRX_END) { | 895 | if (irq & IRQ_TRX_END) { |
| 890 | rc = at86rf230_irq_trx_end(lp); | 896 | at86rf230_irq_trx_end(lp); |
| 891 | if (rc) | ||
| 892 | at86rf230_async_error(lp, ctx, rc); | ||
| 893 | } else { | 897 | } else { |
| 894 | enable_irq(lp->spi->irq); | 898 | enable_irq(lp->spi->irq); |
| 895 | dev_err(&lp->spi->dev, "not supported irq %02x received\n", | 899 | dev_err(&lp->spi->dev, "not supported irq %02x received\n", |
| @@ -964,12 +968,9 @@ at86rf230_xmit_tx_on(void *context) | |||
| 964 | { | 968 | { |
| 965 | struct at86rf230_state_change *ctx = context; | 969 | struct at86rf230_state_change *ctx = context; |
| 966 | struct at86rf230_local *lp = ctx->lp; | 970 | struct at86rf230_local *lp = ctx->lp; |
| 967 | int rc; | ||
| 968 | 971 | ||
| 969 | rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, | 972 | at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, |
| 970 | at86rf230_write_frame); | 973 | at86rf230_write_frame, false); |
| 971 | if (rc) | ||
| 972 | at86rf230_async_error(lp, ctx, rc); | ||
| 973 | } | 974 | } |
| 974 | 975 | ||
| 975 | static int | 976 | static int |
| @@ -990,12 +991,8 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) | |||
| 990 | if (lp->tx_aret) | 991 | if (lp->tx_aret) |
| 991 | tx_complete = at86rf230_xmit_tx_on; | 992 | tx_complete = at86rf230_xmit_tx_on; |
| 992 | 993 | ||
| 993 | rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON, | 994 | at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false); |
| 994 | tx_complete); | 995 | |
| 995 | if (rc) { | ||
| 996 | at86rf230_async_error(lp, ctx, rc); | ||
| 997 | return rc; | ||
| 998 | } | ||
| 999 | rc = wait_for_completion_interruptible_timeout(&lp->tx_complete, | 996 | rc = wait_for_completion_interruptible_timeout(&lp->tx_complete, |
| 1000 | msecs_to_jiffies(lp->data->t_tx_timeout)); | 997 | msecs_to_jiffies(lp->data->t_tx_timeout)); |
| 1001 | if (!rc) { | 998 | if (!rc) { |
