summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-03-14 14:29:45 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-14 14:29:45 -0400
commit5f1764ddfeb038decfe2b2fda030d0bed43fa36a (patch)
treea42d36330758ccce3becb22b96c8c748b89a837a /drivers
parent2801be4a0ea4cd0965f9c12ff813a91892a8e157 (diff)
parentb6d595e3f74fe0dd9edc0d5bf30cd6e6fe29f023 (diff)
downloadop-kernel-dev-5f1764ddfeb038decfe2b2fda030d0bed43fa36a.zip
op-kernel-dev-5f1764ddfeb038decfe2b2fda030d0bed43fa36a.tar.gz
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== Here's another set of Bluetooth & ieee802154 patches intended for 4.1: - Added support for QCA ROME chipset family in the btusb driver - at86rf230 driver fixes & cleanups - ieee802154 cleanups - Refactoring of Bluetooth mgmt API to allow new users - New setting for static Bluetooth address exposed to user space - Refactoring of hci_dev flags to remove limit of 32 - Remove unnecessary fast-connectable setting usage restrictions - Fix behavior to be consistent when trying to pair already paired device - Service discovery corner-case fixes Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/btusb.c333
-rw-r--r--drivers/net/ieee802154/at86rf230.c226
2 files changed, 455 insertions, 104 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8c1bf61..6fa9338 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -52,6 +52,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_SWAVE 0x1000
#define BTUSB_INTEL_NEW 0x2000
#define BTUSB_AMP 0x4000
+#define BTUSB_QCA_ROME 0x8000
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -213,6 +214,10 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
+ /* QCA ROME chipset */
+ { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME},
+ { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME},
+
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -338,6 +343,8 @@ struct btusb_data {
int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
+
+ int (*setup_on_usb)(struct hci_dev *hdev);
};
static inline void btusb_free_frags(struct btusb_data *data)
@@ -879,6 +886,15 @@ static int btusb_open(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
+ /* Patching USB firmware files prior to starting any URBs of HCI path
+ * It is more safe to use USB bulk channel for downloading USB patch
+ */
+ if (data->setup_on_usb) {
+ err = data->setup_on_usb(hdev);
+ if (err <0)
+ return err;
+ }
+
err = usb_autopm_get_interface(data->intf);
if (err < 0)
return err;
@@ -1254,6 +1270,28 @@ static void btusb_waker(struct work_struct *work)
usb_autopm_put_interface(data->intf);
}
+static struct sk_buff *btusb_read_local_version(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return skb;
+ }
+
+ if (skb->len != sizeof(struct hci_rp_read_local_version)) {
+ BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
+ hdev->name);
+ kfree_skb(skb);
+ return ERR_PTR(-EIO);
+ }
+
+ return skb;
+}
+
static int btusb_setup_bcm92035(struct hci_dev *hdev)
{
struct sk_buff *skb;
@@ -1278,12 +1316,9 @@ static int btusb_setup_csr(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb));
+ skb = btusb_read_local_version(hdev);
+ if (IS_ERR(skb))
return -PTR_ERR(skb);
- }
rp = (struct hci_rp_read_local_version *)skb->data;
@@ -2414,21 +2449,9 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
kfree_skb(skb);
/* Read Local Version Info */
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
- HCI_INIT_TIMEOUT);
- if (IS_ERR(skb)) {
- ret = PTR_ERR(skb);
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
- hdev->name, ret);
- return ret;
- }
-
- if (skb->len != sizeof(*ver)) {
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
- hdev->name);
- kfree_skb(skb);
- return -EIO;
- }
+ skb = btusb_read_local_version(hdev);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
ver = (struct hci_rp_read_local_version *)skb->data;
rev = le16_to_cpu(ver->hci_rev);
@@ -2516,20 +2539,9 @@ reset_fw:
kfree_skb(skb);
/* Read Local Version Info */
- skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
- HCI_INIT_TIMEOUT);
+ skb = btusb_read_local_version(hdev);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
- hdev->name, ret);
- goto done;
- }
-
- if (skb->len != sizeof(*ver)) {
- BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
- hdev->name);
- kfree_skb(skb);
- ret = -EIO;
goto done;
}
@@ -2628,6 +2640,258 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
return 0;
}
+#define QCA_DFU_PACKET_LEN 4096
+
+#define QCA_GET_TARGET_VERSION 0x09
+#define QCA_CHECK_STATUS 0x05
+#define QCA_DFU_DOWNLOAD 0x01
+
+#define QCA_SYSCFG_UPDATED 0x40
+#define QCA_PATCH_UPDATED 0x80
+#define QCA_DFU_TIMEOUT 3000
+
+struct qca_version {
+ __le32 rom_version;
+ __le32 patch_version;
+ __le32 ram_version;
+ __le32 ref_clock;
+ __u8 reserved[4];
+} __packed;
+
+struct qca_rampatch_version {
+ __le16 rom_version;
+ __le16 patch_version;
+} __packed;
+
+struct qca_device_info {
+ u32 rom_version;
+ u8 rampatch_hdr; /* length of header in rampatch */
+ u8 nvm_hdr; /* length of header in NVM */
+ u8 ver_offset; /* offset of version structure in rampatch */
+};
+
+static const struct qca_device_info qca_devices_table[] = {
+ { 0x00000100, 20, 4, 10 }, /* Rome 1.0 */
+ { 0x00000101, 20, 4, 10 }, /* Rome 1.1 */
+ { 0x00000201, 28, 4, 18 }, /* Rome 2.1 */
+ { 0x00000300, 28, 4, 18 }, /* Rome 3.0 */
+ { 0x00000302, 28, 4, 18 }, /* Rome 3.2 */
+};
+
+static int btusb_qca_send_vendor_req(struct hci_dev *hdev, u8 request,
+ void *data, u16 size)
+{
+ struct btusb_data *btdata = hci_get_drvdata(hdev);
+ struct usb_device *udev = btdata->udev;
+ int pipe, err;
+ u8 *buf;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* Found some of USB hosts have IOT issues with ours so that we should
+ * not wait until HCI layer is ready.
+ */
+ pipe = usb_rcvctrlpipe(udev, 0);
+ err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN,
+ 0, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+ if (err < 0) {
+ BT_ERR("%s: Failed to access otp area (%d)", hdev->name, err);
+ goto done;
+ }
+
+ memcpy(data, buf, size);
+
+done:
+ kfree(buf);
+
+ return err;
+}
+
+static int btusb_setup_qca_download_fw(struct hci_dev *hdev,
+ const struct firmware *firmware,
+ size_t hdr_size)
+{
+ struct btusb_data *btdata = hci_get_drvdata(hdev);
+ struct usb_device *udev = btdata->udev;
+ size_t count, size, sent = 0;
+ int pipe, len, err;
+ u8 *buf;
+
+ buf = kmalloc(QCA_DFU_PACKET_LEN, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ count = firmware->size;
+
+ size = min_t(size_t, count, hdr_size);
+ memcpy(buf, firmware->data, size);
+
+ /* USB patches should go down to controller through USB path
+ * because binary format fits to go down through USB channel.
+ * USB control path is for patching headers and USB bulk is for
+ * patch body.
+ */
+ pipe = usb_sndctrlpipe(udev, 0);
+ err = usb_control_msg(udev, pipe, QCA_DFU_DOWNLOAD, USB_TYPE_VENDOR,
+ 0, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send headers (%d)", hdev->name, err);
+ goto done;
+ }
+
+ sent += size;
+ count -= size;
+
+ while (count) {
+ size = min_t(size_t, count, QCA_DFU_PACKET_LEN);
+
+ memcpy(buf, firmware->data + sent, size);
+
+ pipe = usb_sndbulkpipe(udev, 0x02);
+ err = usb_bulk_msg(udev, pipe, buf, size, &len,
+ QCA_DFU_TIMEOUT);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send body at %zd of %zd (%d)",
+ hdev->name, sent, firmware->size, err);
+ break;
+ }
+
+ if (size != len) {
+ BT_ERR("%s: Failed to get bulk buffer", hdev->name);
+ err = -EILSEQ;
+ break;
+ }
+
+ sent += size;
+ count -= size;
+ }
+
+done:
+ kfree(buf);
+ return err;
+}
+
+static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
+ struct qca_version *ver,
+ const struct qca_device_info *info)
+{
+ struct qca_rampatch_version *rver;
+ const struct firmware *fw;
+ u32 ver_rom, ver_patch;
+ u16 rver_rom, rver_patch;
+ char fwname[64];
+ int err;
+
+ ver_rom = le32_to_cpu(ver->rom_version);
+ ver_patch = le32_to_cpu(ver->patch_version);
+
+ snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", ver_rom);
+
+ err = request_firmware(&fw, fwname, &hdev->dev);
+ if (err) {
+ BT_ERR("%s: failed to request rampatch file: %s (%d)",
+ hdev->name, fwname, err);
+ return err;
+ }
+
+ BT_INFO("%s: using rampatch file: %s", hdev->name, fwname);
+
+ rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset);
+ rver_rom = le16_to_cpu(rver->rom_version);
+ rver_patch = le16_to_cpu(rver->patch_version);
+
+ BT_INFO("%s: QCA: patch rome 0x%x build 0x%x, firmware rome 0x%x "
+ "build 0x%x", hdev->name, rver_rom, rver_patch, ver_rom,
+ ver_patch);
+
+ if (rver_rom != ver_rom || rver_patch <= ver_patch) {
+ BT_ERR("%s: rampatch file version did not match with firmware",
+ hdev->name);
+ err = -EINVAL;
+ goto done;
+ }
+
+ err = btusb_setup_qca_download_fw(hdev, fw, info->rampatch_hdr);
+
+done:
+ release_firmware(fw);
+
+ return err;
+}
+
+static int btusb_setup_qca_load_nvm(struct hci_dev *hdev,
+ struct qca_version *ver,
+ const struct qca_device_info *info)
+{
+ const struct firmware *fw;
+ char fwname[64];
+ int err;
+
+ snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin",
+ le32_to_cpu(ver->rom_version));
+
+ err = request_firmware(&fw, fwname, &hdev->dev);
+ if (err) {
+ BT_ERR("%s: failed to request NVM file: %s (%d)",
+ hdev->name, fwname, err);
+ return err;
+ }
+
+ BT_INFO("%s: using NVM file: %s", hdev->name, fwname);
+
+ err = btusb_setup_qca_download_fw(hdev, fw, info->nvm_hdr);
+
+ release_firmware(fw);
+
+ return err;
+}
+
+static int btusb_setup_qca(struct hci_dev *hdev)
+{
+ const struct qca_device_info *info = NULL;
+ struct qca_version ver;
+ u32 ver_rom;
+ u8 status;
+ int i, err;
+
+ err = btusb_qca_send_vendor_req(hdev, QCA_GET_TARGET_VERSION, &ver,
+ sizeof(ver));
+ if (err < 0)
+ return err;
+
+ ver_rom = le32_to_cpu(ver.rom_version);
+ for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) {
+ if (ver_rom == qca_devices_table[i].rom_version)
+ info = &qca_devices_table[i];
+ }
+ if (!info) {
+ BT_ERR("%s: don't support firmware rome 0x%x", hdev->name,
+ ver_rom);
+ return -ENODEV;
+ }
+
+ err = btusb_qca_send_vendor_req(hdev, QCA_CHECK_STATUS, &status,
+ sizeof(status));
+ if (err < 0)
+ return err;
+
+ if (!(status & QCA_PATCH_UPDATED)) {
+ err = btusb_setup_qca_load_rampatch(hdev, &ver, info);
+ if (err < 0)
+ return err;
+ }
+
+ if (!(status & QCA_SYSCFG_UPDATED)) {
+ err = btusb_setup_qca_load_nvm(hdev, &ver, info);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -2781,6 +3045,11 @@ static int btusb_probe(struct usb_interface *intf,
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
}
+ if (id->driver_info & BTUSB_QCA_ROME) {
+ data->setup_on_usb = btusb_setup_qca;
+ hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
+ }
+
if (id->driver_info & BTUSB_AMP) {
/* AMP controllers do not support SCO packets */
data->isoc = NULL;
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index 1d438bc..b64c5c7 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -19,6 +19,8 @@
*/
#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>
@@ -52,11 +54,21 @@ struct at86rf2xx_chip_data {
int (*get_desense_steps)(struct at86rf230_local *, s32);
};
-#define AT86RF2XX_MAX_BUF (127 + 3)
+#define AT86RF2XX_MAX_BUF (127 + 3)
+/* tx retries to access the TX_ON state
+ * if it's above then force change will be started.
+ *
+ * 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;
+ int irq;
+ struct hrtimer timer;
struct spi_message msg;
struct spi_transfer trx;
u8 buf[AT86RF2XX_MAX_BUF];
@@ -81,10 +93,12 @@ 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 */
spinlock_t lock;
+ u8 tx_retry;
struct sk_buff *tx_skb;
struct at86rf230_state_change tx;
};
@@ -407,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;
@@ -470,18 +486,25 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg,
u8 *tx_buf = ctx->buf;
tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
- ctx->trx.len = 2;
ctx->msg.complete = complete;
ctx->irq_enable = irq_enable;
rc = spi_async(lp->spi, &ctx->msg);
if (rc) {
if (irq_enable)
- enable_irq(lp->spi->irq);
+ enable_irq(ctx->irq);
at86rf230_async_error(lp, ctx, rc);
}
}
+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)
{
@@ -512,10 +535,21 @@ at86rf230_async_state_assert(void *context)
* in STATE_BUSY_RX_AACK, we run a force state change
* to STATE_TX_ON. This is a timeout handling, if the
* transceiver stucks in STATE_BUSY_RX_AACK.
+ *
+ * Additional we do several retries to try to get into
+ * TX_ON state without forcing. If the retries are
+ * higher or equal than AT86RF2XX_MAX_TX_RETRIES we
+ * will do a force change.
*/
- if (ctx->to_state == STATE_TX_ON) {
- at86rf230_async_state_change(lp, ctx,
- STATE_FORCE_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 = at86rf230_state_to_force(state);
+ lp->tx_retry++;
+
+ at86rf230_async_state_change(lp, ctx, state,
ctx->complete,
ctx->irq_enable);
return;
@@ -531,6 +565,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)
@@ -539,6 +586,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
@@ -562,11 +610,15 @@ 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);
+ /* 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;
@@ -574,14 +626,15 @@ 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) {
- 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;
@@ -593,7 +646,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;
@@ -604,12 +657,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
@@ -645,12 +696,11 @@ at86rf230_async_state_change_start(void *context)
*/
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);
+ enable_irq(ctx->irq);
at86rf230_async_error(lp, ctx, rc);
}
@@ -708,11 +758,10 @@ at86rf230_tx_complete(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- struct sk_buff *skb = lp->tx_skb;
- enable_irq(lp->spi->irq);
+ enable_irq(ctx->irq);
- ieee802154_xmit_complete(lp->hw, skb, !lp->tx_aret);
+ ieee802154_xmit_complete(lp->hw, lp->tx_skb, !lp->tx_aret);
}
static void
@@ -721,7 +770,7 @@ at86rf230_tx_on(void *context)
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
+ at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
at86rf230_tx_complete, true);
}
@@ -765,14 +814,25 @@ at86rf230_tx_trac_status(void *context)
}
static void
-at86rf230_rx(struct at86rf230_local *lp,
- const u8 *data, const u8 len, const u8 lqi)
+at86rf230_rx_read_frame_complete(void *context)
{
- struct sk_buff *skb;
+ struct at86rf230_state_change *ctx = context;
+ struct at86rf230_local *lp = ctx->lp;
u8 rx_local_buf[AT86RF2XX_MAX_BUF];
+ const u8 *buf = ctx->buf;
+ struct sk_buff *skb;
+ u8 len, lqi;
- memcpy(rx_local_buf, data, len);
- enable_irq(lp->spi->irq);
+ len = buf[1];
+ if (!ieee802154_is_valid_psdu_len(len)) {
+ dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
+ len = IEEE802154_MTU;
+ }
+ lqi = buf[2 + len];
+
+ memcpy(rx_local_buf, buf + 2, len);
+ ctx->trx.len = 2;
+ enable_irq(ctx->irq);
skb = dev_alloc_skb(IEEE802154_MTU);
if (!skb) {
@@ -785,51 +845,34 @@ at86rf230_rx(struct at86rf230_local *lp,
}
static void
-at86rf230_rx_read_frame_complete(void *context)
+at86rf230_rx_read_frame(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- const u8 *buf = lp->irq.buf;
- u8 len = buf[1];
-
- if (!ieee802154_is_valid_psdu_len(len)) {
- dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
- len = IEEE802154_MTU;
- }
-
- at86rf230_rx(lp, buf + 2, len, buf[2 + len]);
-}
-
-static void
-at86rf230_rx_read_frame(struct at86rf230_local *lp)
-{
+ u8 *buf = ctx->buf;
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);
+ ctx->trx.len = AT86RF2XX_MAX_BUF;
+ ctx->msg.complete = at86rf230_rx_read_frame_complete;
+ rc = spi_async(lp->spi, &ctx->msg);
if (rc) {
- enable_irq(lp->spi->irq);
- at86rf230_async_error(lp, &lp->irq, rc);
+ ctx->trx.len = 2;
+ enable_irq(ctx->irq);
+ 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;
-
/* Possible check on trac status here. This could be useful to make
* some stats why receive is failed. Not used at the moment, but it's
* maybe timing relevant. Datasheet doesn't say anything about this.
* The programming guide say do it so.
*/
- at86rf230_rx_read_frame(lp);
+ at86rf230_rx_read_frame(context);
}
static void
@@ -862,13 +905,13 @@ at86rf230_irq_status(void *context)
{
struct at86rf230_state_change *ctx = context;
struct at86rf230_local *lp = ctx->lp;
- const u8 *buf = lp->irq.buf;
+ const u8 *buf = ctx->buf;
const u8 irq = buf[1];
if (irq & IRQ_TRX_END) {
at86rf230_irq_trx_end(lp);
} else {
- enable_irq(lp->spi->irq);
+ enable_irq(ctx->irq);
dev_err(&lp->spi->dev, "not supported irq %02x received\n",
irq);
}
@@ -884,7 +927,6 @@ static irqreturn_t at86rf230_isr(int irq, void *data)
disable_irq_nosync(irq);
buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG;
- ctx->trx.len = 2;
ctx->msg.complete = at86rf230_irq_status;
rc = spi_async(lp->spi, &ctx->msg);
if (rc) {
@@ -919,7 +961,7 @@ 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;
+ u8 *buf = ctx->buf;
int rc;
spin_lock(&lp->lock);
@@ -929,11 +971,13 @@ at86rf230_write_frame(void *context)
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)
+ ctx->trx.len = skb->len + 2;
+ ctx->msg.complete = at86rf230_write_frame_complete;
+ rc = spi_async(lp->spi, &ctx->msg);
+ if (rc) {
+ ctx->trx.len = 2;
at86rf230_async_error(lp, ctx, rc);
+ }
}
static void
@@ -946,24 +990,45 @@ at86rf230_xmit_tx_on(void *context)
at86rf230_write_frame, false);
}
+static void
+at86rf230_xmit_start(void *context)
+{
+ 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)
+ 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;
- void (*tx_complete)(void *context) = at86rf230_write_frame;
-
lp->tx_skb = skb;
+ lp->tx_retry = 0;
- /* 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.
+ /* 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 (lp->tx_aret)
- tx_complete = at86rf230_xmit_tx_on;
-
- at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false);
+ 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;
}
@@ -979,6 +1044,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);
}
@@ -1059,6 +1127,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;
}
@@ -1528,25 +1598,37 @@ static void
at86rf230_setup_spi_messages(struct at86rf230_local *lp)
{
lp->state.lp = lp;
+ lp->state.irq = lp->spi->irq;
spi_message_init(&lp->state.msg);
lp->state.msg.context = &lp->state;
+ lp->state.trx.len = 2;
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;
spi_message_init(&lp->irq.msg);
lp->irq.msg.context = &lp->irq;
+ lp->irq.trx.len = 2;
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;
spi_message_init(&lp->tx.msg);
lp->tx.msg.context = &lp->tx;
+ lp->tx.trx.len = 2;
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)
@@ -1555,7 +1637,7 @@ static int at86rf230_probe(struct spi_device *spi)
struct at86rf230_local *lp;
unsigned int status;
int rc, irq_type, rstn, slp_tr;
- u8 xtal_trim;
+ u8 xtal_trim = 0;
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ specified\n");
OpenPOWER on IntegriCloud