Skip to contentSkip to conversation

at86rf230: state delay over hrtimer and calibration

PATCH In review Alexander Aring 2 participants 5 messages Mar 9, 2015 – Mar 14, 2015

Subsystems (2)
lore
Share & tools
lore

Alexander Aring

author maintainer
#0 lore raw

cover at86rf230: state delay over hrtimer and calibration

Hi,

this patch series contains for doing the state delay via hrtimer and introduce the transceiver calibration by doing a TRX_OFF -> TX_ON state before transmit and transceiver leaves 5 minutes in PLL state.

- Alex

Alexander Aring (3):
at86rf230: replace state change sleeps with hrtimer
at86rf230: add support for calibration timeout
at86rf230: fix volatile regmap registers

 drivers/net/ieee802154/at86rf230.c | 113 +++++++++++++++++++++++++++++--------
 1 file changed, 89 insertions(+), 24 deletions(-)
Signature · 1 line
2.3.0
author maintainer
#1 lore raw

PATCH 1/3 at86rf230: replace state change sleeps with hrtimer

This patch replace the state change timing relevant sleeps with hrtimers. Currently the sleeps are done in the complete handler of spi_async. The relation of doing the state change timing sleep with a timer will get the sleep functionality out of spi_async complete handler context.

---
 drivers/net/ieee802154/at86rf230.c | 39 ++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)
drivers/net/ieee802154/at86rf230.c +29 -10
index 088fa68..cdcd152 100644
@@ -19,6 +19,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/hrtimer.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
@@ -64,6 +65,7 @@ struct at86rf230_state_change {
 	struct at86rf230_local *lp;
 	int irq;
 
+	struct hrtimer timer;
 	struct spi_message msg;
 	struct spi_transfer trx;
 	u8 buf[AT86RF2XX_MAX_BUF];
@@ -548,6 +550,19 @@ done:
 		ctx->complete(context);
 }
 
+static enum hrtimer_restart at86rf230_async_state_timer(struct hrtimer *timer)
+{
+	struct at86rf230_state_change *ctx =
+		container_of(timer, struct at86rf230_state_change, timer);
+	struct at86rf230_local *lp = ctx->lp;
+
+	at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+				 at86rf230_async_state_assert,
+				 ctx->irq_enable);
+
+	return HRTIMER_NORESTART;
+}
+
 /* Do state change timing delay. */
 static void
 at86rf230_async_state_delay(void *context)
@@ -556,6 +571,7 @@ at86rf230_async_state_delay(void *context)
 	struct at86rf230_local *lp = ctx->lp;
 	struct at86rf2xx_chip_data *c = lp->data;
 	bool force = false;
+	ktime_t tim;
 
 	/* The force state changes are will show as normal states in the
 	 * state status subregister. We change the to_state to the
@@ -579,11 +595,10 @@ at86rf230_async_state_delay(void *context)
 	case STATE_TRX_OFF:
 		switch (ctx->to_state) {
 		case STATE_RX_AACK_ON:
-			usleep_range(c->t_off_to_aack, c->t_off_to_aack + 10);
+			tim = ktime_set(0, c->t_off_to_aack * NSEC_PER_USEC);
 			goto change;
 		case STATE_TX_ON:
-			usleep_range(c->t_off_to_tx_on,
-				     c->t_off_to_tx_on + 10);
+			tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC);
 			goto change;
 		default:
 			break;
@@ -597,8 +612,8 @@ at86rf230_async_state_delay(void *context)
 			 * to TX_ON.
 			 */
 			if (!force) {
-				usleep_range(c->t_frame + c->t_p_ack,
-					     c->t_frame + c->t_p_ack + 1000);
+				tim = ktime_set(0, (c->t_frame + c->t_p_ack) *
+						   NSEC_PER_USEC);
 				goto change;
 			}
 			break;
@@ -610,7 +625,7 @@ at86rf230_async_state_delay(void *context)
 	case STATE_P_ON:
 		switch (ctx->to_state) {
 		case STATE_TRX_OFF:
-			usleep_range(c->t_reset_to_off, c->t_reset_to_off + 10);
+			tim = ktime_set(0, c->t_reset_to_off * NSEC_PER_USEC);
 			goto change;
 		default:
 			break;
@@ -621,12 +636,10 @@ at86rf230_async_state_delay(void *context)
 	}
 
 	/* Default delay is 1us in the most cases */
-	udelay(1);
+	tim = ktime_set(0, NSEC_PER_USEC);
 
 change:
-	at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
-				 at86rf230_async_state_assert,
-				 ctx->irq_enable);
+	hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL);
 }
 
 static void
@@ -1546,6 +1559,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp)
 	lp->state.trx.tx_buf = lp->state.buf;
 	lp->state.trx.rx_buf = lp->state.buf;
 	spi_message_add_tail(&lp->state.trx, &lp->state.msg);
+	hrtimer_init(&lp->state.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	lp->state.timer.function = at86rf230_async_state_timer;
 
 	lp->irq.lp = lp;
 	lp->irq.irq = lp->spi->irq;
@@ -1555,6 +1570,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp)
 	lp->irq.trx.tx_buf = lp->irq.buf;
 	lp->irq.trx.rx_buf = lp->irq.buf;
 	spi_message_add_tail(&lp->irq.trx, &lp->irq.msg);
