diff options
| author | Alexander Aring <alex.aring@gmail.com> | 2015-03-09 08:56:11 -0400 |
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2015-03-14 12:11:31 -0400 |
| commit | dce481e63dc18ece7c86c607aa17b7c753fce0b7 (patch) | |
| tree | 2a952d0cf786987a03e56fd7268c370e32dd4810 | |
| parent | eb3b435ecdb84d05698db862ce316b3c682f9a95 (diff) | |
at86rf230: add support for calibration timeout
This patch adds a handling for calibration if we are 5 minutes in PLL
state. I first tried to implement the calibration functionality in
TX_ON state via register values CF_START and DCU_START, but this occurs
a one second delay at each calibration time.
An another solution to start a calibration is to switch from TRX_OFF
state into TX_ON, then a calibration is done automatically by
transceiver. This method will be used in this patch, after each transmit
of a frame we check with jiffies if the PLL is set 5 minutes without
doing a TRX_OFF->(TX_ON || RX_AACK_ON) or channel switch. The worst case
would be a transceiver in receiving mode only, but this is under normal
operation very unlikely.
Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Cc: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
Cc: Werner Almesberger <werner@almesberger.net>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
| -rw-r--r-- | drivers/net/ieee802154/at86rf230.c | 72 |
1 files changed, 58 insertions, 14 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 4030fa69f176..795106c23097 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/hrtimer.h> | 22 | #include <linux/hrtimer.h> |
| 23 | #include <linux/jiffies.h> | ||
| 23 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
| 24 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
| 25 | #include <linux/gpio.h> | 26 | #include <linux/gpio.h> |
| @@ -60,6 +61,8 @@ struct at86rf2xx_chip_data { | |||
| 60 | * We assume the max_frame_retries (7) value of 802.15.4 here. | 61 | * We assume the max_frame_retries (7) value of 802.15.4 here. |
| 61 | */ | 62 | */ |
| 62 | #define AT86RF2XX_MAX_TX_RETRIES 7 | 63 | #define AT86RF2XX_MAX_TX_RETRIES 7 |
| 64 | /* We use the recommended 5 minutes timeout to recalibrate */ | ||
| 65 | #define AT86RF2XX_CAL_LOOP_TIMEOUT (5 * 60 * HZ) | ||
| 63 | 66 | ||
| 64 | struct at86rf230_state_change { | 67 | struct at86rf230_state_change { |
| 65 | struct at86rf230_local *lp; | 68 | struct at86rf230_local *lp; |
| @@ -90,6 +93,7 @@ struct at86rf230_local { | |||
| 90 | struct at86rf230_state_change irq; | 93 | struct at86rf230_state_change irq; |
| 91 | 94 | ||
| 92 | bool tx_aret; | 95 | bool tx_aret; |
| 96 | unsigned long cal_timeout; | ||
| 93 | s8 max_frame_retries; | 97 | s8 max_frame_retries; |
| 94 | bool is_tx; | 98 | bool is_tx; |
| 95 | /* spinlock for is_tx protection */ | 99 | /* spinlock for is_tx protection */ |
| @@ -491,6 +495,14 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, | |||
| 491 | } | 495 | } |
| 492 | } | 496 | } |
| 493 | 497 | ||
| 498 | static inline u8 at86rf230_state_to_force(u8 state) | ||
| 499 | { | ||
| 500 | if (state == STATE_TX_ON) | ||
| 501 | return STATE_FORCE_TX_ON; | ||
| 502 | else | ||
| 503 | return STATE_FORCE_TRX_OFF; | ||
| 504 | } | ||
| 505 | |||
| 494 | static void | 506 | static void |
| 495 | at86rf230_async_state_assert(void *context) | 507 | at86rf230_async_state_assert(void *context) |
| 496 | { | 508 | { |
| @@ -527,11 +539,12 @@ at86rf230_async_state_assert(void *context) | |||
| 527 | * higher or equal than AT86RF2XX_MAX_TX_RETRIES we | 539 | * higher or equal than AT86RF2XX_MAX_TX_RETRIES we |
| 528 | * will do a force change. | 540 | * will do a force change. |
| 529 | */ | 541 | */ |
| 530 | if (ctx->to_state == STATE_TX_ON) { | 542 | if (ctx->to_state == STATE_TX_ON || |
| 531 | u8 state = STATE_TX_ON; | 543 | ctx->to_state == STATE_TRX_OFF) { |
| 544 | u8 state = ctx->to_state; | ||
| 532 | 545 | ||
| 533 | if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES) | 546 | if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES) |
| 534 | state = STATE_FORCE_TX_ON; | 547 | state = at86rf230_state_to_force(state); |
| 535 | lp->tx_retry++; | 548 | lp->tx_retry++; |
| 536 | 549 | ||
| 537 | at86rf230_async_state_change(lp, ctx, state, | 550 | at86rf230_async_state_change(lp, ctx, state, |
| @@ -599,6 +612,11 @@ at86rf230_async_state_delay(void *context) | |||
| 599 | goto change; | 612 | goto change; |
| 600 | case STATE_TX_ON: | 613 | case STATE_TX_ON: |
| 601 | tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); | 614 | tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); |
| 615 | /* state change from TRX_OFF to TX_ON to do a | ||
| 616 | * calibration, we need to reset the timeout for the | ||
| 617 | * next one. | ||
| 618 | */ | ||
| 619 | lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; | ||
| 602 | goto change; | 620 | goto change; |
| 603 | default: | 621 | default: |
| 604 | break; | 622 | break; |
| @@ -606,10 +624,11 @@ at86rf230_async_state_delay(void *context) | |||
| 606 | break; | 624 | break; |
| 607 | case STATE_BUSY_RX_AACK: | 625 | case STATE_BUSY_RX_AACK: |
| 608 | switch (ctx->to_state) { | 626 | switch (ctx->to_state) { |
| 627 | case STATE_TRX_OFF: | ||
| 609 | case STATE_TX_ON: | 628 | case STATE_TX_ON: |
| 610 | /* Wait for worst case receiving time if we | 629 | /* Wait for worst case receiving time if we |
| 611 | * didn't make a force change from BUSY_RX_AACK | 630 | * didn't make a force change from BUSY_RX_AACK |
| 612 | * to TX_ON. | 631 | * to TX_ON or TRX_OFF. |
| 613 | */ | 632 | */ |
| 614 | if (!force) { | 633 | if (!force) { |
| 615 | tim = ktime_set(0, (c->t_frame + c->t_p_ack) * | 634 | tim = ktime_set(0, (c->t_frame + c->t_p_ack) * |
| @@ -969,25 +988,45 @@ at86rf230_xmit_tx_on(void *context) | |||
| 969 | at86rf230_write_frame, false); | 988 | at86rf230_write_frame, false); |
| 970 | } | 989 | } |
| 971 | 990 | ||
| 972 | static int | 991 | static void |
| 973 | at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) | 992 | at86rf230_xmit_start(void *context) |
| 974 | { | 993 | { |
| 975 | struct at86rf230_local *lp = hw->priv; | 994 | struct at86rf230_state_change *ctx = context; |
| 976 | struct at86rf230_state_change *ctx = &lp->tx; | 995 | struct at86rf230_local *lp = ctx->lp; |
| 977 | |||
| 978 | void (*tx_complete)(void *context) = at86rf230_write_frame; | ||
| 979 | |||
| 980 | lp->tx_skb = skb; | ||
| 981 | 996 | ||
| 982 | /* In ARET mode we need to go into STATE_TX_ARET_ON after we | 997 | /* In ARET mode we need to go into STATE_TX_ARET_ON after we |
| 983 | * are in STATE_TX_ON. The pfad differs here, so we change | 998 | * are in STATE_TX_ON. The pfad differs here, so we change |
| 984 | * the complete handler. | 999 | * the complete handler. |
| 985 | */ | 1000 | */ |
| 986 | if (lp->tx_aret) | 1001 | if (lp->tx_aret) |
| 987 | tx_complete = at86rf230_xmit_tx_on; | 1002 | at86rf230_async_state_change(lp, ctx, STATE_TX_ON, |
| 1003 | at86rf230_xmit_tx_on, false); | ||
| 1004 | else | ||
| 1005 | at86rf230_async_state_change(lp, ctx, STATE_TX_ON, | ||
| 1006 | at86rf230_write_frame, false); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static int | ||
| 1010 | at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) | ||
| 1011 | { | ||
| 1012 | struct at86rf230_local *lp = hw->priv; | ||
| 1013 | struct at86rf230_state_change *ctx = &lp->tx; | ||
| 988 | 1014 | ||
| 1015 | lp->tx_skb = skb; | ||
| 989 | lp->tx_retry = 0; | 1016 | lp->tx_retry = 0; |
| 990 | at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false); | 1017 | |
| 1018 | /* After 5 minutes in PLL and the same frequency we run again the | ||
| 1019 | * calibration loops which is recommended by at86rf2xx datasheets. | ||
| 1020 | * | ||
| 1021 | * The calibration is initiate by a state change from TRX_OFF | ||
| 1022 | * to TX_ON, the lp->cal_timeout should be reinit by state_delay | ||
| 1023 | * function then to start in the next 5 minutes. | ||
| 1024 | */ | ||
| 1025 | if (time_is_before_jiffies(lp->cal_timeout)) | ||
| 1026 | at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF, | ||
| 1027 | at86rf230_xmit_start, false); | ||
| 1028 | else | ||
| 1029 | at86rf230_xmit_start(ctx); | ||
| 991 | 1030 | ||
| 992 | return 0; | 1031 | return 0; |
| 993 | } | 1032 | } |
| @@ -1003,6 +1042,9 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level) | |||
| 1003 | static int | 1042 | static int |
| 1004 | at86rf230_start(struct ieee802154_hw *hw) | 1043 | at86rf230_start(struct ieee802154_hw *hw) |
| 1005 | { | 1044 | { |
| 1045 | struct at86rf230_local *lp = hw->priv; | ||
| 1046 | |||
| 1047 | lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; | ||
| 1006 | return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); | 1048 | return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); |
| 1007 | } | 1049 | } |
| 1008 | 1050 | ||
| @@ -1083,6 +1125,8 @@ at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel) | |||
| 1083 | /* Wait for PLL */ | 1125 | /* Wait for PLL */ |
| 1084 | usleep_range(lp->data->t_channel_switch, | 1126 | usleep_range(lp->data->t_channel_switch, |
| 1085 | lp->data->t_channel_switch + 10); | 1127 | lp->data->t_channel_switch + 10); |
| 1128 | |||
