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 | |||
1129 | lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; | ||
1086 | return rc; | 1130 | return rc; |
1087 | } | 1131 | } |
1088 | 1132 | ||