+	hrtimer_init(&lp->irq.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	lp->irq.timer.function = at86rf230_async_state_timer;
 
 	lp->tx.lp = lp;
 	lp->tx.irq = lp->spi->irq;
@@ -1564,6 +1581,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp)
 	lp->tx.trx.tx_buf = lp->tx.buf;
 	lp->tx.trx.rx_buf = lp->tx.buf;
 	spi_message_add_tail(&lp->tx.trx, &lp->tx.msg);
+	hrtimer_init(&lp->tx.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	lp->tx.timer.function = at86rf230_async_state_timer;
 }
 
 static int at86rf230_probe(struct spi_device *spi)
Signature · 1 line
2.3.0
author maintainer
#2 lore raw

PATCH 2/3 at86rf230: add support for calibration timeout

In reply to Alexander Aring

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.

Cc Phoebe Buckheister <[email protected]>
Cc Werner Almesberger <[email protected]>
---
 drivers/net/ieee802154/at86rf230.c | 72 ++++++++++++++++++++++++++++++--------
 1 file changed, 58 insertions(+), 14 deletions(-)
drivers/net/ieee802154/at86rf230.c +58 -14
index cdcd152..3b81c62 100644
@@ -20,6 +20,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/hrtimer.h>
+#include <linux/jiffies.h>
 #include <linux/interrupt.h>
 #include <linux/irq.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.
  */
 #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_local *lp;
@@ -90,6 +93,7 @@ struct at86rf230_local {
 	struct at86rf230_state_change irq;
 
 	bool tx_aret;
+	unsigned long cal_timeout;
 	s8 max_frame_retries;
 	bool is_tx;
 	/* 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
 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
 			 * will do a force change.
 			 */
-			if (ctx->to_state == STATE_TX_ON) {
-				u8 state = STATE_TX_ON;
+			if (ctx->to_state == STATE_TX_ON ||
+			    ctx->to_state == STATE_TRX_OFF) {
+				u8 state = ctx->to_state;
 
 				if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES)
-					state = STATE_FORCE_TX_ON;
+					state = at86rf230_state_to_force(state);
 				lp->tx_retry++;
 
 				at86rf230_async_state_change(lp, ctx, state,
@@ -599,6 +612,11 @@ at86rf230_async_state_delay(void *context)
 			goto change;
 		case STATE_TX_ON:
 			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;
 		default:
 			break;
@@ -606,10 +624,11 @@ at86rf230_async_state_delay(void *context)
 		break;
 	case STATE_BUSY_RX_AACK:
 		switch (ctx->to_state) {
+		case STATE_TRX_OFF:
 		case STATE_TX_ON:
 			/* Wait for worst case receiving time if we
 			 * didn't make a force change from BUSY_RX_AACK
-			 * to TX_ON.
+			 * to TX_ON or TRX_OFF.
 			 */
 			if (!force) {
 				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);
 }
 
-static int
-at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
+static void
+at86rf230_xmit_start(void *context)
 {
-	struct at86rf230_local *lp = hw->priv;
-	struct at86rf230_state_change *ctx = &lp->tx;
-
-	void (*tx_complete)(void *context) = at86rf230_write_frame;
-
-	lp->tx_skb = skb;
+	struct at86rf230_state_change *ctx = context;
+	struct at86rf230_local *lp = ctx->lp;
 
 	/* 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
 	 * the complete handler.
 	 */
 	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;
-	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;
 }
@@ -1003,6 +1042,9 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level)
 static int
 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);
 }
 
@@ -1083,6 +1125,8 @@ at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
 	/* Wait for PLL */
 	usleep_range(lp->data->t_channel_switch,
 		     lp->data->t_channel_switch + 10);
+
+	lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
 	return rc;
 }
 
Signature · 1 line
2.3.0
author maintainer
#3 lore raw

PATCH 3/3 at86rf230: fix volatile regmap registers

In reply to Alexander Aring

These registers are also changed by transceiver and should be volatile for right accessing via regmap debugfs.

---
 drivers/net/ieee802154/at86rf230.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/net/ieee802154/at86rf230.c +2 -0
index 3b81c62..51b88fd 100644
@@ -421,6 +421,8 @@ at86rf230_reg_volatile(struct device *dev, unsigned int reg)
 	case RG_PHY_ED_LEVEL:
 	case RG_IRQ_STATUS:
 	case RG_VREG_CTRL:
+	case RG_PLL_CF:
+	case RG_PLL_DCU:
 		return true;
 	default:
 		return false;
Signature · 1 line
2.3.0
#4 lore raw
In reply to Alexander Aring

Hi Alex,

Quoted 6 lines

this patch series contains for doing the state delay via hrtimer and introduce the transceiver calibration by doing a TRX_OFF -> TX_ON state before transmit and transceiver leaves 5 minutes in PLL state.

- Alex

Quoted 7 lines

Alexander Aring (3):
at86rf230: replace state change sleeps with hrtimer
at86rf230: add support for calibration timeout
at86rf230: fix volatile regmap registers

drivers/net/ieee802154/at86rf230.c | 113 +++++++++++++++++++++++++++++--------

1 file changed, 89 insertions(+), 24 deletions(-)

all 3 patches have been applied to bluetooth-next tree.

Regards

Marcel