static irqreturn_t at86rf230_isr(int irq, void *data) { struct at86rf230_local *lp = data; struct at86rf230_state_change *ctx; int rc; disable_irq_nosync(irq); ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC); if (!ctx) { enable_irq(irq); return IRQ_NONE; } at86rf230_setup_spi_messages(lp, ctx); /* tell on error handling to free ctx */ ctx->free = true; ctx->buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG; ctx->msg.complete = at86rf230_irq_status; rc = spi_async(lp->spi, &ctx->msg); if (rc) { at86rf230_async_error(lp, ctx, rc); enable_irq(irq); return IRQ_NONE; } return IRQ_HANDLED; }
static void at86rf230_async_write_reg(struct at86rf230_local *lp, u8 reg, u8 val, struct at86rf230_state_change *ctx, void (*complete)(void *context)) { int rc; ctx->buf[0] = (reg & CMD_REG_MASK) | CMD_REG | CMD_WRITE; ctx->buf[1] = val; ctx->msg.complete = complete; rc = spi_async(lp->spi, &ctx->msg); if (rc) at86rf230_async_error(lp, ctx, rc); }
/* Generic function to get some register value in async mode */ static void at86rf230_async_read_reg(struct at86rf230_local *lp, u8 reg, struct at86rf230_state_change *ctx, void (*complete)(void *context)) { int rc; u8 *tx_buf = ctx->buf; tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; ctx->msg.complete = complete; rc = spi_async(lp->spi, &ctx->msg); if (rc) at86rf230_async_error(lp, ctx, rc); }
static void at86rf230_write_frame_complete(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; u8 *buf = ctx->buf; int rc; buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; buf[1] = STATE_BUSY_TX; ctx->trx.len = 2; ctx->msg.complete = NULL; rc = spi_async(lp->spi, &ctx->msg); if (rc) at86rf230_async_error(lp, ctx, rc); }
static void at86rf230_rx_read_frame(struct at86rf230_local *lp) { int rc; u8 *buf = lp->irq.buf; buf[0] = CMD_FB; lp->irq.trx.len = AT86RF2XX_MAX_BUF; lp->irq.msg.complete = at86rf230_rx_read_frame_complete; rc = spi_async(lp->spi, &lp->irq.msg); if (rc) { enable_irq(lp->spi->irq); at86rf230_async_error(lp, &lp->irq, rc); } }
/* This function do a sync framework above the async state change. * Some callbacks of the IEEE 802.15.4 driver interface need to be * handled synchronously. */ static int at86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state) { unsigned long rc; at86rf230_async_state_change(lp, &lp->state, state, at86rf230_sync_state_change_complete); rc = wait_for_completion_timeout(&lp->state_complete, msecs_to_jiffies(100)); if (!rc) { at86rf230_async_error(lp, &lp->state, -ETIMEDOUT); return -ETIMEDOUT; } return 0; }
static void at86rf230_rx_read_frame(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; u8 *buf = ctx->buf; int rc; buf[0] = CMD_FB; ctx->trx.len = AT86RF2XX_MAX_BUF; ctx->msg.complete = at86rf230_rx_read_frame_complete; rc = spi_async(lp->spi, &ctx->msg); if (rc) { ctx->trx.len = 2; enable_irq(ctx->irq); at86rf230_async_error(lp, ctx, rc); } }
static void at86rf230_async_state_change_start(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; u8 *buf = ctx->buf; const u8 trx_state = buf[1] & 0x1f; int rc; /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ if (trx_state == STATE_TRANSITION_IN_PROGRESS) { udelay(1); at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, at86rf230_async_state_change_start, ctx->irq_enable); return; } /* Check if we already are in the state which we change in */ if (trx_state == ctx->to_state) { if (ctx->complete) ctx->complete(context); return; } /* Set current state to the context of state change */ ctx->from_state = trx_state; /* Going into the next step for a state change which do a timing * relevant delay. */ buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; buf[1] = ctx->to_state; ctx->trx.len = 2; ctx->msg.complete = at86rf230_async_state_delay; rc = spi_async(lp->spi, &ctx->msg); if (rc) { if (ctx->irq_enable) enable_irq(lp->spi->irq); at86rf230_async_error(lp, ctx, rc); } }
static irqreturn_t at86rf230_isr(int irq, void *data) { struct at86rf230_local *lp = data; struct at86rf230_state_change *ctx = &lp->irq; u8 *buf = ctx->buf; int rc; disable_irq_nosync(irq); buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG; ctx->msg.complete = at86rf230_irq_status; rc = spi_async(lp->spi, &ctx->msg); if (rc) { enable_irq(irq); at86rf230_async_error(lp, ctx, rc); return IRQ_NONE; } return IRQ_HANDLED; }
/* Generic function to get some register value in async mode */ static void at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, struct at86rf230_state_change *ctx, void (*complete)(void *context), const bool irq_enable) { int rc; u8 *tx_buf = ctx->buf; tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; ctx->msg.complete = complete; ctx->irq_enable = irq_enable; rc = spi_async(lp->spi, &ctx->msg); if (rc) { if (irq_enable) enable_irq(ctx->irq); at86rf230_async_error(lp, ctx, rc); } }
static void at86rf230_write_frame(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; struct sk_buff *skb = lp->tx_skb; u8 *buf = lp->tx.buf; int rc; spin_lock(&lp->lock); lp->is_tx = 1; spin_unlock(&lp->lock); buf[0] = CMD_FB | CMD_WRITE; buf[1] = skb->len + 2; memcpy(buf + 2, skb->data, skb->len); lp->tx.trx.len = skb->len + 2; lp->tx.msg.complete = at86rf230_write_frame_complete; rc = spi_async(lp->spi, &lp->tx.msg); if (rc) at86rf230_async_error(lp, ctx, rc); }
static void at86rf230_rx_trac_check(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; u8 *buf = ctx->buf; int rc; if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS)) { u8 trac = TRAC_MASK(buf[1]); switch (trac) { case TRAC_SUCCESS: lp->trac.success++; break; case TRAC_SUCCESS_WAIT_FOR_ACK: lp->trac.success_wait_for_ack++; break; case TRAC_INVALID: lp->trac.invalid++; break; default: WARN_ONCE(1, "received rx trac status %d\n", trac); break; } } buf[0] = CMD_FB; ctx->trx.len = AT86RF2XX_MAX_BUF; ctx->msg.complete = at86rf230_rx_read_frame_complete; rc = spi_async(lp->spi, &ctx->msg); if (rc) { ctx->trx.len = 2; at86rf230_async_error(lp, ctx, rc); } }