Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dce481e6 authored by Alexander Aring's avatar Alexander Aring Committed by Marcel Holtmann
Browse files

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: default avatarAlexander Aring <alex.aring@gmail.com>
Cc: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
Cc: Werner Almesberger <werner@almesberger.net>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent eb3b435e
Loading
Loading
Loading
Loading
+58 −14
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/hrtimer.h>
#include <linux/hrtimer.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/gpio.h>
@@ -60,6 +61,8 @@ struct at86rf2xx_chip_data {
 * We assume the max_frame_retries (7) value of 802.15.4 here.
 * We assume the max_frame_retries (7) value of 802.15.4 here.
 */
 */
#define AT86RF2XX_MAX_TX_RETRIES	7
#define AT86RF2XX_MAX_TX_RETRIES	7
/* We use the recommended 5 minutes timeout to recalibrate */
#define AT86RF2XX_CAL_LOOP_TIMEOUT	(5 * 60 * HZ)


struct at86rf230_state_change {
struct at86rf230_state_change {
	struct at86rf230_local *lp;
	struct at86rf230_local *lp;
@@ -90,6 +93,7 @@ struct at86rf230_local {
	struct at86rf230_state_change irq;
	struct at86rf230_state_change irq;


	bool tx_aret;
	bool tx_aret;
	unsigned long cal_timeout;
	s8 max_frame_retries;
	s8 max_frame_retries;
	bool is_tx;
	bool is_tx;
	/* spinlock for is_tx protection */
	/* spinlock for is_tx protection */
@@ -491,6 +495,14 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg,
	}
	}
}
}


static inline u8 at86rf230_state_to_force(u8 state)
{
	if (state == STATE_TX_ON)
		return STATE_FORCE_TX_ON;
	else
		return STATE_FORCE_TRX_OFF;
}

static void
static void
at86rf230_async_state_assert(void *context)
at86rf230_async_state_assert(void *context)
{
{
@@ -527,11 +539,12 @@ at86rf230_async_state_assert(void *context)
			 * higher or equal than AT86RF2XX_MAX_TX_RETRIES we
			 * higher or equal than AT86RF2XX_MAX_TX_RETRIES we
			 * will do a force change.
			 * will do a force change.
			 */
			 */
			if (ctx->to_state == STATE_TX_ON) {
			if (ctx->to_state == STATE_TX_ON ||
				u8 state = STATE_TX_ON;
			    ctx->to_state == STATE_TRX_OFF) {
				u8 state = ctx->to_state;


				if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES)
				if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES)
					state = STATE_FORCE_TX_ON;
					state = at86rf230_state_to_force(state);
				lp->tx_retry++;
				lp->tx_retry++;


				at86rf230_async_state_change(lp, ctx, state,
				at86rf230_async_state_change(lp, ctx, state,
@@ -599,6 +612,11 @@ at86rf230_async_state_delay(void *context)
			goto change;
			goto change;
		case STATE_TX_ON:
		case STATE_TX_ON:
			tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC);
			tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC);
			/* state change from TRX_OFF to TX_ON to do a
			 * calibration, we need to reset the timeout for the
			 * next one.
			 */
			lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
			goto change;
			goto change;
		default:
		default:
			break;
			break;
@@ -606,10 +624,11 @@ at86rf230_async_state_delay(void *context)
		break;
		break;
	case STATE_BUSY_RX_AACK:
	case STATE_BUSY_RX_AACK:
		switch (ctx->to_state) {
		switch (ctx->to_state) {
		case STATE_TRX_OFF:
		case STATE_TX_ON:
		case STATE_TX_ON:
			/* Wait for worst case receiving time if we
			/* Wait for worst case receiving time if we
			 * didn't make a force change from BUSY_RX_AACK
			 * didn't make a force change from BUSY_RX_AACK
			 * to TX_ON.
			 * to TX_ON or TRX_OFF.
			 */
			 */
			if (!force) {
			if (!force) {
				tim = ktime_set(0, (c->t_frame + c->t_p_ack) *
				tim = ktime_set(0, (c->t_frame + c->t_p_ack) *
@@ -969,25 +988,45 @@ at86rf230_xmit_tx_on(void *context)
				     at86rf230_write_frame, false);
				     at86rf230_write_frame, false);
}
}


static int
static void
at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
at86rf230_xmit_start(void *context)
{
{
	struct at86rf230_local *lp = hw->priv;
	struct at86rf230_state_change *ctx = context;
	struct at86rf230_state_change *ctx = &lp->tx;
	struct at86rf230_local *lp = ctx->lp;

	void (*tx_complete)(void *context) = at86rf230_write_frame;

	lp->tx_skb = skb;


	/* In ARET mode we need to go into STATE_TX_ARET_ON after we
	/* In ARET mode we need to go into STATE_TX_ARET_ON after we
	 * are in STATE_TX_ON. The pfad differs here, so we change
	 * are in STATE_TX_ON. The pfad differs here, so we change
	 * the complete handler.
	 * the complete handler.
	 */
	 */
	if (lp->tx_aret)
	if (lp->tx_aret)
		tx_complete = at86rf230_xmit_tx_on;
		at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
					     at86rf230_xmit_tx_on, false);
	else
		at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
					     at86rf230_write_frame, false);
}

static int
at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
{
	struct at86rf230_local *lp = hw->priv;
	struct at86rf230_state_change *ctx = &lp->tx;


	lp->tx_skb = skb;
	lp->tx_retry = 0;
	lp->tx_retry = 0;
	at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false);

	/* After 5 minutes in PLL and the same frequency we run again the
	 * calibration loops which is recommended by at86rf2xx datasheets.
	 *
	 * The calibration is initiate by a state change from TRX_OFF
	 * to TX_ON, the lp->cal_timeout should be reinit by state_delay
	 * function then to start in the next 5 minutes.
	 */
	if (time_is_before_jiffies(lp->cal_timeout))
		at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF,
					     at86rf230_xmit_start, false);
	else
		at86rf230_xmit_start(ctx);


	return 0;
	return 0;
}
}
@@ -1003,6 +1042,9 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level)
static int
static int
at86rf230_start(struct ieee802154_hw *hw)
at86rf230_start(struct ieee802154_hw *hw)
{
{
	struct at86rf230_local *lp = hw->priv;

	lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
	return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON);
	return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON);
}
}


@@ -1083,6 +1125,8 @@ at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
	/* Wait for PLL */
	/* Wait for PLL */
	usleep_range(lp->data->t_channel_switch,
	usleep_range(lp->data->t_channel_switch,
		     lp->data->t_channel_switch + 10);
		     lp->data->t_channel_switch + 10);

	lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
	return rc;
	return rc;
}
}