18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * atusb.c - Driver for the ATUSB IEEE 802.15.4 dongle
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Written 2013 by Werner Almesberger <werner@almesberger.net>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2015 - 2016 Stefan Schmidt <stefan@datenfreihafen.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Based on at86rf230.c and spi_atusb.c.
108c2ecf20Sopenharmony_ci * at86rf230.c is
118c2ecf20Sopenharmony_ci * Copyright (C) 2009 Siemens AG
128c2ecf20Sopenharmony_ci * Written by: Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * spi_atusb.c is
158c2ecf20Sopenharmony_ci * Copyright (c) 2011 Richard Sharpe <realrichardsharpe@gmail.com>
168c2ecf20Sopenharmony_ci * Copyright (c) 2011 Stefan Schmidt <stefan@datenfreihafen.org>
178c2ecf20Sopenharmony_ci * Copyright (c) 2011 Werner Almesberger <werner@almesberger.net>
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * USB initialization is
208c2ecf20Sopenharmony_ci * Copyright (c) 2013 Alexander Aring <alex.aring@gmail.com>
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * Busware HUL support is
238c2ecf20Sopenharmony_ci * Copyright (c) 2017 Josef Filzmaier <j.filzmaier@gmx.at>
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/kernel.h>
278c2ecf20Sopenharmony_ci#include <linux/slab.h>
288c2ecf20Sopenharmony_ci#include <linux/module.h>
298c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
308c2ecf20Sopenharmony_ci#include <linux/usb.h>
318c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <net/cfg802154.h>
348c2ecf20Sopenharmony_ci#include <net/mac802154.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include "at86rf230.h"
378c2ecf20Sopenharmony_ci#include "atusb.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define ATUSB_JEDEC_ATMEL	0x1f	/* JEDEC manufacturer ID */
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define ATUSB_NUM_RX_URBS	4	/* allow for a bit of local latency */
428c2ecf20Sopenharmony_ci#define ATUSB_ALLOC_DELAY_MS	100	/* delay after failed allocation */
438c2ecf20Sopenharmony_ci#define ATUSB_TX_TIMEOUT_MS	200	/* on the air timeout */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct atusb {
468c2ecf20Sopenharmony_ci	struct ieee802154_hw *hw;
478c2ecf20Sopenharmony_ci	struct usb_device *usb_dev;
488c2ecf20Sopenharmony_ci	struct atusb_chip_data *data;
498c2ecf20Sopenharmony_ci	int shutdown;			/* non-zero if shutting down */
508c2ecf20Sopenharmony_ci	int err;			/* set by first error */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* RX variables */
538c2ecf20Sopenharmony_ci	struct delayed_work work;	/* memory allocations */
548c2ecf20Sopenharmony_ci	struct usb_anchor idle_urbs;	/* URBs waiting to be submitted */
558c2ecf20Sopenharmony_ci	struct usb_anchor rx_urbs;	/* URBs waiting for reception */
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/* TX variables */
588c2ecf20Sopenharmony_ci	struct usb_ctrlrequest tx_dr;
598c2ecf20Sopenharmony_ci	struct urb *tx_urb;
608c2ecf20Sopenharmony_ci	struct sk_buff *tx_skb;
618c2ecf20Sopenharmony_ci	u8 tx_ack_seq;		/* current TX ACK sequence number */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* Firmware variable */
648c2ecf20Sopenharmony_ci	unsigned char fw_ver_maj;	/* Firmware major version number */
658c2ecf20Sopenharmony_ci	unsigned char fw_ver_min;	/* Firmware minor version number */
668c2ecf20Sopenharmony_ci	unsigned char fw_hw_type;	/* Firmware hardware type */
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct atusb_chip_data {
708c2ecf20Sopenharmony_ci	u16 t_channel_switch;
718c2ecf20Sopenharmony_ci	int rssi_base_val;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	int (*set_channel)(struct ieee802154_hw*, u8, u8);
748c2ecf20Sopenharmony_ci	int (*set_txpower)(struct ieee802154_hw*, s32);
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* ----- USB commands without data ----------------------------------------- */
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/* To reduce the number of error checks in the code, we record the first error
808c2ecf20Sopenharmony_ci * in atusb->err and reject all subsequent requests until the error is cleared.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic int atusb_control_msg(struct atusb *atusb, unsigned int pipe,
848c2ecf20Sopenharmony_ci			     __u8 request, __u8 requesttype,
858c2ecf20Sopenharmony_ci			     __u16 value, __u16 index,
868c2ecf20Sopenharmony_ci			     void *data, __u16 size, int timeout)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
898c2ecf20Sopenharmony_ci	int ret;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (atusb->err)
928c2ecf20Sopenharmony_ci		return atusb->err;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	ret = usb_control_msg(usb_dev, pipe, request, requesttype,
958c2ecf20Sopenharmony_ci			      value, index, data, size, timeout);
968c2ecf20Sopenharmony_ci	if (ret < size) {
978c2ecf20Sopenharmony_ci		ret = ret < 0 ? ret : -ENODATA;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		atusb->err = ret;
1008c2ecf20Sopenharmony_ci		dev_err(&usb_dev->dev,
1018c2ecf20Sopenharmony_ci			"%s: req 0x%02x val 0x%x idx 0x%x, error %d\n",
1028c2ecf20Sopenharmony_ci			__func__, request, value, index, ret);
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	return ret;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int atusb_command(struct atusb *atusb, u8 cmd, u8 arg)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s: cmd = 0x%x\n", __func__, cmd);
1128c2ecf20Sopenharmony_ci	return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0),
1138c2ecf20Sopenharmony_ci				 cmd, ATUSB_REQ_TO_DEV, arg, 0, NULL, 0, 1000);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic int atusb_write_reg(struct atusb *atusb, u8 reg, u8 value)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s: 0x%02x <- 0x%02x\n", __func__, reg, value);
1218c2ecf20Sopenharmony_ci	return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0),
1228c2ecf20Sopenharmony_ci				 ATUSB_REG_WRITE, ATUSB_REQ_TO_DEV,
1238c2ecf20Sopenharmony_ci				 value, reg, NULL, 0, 1000);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic int atusb_read_reg(struct atusb *atusb, u8 reg)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
1298c2ecf20Sopenharmony_ci	int ret;
1308c2ecf20Sopenharmony_ci	u8 *buffer;
1318c2ecf20Sopenharmony_ci	u8 value;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	buffer = kmalloc(1, GFP_KERNEL);
1348c2ecf20Sopenharmony_ci	if (!buffer)
1358c2ecf20Sopenharmony_ci		return -ENOMEM;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s: reg = 0x%x\n", __func__, reg);
1388c2ecf20Sopenharmony_ci	ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
1398c2ecf20Sopenharmony_ci				ATUSB_REG_READ, ATUSB_REQ_FROM_DEV,
1408c2ecf20Sopenharmony_ci				0, reg, buffer, 1, 1000);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (ret >= 0) {
1438c2ecf20Sopenharmony_ci		value = buffer[0];
1448c2ecf20Sopenharmony_ci		kfree(buffer);
1458c2ecf20Sopenharmony_ci		return value;
1468c2ecf20Sopenharmony_ci	} else {
1478c2ecf20Sopenharmony_ci		kfree(buffer);
1488c2ecf20Sopenharmony_ci		return ret;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int atusb_write_subreg(struct atusb *atusb, u8 reg, u8 mask,
1538c2ecf20Sopenharmony_ci			      u8 shift, u8 value)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
1568c2ecf20Sopenharmony_ci	u8 orig, tmp;
1578c2ecf20Sopenharmony_ci	int ret = 0;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s: 0x%02x <- 0x%02x\n", __func__, reg, value);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	orig = atusb_read_reg(atusb, reg);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* Write the value only into that part of the register which is allowed
1648c2ecf20Sopenharmony_ci	 * by the mask. All other bits stay as before.
1658c2ecf20Sopenharmony_ci	 */
1668c2ecf20Sopenharmony_ci	tmp = orig & ~mask;
1678c2ecf20Sopenharmony_ci	tmp |= (value << shift) & mask;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (tmp != orig)
1708c2ecf20Sopenharmony_ci		ret = atusb_write_reg(atusb, reg, tmp);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return ret;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic int atusb_read_subreg(struct atusb *lp,
1768c2ecf20Sopenharmony_ci			     unsigned int addr, unsigned int mask,
1778c2ecf20Sopenharmony_ci			     unsigned int shift)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int rc;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	rc = atusb_read_reg(lp, addr);
1828c2ecf20Sopenharmony_ci	rc = (rc & mask) >> shift;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return rc;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int atusb_get_and_clear_error(struct atusb *atusb)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	int err = atusb->err;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	atusb->err = 0;
1928c2ecf20Sopenharmony_ci	return err;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/* ----- skb allocation ---------------------------------------------------- */
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci#define MAX_PSDU	127
1988c2ecf20Sopenharmony_ci#define MAX_RX_XFER	(1 + MAX_PSDU + 2 + 1)	/* PHR+PSDU+CRC+LQI */
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci#define SKB_ATUSB(skb)	(*(struct atusb **)(skb)->cb)
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic void atusb_in(struct urb *urb);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int atusb_submit_rx_urb(struct atusb *atusb, struct urb *urb)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
2078c2ecf20Sopenharmony_ci	struct sk_buff *skb = urb->context;
2088c2ecf20Sopenharmony_ci	int ret;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (!skb) {
2118c2ecf20Sopenharmony_ci		skb = alloc_skb(MAX_RX_XFER, GFP_KERNEL);
2128c2ecf20Sopenharmony_ci		if (!skb) {
2138c2ecf20Sopenharmony_ci			dev_warn_ratelimited(&usb_dev->dev,
2148c2ecf20Sopenharmony_ci					     "atusb_in: can't allocate skb\n");
2158c2ecf20Sopenharmony_ci			return -ENOMEM;
2168c2ecf20Sopenharmony_ci		}
2178c2ecf20Sopenharmony_ci		skb_put(skb, MAX_RX_XFER);
2188c2ecf20Sopenharmony_ci		SKB_ATUSB(skb) = atusb;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	usb_fill_bulk_urb(urb, usb_dev, usb_rcvbulkpipe(usb_dev, 1),
2228c2ecf20Sopenharmony_ci			  skb->data, MAX_RX_XFER, atusb_in, skb);
2238c2ecf20Sopenharmony_ci	usb_anchor_urb(urb, &atusb->rx_urbs);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	ret = usb_submit_urb(urb, GFP_KERNEL);
2268c2ecf20Sopenharmony_ci	if (ret) {
2278c2ecf20Sopenharmony_ci		usb_unanchor_urb(urb);
2288c2ecf20Sopenharmony_ci		kfree_skb(skb);
2298c2ecf20Sopenharmony_ci		urb->context = NULL;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci	return ret;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic void atusb_work_urbs(struct work_struct *work)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct atusb *atusb =
2378c2ecf20Sopenharmony_ci	    container_of(to_delayed_work(work), struct atusb, work);
2388c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
2398c2ecf20Sopenharmony_ci	struct urb *urb;
2408c2ecf20Sopenharmony_ci	int ret;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (atusb->shutdown)
2438c2ecf20Sopenharmony_ci		return;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	do {
2468c2ecf20Sopenharmony_ci		urb = usb_get_from_anchor(&atusb->idle_urbs);
2478c2ecf20Sopenharmony_ci		if (!urb)
2488c2ecf20Sopenharmony_ci			return;
2498c2ecf20Sopenharmony_ci		ret = atusb_submit_rx_urb(atusb, urb);
2508c2ecf20Sopenharmony_ci	} while (!ret);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	usb_anchor_urb(urb, &atusb->idle_urbs);
2538c2ecf20Sopenharmony_ci	dev_warn_ratelimited(&usb_dev->dev,
2548c2ecf20Sopenharmony_ci			     "atusb_in: can't allocate/submit URB (%d)\n", ret);
2558c2ecf20Sopenharmony_ci	schedule_delayed_work(&atusb->work,
2568c2ecf20Sopenharmony_ci			      msecs_to_jiffies(ATUSB_ALLOC_DELAY_MS) + 1);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/* ----- Asynchronous USB -------------------------------------------------- */
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic void atusb_tx_done(struct atusb *atusb, u8 seq)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
2648c2ecf20Sopenharmony_ci	u8 expect = atusb->tx_ack_seq;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s (0x%02x/0x%02x)\n", __func__, seq, expect);
2678c2ecf20Sopenharmony_ci	if (seq == expect) {
2688c2ecf20Sopenharmony_ci		/* TODO check for ifs handling in firmware */
2698c2ecf20Sopenharmony_ci		ieee802154_xmit_complete(atusb->hw, atusb->tx_skb, false);
2708c2ecf20Sopenharmony_ci	} else {
2718c2ecf20Sopenharmony_ci		/* TODO I experience this case when atusb has a tx complete
2728c2ecf20Sopenharmony_ci		 * irq before probing, we should fix the firmware it's an
2738c2ecf20Sopenharmony_ci		 * unlikely case now that seq == expect is then true, but can
2748c2ecf20Sopenharmony_ci		 * happen and fail with a tx_skb = NULL;
2758c2ecf20Sopenharmony_ci		 */
2768c2ecf20Sopenharmony_ci		ieee802154_wake_queue(atusb->hw);
2778c2ecf20Sopenharmony_ci		if (atusb->tx_skb)
2788c2ecf20Sopenharmony_ci			dev_kfree_skb_irq(atusb->tx_skb);
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic void atusb_in_good(struct urb *urb)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = urb->dev;
2858c2ecf20Sopenharmony_ci	struct sk_buff *skb = urb->context;
2868c2ecf20Sopenharmony_ci	struct atusb *atusb = SKB_ATUSB(skb);
2878c2ecf20Sopenharmony_ci	u8 len, lqi;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (!urb->actual_length) {
2908c2ecf20Sopenharmony_ci		dev_dbg(&usb_dev->dev, "atusb_in: zero-sized URB ?\n");
2918c2ecf20Sopenharmony_ci		return;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	len = *skb->data;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (urb->actual_length == 1) {
2978c2ecf20Sopenharmony_ci		atusb_tx_done(atusb, len);
2988c2ecf20Sopenharmony_ci		return;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (len + 1 > urb->actual_length - 1) {
3028c2ecf20Sopenharmony_ci		dev_dbg(&usb_dev->dev, "atusb_in: frame len %d+1 > URB %u-1\n",
3038c2ecf20Sopenharmony_ci			len, urb->actual_length);
3048c2ecf20Sopenharmony_ci		return;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (!ieee802154_is_valid_psdu_len(len)) {
3088c2ecf20Sopenharmony_ci		dev_dbg(&usb_dev->dev, "atusb_in: frame corrupted\n");
3098c2ecf20Sopenharmony_ci		return;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	lqi = skb->data[len + 1];
3138c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "atusb_in: rx len %d lqi 0x%02x\n", len, lqi);
3148c2ecf20Sopenharmony_ci	skb_pull(skb, 1);	/* remove PHR */
3158c2ecf20Sopenharmony_ci	skb_trim(skb, len);	/* get payload only */
3168c2ecf20Sopenharmony_ci	ieee802154_rx_irqsafe(atusb->hw, skb, lqi);
3178c2ecf20Sopenharmony_ci	urb->context = NULL;	/* skb is gone */
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic void atusb_in(struct urb *urb)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = urb->dev;
3238c2ecf20Sopenharmony_ci	struct sk_buff *skb = urb->context;
3248c2ecf20Sopenharmony_ci	struct atusb *atusb = SKB_ATUSB(skb);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s: status %d len %d\n", __func__,
3278c2ecf20Sopenharmony_ci		urb->status, urb->actual_length);
3288c2ecf20Sopenharmony_ci	if (urb->status) {
3298c2ecf20Sopenharmony_ci		if (urb->status == -ENOENT) { /* being killed */
3308c2ecf20Sopenharmony_ci			kfree_skb(skb);
3318c2ecf20Sopenharmony_ci			urb->context = NULL;
3328c2ecf20Sopenharmony_ci			return;
3338c2ecf20Sopenharmony_ci		}
3348c2ecf20Sopenharmony_ci		dev_dbg(&usb_dev->dev, "%s: URB error %d\n", __func__, urb->status);
3358c2ecf20Sopenharmony_ci	} else {
3368c2ecf20Sopenharmony_ci		atusb_in_good(urb);
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	usb_anchor_urb(urb, &atusb->idle_urbs);
3408c2ecf20Sopenharmony_ci	if (!atusb->shutdown)
3418c2ecf20Sopenharmony_ci		schedule_delayed_work(&atusb->work, 0);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/* ----- URB allocation/deallocation --------------------------------------- */
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void atusb_free_urbs(struct atusb *atusb)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct urb *urb;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	while (1) {
3518c2ecf20Sopenharmony_ci		urb = usb_get_from_anchor(&atusb->idle_urbs);
3528c2ecf20Sopenharmony_ci		if (!urb)
3538c2ecf20Sopenharmony_ci			break;
3548c2ecf20Sopenharmony_ci		kfree_skb(urb->context);
3558c2ecf20Sopenharmony_ci		usb_free_urb(urb);
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic int atusb_alloc_urbs(struct atusb *atusb, int n)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct urb *urb;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	while (n) {
3648c2ecf20Sopenharmony_ci		urb = usb_alloc_urb(0, GFP_KERNEL);
3658c2ecf20Sopenharmony_ci		if (!urb) {
3668c2ecf20Sopenharmony_ci			atusb_free_urbs(atusb);
3678c2ecf20Sopenharmony_ci			return -ENOMEM;
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci		usb_anchor_urb(urb, &atusb->idle_urbs);
3708c2ecf20Sopenharmony_ci		usb_free_urb(urb);
3718c2ecf20Sopenharmony_ci		n--;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci	return 0;
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci/* ----- IEEE 802.15.4 interface operations -------------------------------- */
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic void atusb_xmit_complete(struct urb *urb)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	dev_dbg(&urb->dev->dev, "atusb_xmit urb completed");
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int atusb_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
3868c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
3878c2ecf20Sopenharmony_ci	int ret;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s (%d)\n", __func__, skb->len);
3908c2ecf20Sopenharmony_ci	atusb->tx_skb = skb;
3918c2ecf20Sopenharmony_ci	atusb->tx_ack_seq++;
3928c2ecf20Sopenharmony_ci	atusb->tx_dr.wIndex = cpu_to_le16(atusb->tx_ack_seq);
3938c2ecf20Sopenharmony_ci	atusb->tx_dr.wLength = cpu_to_le16(skb->len);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	usb_fill_control_urb(atusb->tx_urb, usb_dev,
3968c2ecf20Sopenharmony_ci			     usb_sndctrlpipe(usb_dev, 0),
3978c2ecf20Sopenharmony_ci			     (unsigned char *)&atusb->tx_dr, skb->data,
3988c2ecf20Sopenharmony_ci			     skb->len, atusb_xmit_complete, NULL);
3998c2ecf20Sopenharmony_ci	ret = usb_submit_urb(atusb->tx_urb, GFP_ATOMIC);
4008c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s done (%d)\n", __func__, ret);
4018c2ecf20Sopenharmony_ci	return ret;
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic int atusb_ed(struct ieee802154_hw *hw, u8 *level)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	WARN_ON(!level);
4078c2ecf20Sopenharmony_ci	*level = 0xbe;
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic int atusb_set_hw_addr_filt(struct ieee802154_hw *hw,
4128c2ecf20Sopenharmony_ci				  struct ieee802154_hw_addr_filt *filt,
4138c2ecf20Sopenharmony_ci				  unsigned long changed)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
4168c2ecf20Sopenharmony_ci	struct device *dev = &atusb->usb_dev->dev;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
4198c2ecf20Sopenharmony_ci		u16 addr = le16_to_cpu(filt->short_addr);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		dev_vdbg(dev, "%s called for saddr\n", __func__);
4228c2ecf20Sopenharmony_ci		atusb_write_reg(atusb, RG_SHORT_ADDR_0, addr);
4238c2ecf20Sopenharmony_ci		atusb_write_reg(atusb, RG_SHORT_ADDR_1, addr >> 8);
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (changed & IEEE802154_AFILT_PANID_CHANGED) {
4278c2ecf20Sopenharmony_ci		u16 pan = le16_to_cpu(filt->pan_id);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		dev_vdbg(dev, "%s called for pan id\n", __func__);
4308c2ecf20Sopenharmony_ci		atusb_write_reg(atusb, RG_PAN_ID_0, pan);
4318c2ecf20Sopenharmony_ci		atusb_write_reg(atusb, RG_PAN_ID_1, pan >> 8);
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
4358c2ecf20Sopenharmony_ci		u8 i, addr[IEEE802154_EXTENDED_ADDR_LEN];
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		memcpy(addr, &filt->ieee_addr, IEEE802154_EXTENDED_ADDR_LEN);
4388c2ecf20Sopenharmony_ci		dev_vdbg(dev, "%s called for IEEE addr\n", __func__);
4398c2ecf20Sopenharmony_ci		for (i = 0; i < 8; i++)
4408c2ecf20Sopenharmony_ci			atusb_write_reg(atusb, RG_IEEE_ADDR_0 + i, addr[i]);
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
4448c2ecf20Sopenharmony_ci		dev_vdbg(dev, "%s called for panc change\n", __func__);
4458c2ecf20Sopenharmony_ci		if (filt->pan_coord)
4468c2ecf20Sopenharmony_ci			atusb_write_subreg(atusb, SR_AACK_I_AM_COORD, 1);
4478c2ecf20Sopenharmony_ci		else
4488c2ecf20Sopenharmony_ci			atusb_write_subreg(atusb, SR_AACK_I_AM_COORD, 0);
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	return atusb_get_and_clear_error(atusb);
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int atusb_start(struct ieee802154_hw *hw)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
4578c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
4588c2ecf20Sopenharmony_ci	int ret;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s\n", __func__);
4618c2ecf20Sopenharmony_ci	schedule_delayed_work(&atusb->work, 0);
4628c2ecf20Sopenharmony_ci	atusb_command(atusb, ATUSB_RX_MODE, 1);
4638c2ecf20Sopenharmony_ci	ret = atusb_get_and_clear_error(atusb);
4648c2ecf20Sopenharmony_ci	if (ret < 0)
4658c2ecf20Sopenharmony_ci		usb_kill_anchored_urbs(&atusb->idle_urbs);
4668c2ecf20Sopenharmony_ci	return ret;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic void atusb_stop(struct ieee802154_hw *hw)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
4728c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	dev_dbg(&usb_dev->dev, "%s\n", __func__);
4758c2ecf20Sopenharmony_ci	usb_kill_anchored_urbs(&atusb->idle_urbs);
4768c2ecf20Sopenharmony_ci	atusb_command(atusb, ATUSB_RX_MODE, 0);
4778c2ecf20Sopenharmony_ci	atusb_get_and_clear_error(atusb);
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci#define ATUSB_MAX_TX_POWERS 0xF
4818c2ecf20Sopenharmony_cistatic const s32 atusb_powers[ATUSB_MAX_TX_POWERS + 1] = {
4828c2ecf20Sopenharmony_ci	300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700,
4838c2ecf20Sopenharmony_ci	-900, -1200, -1700,
4848c2ecf20Sopenharmony_ci};
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic int
4878c2ecf20Sopenharmony_ciatusb_txpower(struct ieee802154_hw *hw, s32 mbm)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	if (atusb->data)
4928c2ecf20Sopenharmony_ci		return atusb->data->set_txpower(hw, mbm);
4938c2ecf20Sopenharmony_ci	else
4948c2ecf20Sopenharmony_ci		return -ENOTSUPP;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic int
4988c2ecf20Sopenharmony_ciatusb_set_txpower(struct ieee802154_hw *hw, s32 mbm)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
5018c2ecf20Sopenharmony_ci	u32 i;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	for (i = 0; i < hw->phy->supported.tx_powers_size; i++) {
5048c2ecf20Sopenharmony_ci		if (hw->phy->supported.tx_powers[i] == mbm)
5058c2ecf20Sopenharmony_ci			return atusb_write_subreg(atusb, SR_TX_PWR_23X, i);
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	return -EINVAL;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic int
5128c2ecf20Sopenharmony_cihulusb_set_txpower(struct ieee802154_hw *hw, s32 mbm)
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	u32 i;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	for (i = 0; i < hw->phy->supported.tx_powers_size; i++) {
5178c2ecf20Sopenharmony_ci		if (hw->phy->supported.tx_powers[i] == mbm)
5188c2ecf20Sopenharmony_ci			return atusb_write_subreg(hw->priv, SR_TX_PWR_212, i);
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	return -EINVAL;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci#define ATUSB_MAX_ED_LEVELS 0xF
5258c2ecf20Sopenharmony_cistatic const s32 atusb_ed_levels[ATUSB_MAX_ED_LEVELS + 1] = {
5268c2ecf20Sopenharmony_ci	-9100, -8900, -8700, -8500, -8300, -8100, -7900, -7700, -7500, -7300,
5278c2ecf20Sopenharmony_ci	-7100, -6900, -6700, -6500, -6300, -6100,
5288c2ecf20Sopenharmony_ci};
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci#define AT86RF212_MAX_TX_POWERS 0x1F
5318c2ecf20Sopenharmony_cistatic const s32 at86rf212_powers[AT86RF212_MAX_TX_POWERS + 1] = {
5328c2ecf20Sopenharmony_ci	500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700,
5338c2ecf20Sopenharmony_ci	-800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
5348c2ecf20Sopenharmony_ci	-1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
5358c2ecf20Sopenharmony_ci};
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci#define AT86RF2XX_MAX_ED_LEVELS 0xF
5388c2ecf20Sopenharmony_cistatic const s32 at86rf212_ed_levels_100[AT86RF2XX_MAX_ED_LEVELS + 1] = {
5398c2ecf20Sopenharmony_ci	-10000, -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200,
5408c2ecf20Sopenharmony_ci	-8000, -7800, -7600, -7400, -7200, -7000,
5418c2ecf20Sopenharmony_ci};
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic const s32 at86rf212_ed_levels_98[AT86RF2XX_MAX_ED_LEVELS + 1] = {
5448c2ecf20Sopenharmony_ci	-9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000,
5458c2ecf20Sopenharmony_ci	-7800, -7600, -7400, -7200, -7000, -6800,
5468c2ecf20Sopenharmony_ci};
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic int
5498c2ecf20Sopenharmony_ciatusb_set_cca_mode(struct ieee802154_hw *hw, const struct wpan_phy_cca *cca)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
5528c2ecf20Sopenharmony_ci	u8 val;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	/* mapping 802.15.4 to driver spec */
5558c2ecf20Sopenharmony_ci	switch (cca->mode) {
5568c2ecf20Sopenharmony_ci	case NL802154_CCA_ENERGY:
5578c2ecf20Sopenharmony_ci		val = 1;
5588c2ecf20Sopenharmony_ci		break;
5598c2ecf20Sopenharmony_ci	case NL802154_CCA_CARRIER:
5608c2ecf20Sopenharmony_ci		val = 2;
5618c2ecf20Sopenharmony_ci		break;
5628c2ecf20Sopenharmony_ci	case NL802154_CCA_ENERGY_CARRIER:
5638c2ecf20Sopenharmony_ci		switch (cca->opt) {
5648c2ecf20Sopenharmony_ci		case NL802154_CCA_OPT_ENERGY_CARRIER_AND:
5658c2ecf20Sopenharmony_ci			val = 3;
5668c2ecf20Sopenharmony_ci			break;
5678c2ecf20Sopenharmony_ci		case NL802154_CCA_OPT_ENERGY_CARRIER_OR:
5688c2ecf20Sopenharmony_ci			val = 0;
5698c2ecf20Sopenharmony_ci			break;
5708c2ecf20Sopenharmony_ci		default:
5718c2ecf20Sopenharmony_ci			return -EINVAL;
5728c2ecf20Sopenharmony_ci		}
5738c2ecf20Sopenharmony_ci		break;
5748c2ecf20Sopenharmony_ci	default:
5758c2ecf20Sopenharmony_ci		return -EINVAL;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	return atusb_write_subreg(atusb, SR_CCA_MODE, val);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic int hulusb_set_cca_ed_level(struct atusb *lp, int rssi_base_val)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	unsigned int cca_ed_thres;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	cca_ed_thres = atusb_read_subreg(lp, SR_CCA_ED_THRES);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	switch (rssi_base_val) {
5888c2ecf20Sopenharmony_ci	case -98:
5898c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_98;
5908c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_98);
5918c2ecf20Sopenharmony_ci		lp->hw->phy->cca_ed_level = at86rf212_ed_levels_98[cca_ed_thres];
5928c2ecf20Sopenharmony_ci		break;
5938c2ecf20Sopenharmony_ci	case -100:
5948c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100;
5958c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100);
5968c2ecf20Sopenharmony_ci		lp->hw->phy->cca_ed_level = at86rf212_ed_levels_100[cca_ed_thres];
5978c2ecf20Sopenharmony_ci		break;
5988c2ecf20Sopenharmony_ci	default:
5998c2ecf20Sopenharmony_ci		WARN_ON(1);
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	return 0;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic int
6068c2ecf20Sopenharmony_ciatusb_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
6098c2ecf20Sopenharmony_ci	u32 i;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) {
6128c2ecf20Sopenharmony_ci		if (hw->phy->supported.cca_ed_levels[i] == mbm)
6138c2ecf20Sopenharmony_ci			return atusb_write_subreg(atusb, SR_CCA_ED_THRES, i);
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	return -EINVAL;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic int atusb_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
6228c2ecf20Sopenharmony_ci	int ret = -ENOTSUPP;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	if (atusb->data) {
6258c2ecf20Sopenharmony_ci		ret = atusb->data->set_channel(hw, page, channel);
6268c2ecf20Sopenharmony_ci		/* @@@ ugly synchronization */
6278c2ecf20Sopenharmony_ci		msleep(atusb->data->t_channel_switch);
6288c2ecf20Sopenharmony_ci	}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	return ret;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic int atusb_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
6368c2ecf20Sopenharmony_ci	int ret;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	ret = atusb_write_subreg(atusb, SR_CHANNEL, channel);
6398c2ecf20Sopenharmony_ci	if (ret < 0)
6408c2ecf20Sopenharmony_ci		return ret;
6418c2ecf20Sopenharmony_ci	return 0;
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic int hulusb_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	int rc;
6478c2ecf20Sopenharmony_ci	int rssi_base_val;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	struct atusb *lp = hw->priv;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	if (channel == 0)
6528c2ecf20Sopenharmony_ci		rc = atusb_write_subreg(lp, SR_SUB_MODE, 0);
6538c2ecf20Sopenharmony_ci	else
6548c2ecf20Sopenharmony_ci		rc = atusb_write_subreg(lp, SR_SUB_MODE, 1);
6558c2ecf20Sopenharmony_ci	if (rc < 0)
6568c2ecf20Sopenharmony_ci		return rc;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	if (page == 0) {
6598c2ecf20Sopenharmony_ci		rc = atusb_write_subreg(lp, SR_BPSK_QPSK, 0);
6608c2ecf20Sopenharmony_ci		rssi_base_val = -100;
6618c2ecf20Sopenharmony_ci	} else {
6628c2ecf20Sopenharmony_ci		rc = atusb_write_subreg(lp, SR_BPSK_QPSK, 1);
6638c2ecf20Sopenharmony_ci		rssi_base_val = -98;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci	if (rc < 0)
6668c2ecf20Sopenharmony_ci		return rc;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	rc = hulusb_set_cca_ed_level(lp, rssi_base_val);
6698c2ecf20Sopenharmony_ci	if (rc < 0)
6708c2ecf20Sopenharmony_ci		return rc;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/* This sets the symbol_duration according frequency on the 212.
6738c2ecf20Sopenharmony_ci	 * TODO move this handling while set channel and page in cfg802154.
6748c2ecf20Sopenharmony_ci	 * We can do that, this timings are according 802.15.4 standard.
6758c2ecf20Sopenharmony_ci	 * If we do that in cfg802154, this is a more generic calculation.
6768c2ecf20Sopenharmony_ci	 *
6778c2ecf20Sopenharmony_ci	 * This should also protected from ifs_timer. Means cancel timer and
6788c2ecf20Sopenharmony_ci	 * init with a new value. For now, this is okay.
6798c2ecf20Sopenharmony_ci	 */
6808c2ecf20Sopenharmony_ci	if (channel == 0) {
6818c2ecf20Sopenharmony_ci		if (page == 0) {
6828c2ecf20Sopenharmony_ci			/* SUB:0 and BPSK:0 -> BPSK-20 */
6838c2ecf20Sopenharmony_ci			lp->hw->phy->symbol_duration = 50;
6848c2ecf20Sopenharmony_ci		} else {
6858c2ecf20Sopenharmony_ci			/* SUB:1 and BPSK:0 -> BPSK-40 */
6868c2ecf20Sopenharmony_ci			lp->hw->phy->symbol_duration = 25;
6878c2ecf20Sopenharmony_ci		}
6888c2ecf20Sopenharmony_ci	} else {
6898c2ecf20Sopenharmony_ci		if (page == 0)
6908c2ecf20Sopenharmony_ci			/* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
6918c2ecf20Sopenharmony_ci			lp->hw->phy->symbol_duration = 40;
6928c2ecf20Sopenharmony_ci		else
6938c2ecf20Sopenharmony_ci			/* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
6948c2ecf20Sopenharmony_ci			lp->hw->phy->symbol_duration = 16;
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	lp->hw->phy->lifs_period = IEEE802154_LIFS_PERIOD *
6988c2ecf20Sopenharmony_ci				   lp->hw->phy->symbol_duration;
6998c2ecf20Sopenharmony_ci	lp->hw->phy->sifs_period = IEEE802154_SIFS_PERIOD *
7008c2ecf20Sopenharmony_ci				   lp->hw->phy->symbol_duration;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	return atusb_write_subreg(lp, SR_CHANNEL, channel);
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_cistatic int
7068c2ecf20Sopenharmony_ciatusb_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be, u8 retries)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
7098c2ecf20Sopenharmony_ci	int ret;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	ret = atusb_write_subreg(atusb, SR_MIN_BE, min_be);
7128c2ecf20Sopenharmony_ci	if (ret)
7138c2ecf20Sopenharmony_ci		return ret;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	ret = atusb_write_subreg(atusb, SR_MAX_BE, max_be);
7168c2ecf20Sopenharmony_ci	if (ret)
7178c2ecf20Sopenharmony_ci		return ret;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	return atusb_write_subreg(atusb, SR_MAX_CSMA_RETRIES, retries);
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic int
7238c2ecf20Sopenharmony_cihulusb_set_lbt(struct ieee802154_hw *hw, bool on)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	return atusb_write_subreg(atusb, SR_CSMA_LBT_MODE, on);
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cistatic int
7318c2ecf20Sopenharmony_ciatusb_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	return atusb_write_subreg(atusb, SR_MAX_FRAME_RETRIES, retries);
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic int
7398c2ecf20Sopenharmony_ciatusb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	struct atusb *atusb = hw->priv;
7428c2ecf20Sopenharmony_ci	int ret;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	if (on) {
7458c2ecf20Sopenharmony_ci		ret = atusb_write_subreg(atusb, SR_AACK_DIS_ACK, 1);
7468c2ecf20Sopenharmony_ci		if (ret < 0)
7478c2ecf20Sopenharmony_ci			return ret;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		ret = atusb_write_subreg(atusb, SR_AACK_PROM_MODE, 1);
7508c2ecf20Sopenharmony_ci		if (ret < 0)
7518c2ecf20Sopenharmony_ci			return ret;
7528c2ecf20Sopenharmony_ci	} else {
7538c2ecf20Sopenharmony_ci		ret = atusb_write_subreg(atusb, SR_AACK_PROM_MODE, 0);
7548c2ecf20Sopenharmony_ci		if (ret < 0)
7558c2ecf20Sopenharmony_ci			return ret;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci		ret = atusb_write_subreg(atusb, SR_AACK_DIS_ACK, 0);
7588c2ecf20Sopenharmony_ci		if (ret < 0)
7598c2ecf20Sopenharmony_ci			return ret;
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	return 0;
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic struct atusb_chip_data atusb_chip_data = {
7668c2ecf20Sopenharmony_ci	.t_channel_switch = 1,
7678c2ecf20Sopenharmony_ci	.rssi_base_val = -91,
7688c2ecf20Sopenharmony_ci	.set_txpower = atusb_set_txpower,
7698c2ecf20Sopenharmony_ci	.set_channel = atusb_set_channel,
7708c2ecf20Sopenharmony_ci};
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic struct atusb_chip_data hulusb_chip_data = {
7738c2ecf20Sopenharmony_ci	.t_channel_switch = 11,
7748c2ecf20Sopenharmony_ci	.rssi_base_val = -100,
7758c2ecf20Sopenharmony_ci	.set_txpower = hulusb_set_txpower,
7768c2ecf20Sopenharmony_ci	.set_channel = hulusb_set_channel,
7778c2ecf20Sopenharmony_ci};
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_cistatic const struct ieee802154_ops atusb_ops = {
7808c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
7818c2ecf20Sopenharmony_ci	.xmit_async		= atusb_xmit,
7828c2ecf20Sopenharmony_ci	.ed			= atusb_ed,
7838c2ecf20Sopenharmony_ci	.set_channel		= atusb_channel,
7848c2ecf20Sopenharmony_ci	.start			= atusb_start,
7858c2ecf20Sopenharmony_ci	.stop			= atusb_stop,
7868c2ecf20Sopenharmony_ci	.set_hw_addr_filt	= atusb_set_hw_addr_filt,
7878c2ecf20Sopenharmony_ci	.set_txpower		= atusb_txpower,
7888c2ecf20Sopenharmony_ci	.set_lbt		= hulusb_set_lbt,
7898c2ecf20Sopenharmony_ci	.set_cca_mode		= atusb_set_cca_mode,
7908c2ecf20Sopenharmony_ci	.set_cca_ed_level	= atusb_set_cca_ed_level,
7918c2ecf20Sopenharmony_ci	.set_csma_params	= atusb_set_csma_params,
7928c2ecf20Sopenharmony_ci	.set_frame_retries	= atusb_set_frame_retries,
7938c2ecf20Sopenharmony_ci	.set_promiscuous_mode	= atusb_set_promiscuous_mode,
7948c2ecf20Sopenharmony_ci};
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci/* ----- Firmware and chip version information ----------------------------- */
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cistatic int atusb_get_and_show_revision(struct atusb *atusb)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
8018c2ecf20Sopenharmony_ci	char *hw_name;
8028c2ecf20Sopenharmony_ci	unsigned char *buffer;
8038c2ecf20Sopenharmony_ci	int ret;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	buffer = kmalloc(3, GFP_KERNEL);
8068c2ecf20Sopenharmony_ci	if (!buffer)
8078c2ecf20Sopenharmony_ci		return -ENOMEM;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	/* Get a couple of the ATMega Firmware values */
8108c2ecf20Sopenharmony_ci	ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
8118c2ecf20Sopenharmony_ci				ATUSB_ID, ATUSB_REQ_FROM_DEV, 0, 0,
8128c2ecf20Sopenharmony_ci				buffer, 3, 1000);
8138c2ecf20Sopenharmony_ci	if (ret >= 0) {
8148c2ecf20Sopenharmony_ci		atusb->fw_ver_maj = buffer[0];
8158c2ecf20Sopenharmony_ci		atusb->fw_ver_min = buffer[1];
8168c2ecf20Sopenharmony_ci		atusb->fw_hw_type = buffer[2];
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci		switch (atusb->fw_hw_type) {
8198c2ecf20Sopenharmony_ci		case ATUSB_HW_TYPE_100813:
8208c2ecf20Sopenharmony_ci		case ATUSB_HW_TYPE_101216:
8218c2ecf20Sopenharmony_ci		case ATUSB_HW_TYPE_110131:
8228c2ecf20Sopenharmony_ci			hw_name = "ATUSB";
8238c2ecf20Sopenharmony_ci			atusb->data = &atusb_chip_data;
8248c2ecf20Sopenharmony_ci			break;
8258c2ecf20Sopenharmony_ci		case ATUSB_HW_TYPE_RZUSB:
8268c2ecf20Sopenharmony_ci			hw_name = "RZUSB";
8278c2ecf20Sopenharmony_ci			atusb->data = &atusb_chip_data;
8288c2ecf20Sopenharmony_ci			break;
8298c2ecf20Sopenharmony_ci		case ATUSB_HW_TYPE_HULUSB:
8308c2ecf20Sopenharmony_ci			hw_name = "HULUSB";
8318c2ecf20Sopenharmony_ci			atusb->data = &hulusb_chip_data;
8328c2ecf20Sopenharmony_ci			break;
8338c2ecf20Sopenharmony_ci		default:
8348c2ecf20Sopenharmony_ci			hw_name = "UNKNOWN";
8358c2ecf20Sopenharmony_ci			atusb->err = -ENOTSUPP;
8368c2ecf20Sopenharmony_ci			ret = -ENOTSUPP;
8378c2ecf20Sopenharmony_ci			break;
8388c2ecf20Sopenharmony_ci		}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		dev_info(&usb_dev->dev,
8418c2ecf20Sopenharmony_ci			 "Firmware: major: %u, minor: %u, hardware type: %s (%d)\n",
8428c2ecf20Sopenharmony_ci			 atusb->fw_ver_maj, atusb->fw_ver_min, hw_name,
8438c2ecf20Sopenharmony_ci			 atusb->fw_hw_type);
8448c2ecf20Sopenharmony_ci	}
8458c2ecf20Sopenharmony_ci	if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 2) {
8468c2ecf20Sopenharmony_ci		dev_info(&usb_dev->dev,
8478c2ecf20Sopenharmony_ci			 "Firmware version (%u.%u) predates our first public release.",
8488c2ecf20Sopenharmony_ci			 atusb->fw_ver_maj, atusb->fw_ver_min);
8498c2ecf20Sopenharmony_ci		dev_info(&usb_dev->dev, "Please update to version 0.2 or newer");
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	kfree(buffer);
8538c2ecf20Sopenharmony_ci	return ret;
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_cistatic int atusb_get_and_show_build(struct atusb *atusb)
8578c2ecf20Sopenharmony_ci{
8588c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
8598c2ecf20Sopenharmony_ci	char *build;
8608c2ecf20Sopenharmony_ci	int ret;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	build = kmalloc(ATUSB_BUILD_SIZE + 1, GFP_KERNEL);
8638c2ecf20Sopenharmony_ci	if (!build)
8648c2ecf20Sopenharmony_ci		return -ENOMEM;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/* We cannot call atusb_control_msg() here, since this request may read various length data */
8678c2ecf20Sopenharmony_ci	ret = usb_control_msg(atusb->usb_dev, usb_rcvctrlpipe(usb_dev, 0), ATUSB_BUILD,
8688c2ecf20Sopenharmony_ci			      ATUSB_REQ_FROM_DEV, 0, 0, build, ATUSB_BUILD_SIZE, 1000);
8698c2ecf20Sopenharmony_ci	if (ret >= 0) {
8708c2ecf20Sopenharmony_ci		build[ret] = 0;
8718c2ecf20Sopenharmony_ci		dev_info(&usb_dev->dev, "Firmware: build %s\n", build);
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	kfree(build);
8758c2ecf20Sopenharmony_ci	return ret;
8768c2ecf20Sopenharmony_ci}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_cistatic int atusb_get_and_conf_chip(struct atusb *atusb)
8798c2ecf20Sopenharmony_ci{
8808c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
8818c2ecf20Sopenharmony_ci	u8 man_id_0, man_id_1, part_num, version_num;
8828c2ecf20Sopenharmony_ci	const char *chip;
8838c2ecf20Sopenharmony_ci	struct ieee802154_hw *hw = atusb->hw;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	man_id_0 = atusb_read_reg(atusb, RG_MAN_ID_0);
8868c2ecf20Sopenharmony_ci	man_id_1 = atusb_read_reg(atusb, RG_MAN_ID_1);
8878c2ecf20Sopenharmony_ci	part_num = atusb_read_reg(atusb, RG_PART_NUM);
8888c2ecf20Sopenharmony_ci	version_num = atusb_read_reg(atusb, RG_VERSION_NUM);
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (atusb->err)
8918c2ecf20Sopenharmony_ci		return atusb->err;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
8948c2ecf20Sopenharmony_ci		    IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL |
8978c2ecf20Sopenharmony_ci			 WPAN_PHY_FLAG_CCA_MODE;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) |
9008c2ecf20Sopenharmony_ci				       BIT(NL802154_CCA_CARRIER) |
9018c2ecf20Sopenharmony_ci				       BIT(NL802154_CCA_ENERGY_CARRIER);
9028c2ecf20Sopenharmony_ci	hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) |
9038c2ecf20Sopenharmony_ci				      BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	hw->phy->cca.mode = NL802154_CCA_ENERGY;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	hw->phy->current_page = 0;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	if ((man_id_1 << 8 | man_id_0) != ATUSB_JEDEC_ATMEL) {
9108c2ecf20Sopenharmony_ci		dev_err(&usb_dev->dev,
9118c2ecf20Sopenharmony_ci			"non-Atmel transceiver xxxx%02x%02x\n",
9128c2ecf20Sopenharmony_ci			man_id_1, man_id_0);
9138c2ecf20Sopenharmony_ci		goto fail;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	switch (part_num) {
9178c2ecf20Sopenharmony_ci	case 2:
9188c2ecf20Sopenharmony_ci		chip = "AT86RF230";
9198c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.channels[0] = 0x7FFF800;
9208c2ecf20Sopenharmony_ci		atusb->hw->phy->current_channel = 11;	/* reset default */
9218c2ecf20Sopenharmony_ci		atusb->hw->phy->symbol_duration = 16;
9228c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.tx_powers = atusb_powers;
9238c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers);
9248c2ecf20Sopenharmony_ci		hw->phy->supported.cca_ed_levels = atusb_ed_levels;
9258c2ecf20Sopenharmony_ci		hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(atusb_ed_levels);
9268c2ecf20Sopenharmony_ci		break;
9278c2ecf20Sopenharmony_ci	case 3:
9288c2ecf20Sopenharmony_ci		chip = "AT86RF231";
9298c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.channels[0] = 0x7FFF800;
9308c2ecf20Sopenharmony_ci		atusb->hw->phy->current_channel = 11;	/* reset default */
9318c2ecf20Sopenharmony_ci		atusb->hw->phy->symbol_duration = 16;
9328c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.tx_powers = atusb_powers;
9338c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers);
9348c2ecf20Sopenharmony_ci		hw->phy->supported.cca_ed_levels = atusb_ed_levels;
9358c2ecf20Sopenharmony_ci		hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(atusb_ed_levels);
9368c2ecf20Sopenharmony_ci		break;
9378c2ecf20Sopenharmony_ci	case 7:
9388c2ecf20Sopenharmony_ci		chip = "AT86RF212";
9398c2ecf20Sopenharmony_ci		atusb->hw->flags |= IEEE802154_HW_LBT;
9408c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.channels[0] = 0x00007FF;
9418c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.channels[2] = 0x00007FF;
9428c2ecf20Sopenharmony_ci		atusb->hw->phy->current_channel = 5;
9438c2ecf20Sopenharmony_ci		atusb->hw->phy->symbol_duration = 25;
9448c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH;
9458c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.tx_powers = at86rf212_powers;
9468c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers);
9478c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100;
9488c2ecf20Sopenharmony_ci		atusb->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100);
9498c2ecf20Sopenharmony_ci		break;
9508c2ecf20Sopenharmony_ci	default:
9518c2ecf20Sopenharmony_ci		dev_err(&usb_dev->dev,
9528c2ecf20Sopenharmony_ci			"unexpected transceiver, part 0x%02x version 0x%02x\n",
9538c2ecf20Sopenharmony_ci			part_num, version_num);
9548c2ecf20Sopenharmony_ci		goto fail;
9558c2ecf20Sopenharmony_ci	}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	hw->phy->transmit_power = hw->phy->supported.tx_powers[0];
9588c2ecf20Sopenharmony_ci	hw->phy->cca_ed_level = hw->phy->supported.cca_ed_levels[7];
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	dev_info(&usb_dev->dev, "ATUSB: %s version %d\n", chip, version_num);
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	return 0;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_cifail:
9658c2ecf20Sopenharmony_ci	atusb->err = -ENODEV;
9668c2ecf20Sopenharmony_ci	return -ENODEV;
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic int atusb_set_extended_addr(struct atusb *atusb)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = atusb->usb_dev;
9728c2ecf20Sopenharmony_ci	unsigned char *buffer;
9738c2ecf20Sopenharmony_ci	__le64 extended_addr;
9748c2ecf20Sopenharmony_ci	u64 addr;
9758c2ecf20Sopenharmony_ci	int ret;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	/* Firmware versions before 0.3 do not support the EUI64_READ command.
9788c2ecf20Sopenharmony_ci	 * Just use a random address and be done.
9798c2ecf20Sopenharmony_ci	 */
9808c2ecf20Sopenharmony_ci	if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 3) {
9818c2ecf20Sopenharmony_ci		ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr);
9828c2ecf20Sopenharmony_ci		return 0;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	buffer = kmalloc(IEEE802154_EXTENDED_ADDR_LEN, GFP_KERNEL);
9868c2ecf20Sopenharmony_ci	if (!buffer)
9878c2ecf20Sopenharmony_ci		return -ENOMEM;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	/* Firmware is new enough so we fetch the address from EEPROM */
9908c2ecf20Sopenharmony_ci	ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
9918c2ecf20Sopenharmony_ci				ATUSB_EUI64_READ, ATUSB_REQ_FROM_DEV, 0, 0,
9928c2ecf20Sopenharmony_ci				buffer, IEEE802154_EXTENDED_ADDR_LEN, 1000);
9938c2ecf20Sopenharmony_ci	if (ret < 0) {
9948c2ecf20Sopenharmony_ci		dev_err(&usb_dev->dev, "failed to fetch extended address, random address set\n");
9958c2ecf20Sopenharmony_ci		ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr);
9968c2ecf20Sopenharmony_ci		kfree(buffer);
9978c2ecf20Sopenharmony_ci		return ret;
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	memcpy(&extended_addr, buffer, IEEE802154_EXTENDED_ADDR_LEN);
10018c2ecf20Sopenharmony_ci	/* Check if read address is not empty and the unicast bit is set correctly */
10028c2ecf20Sopenharmony_ci	if (!ieee802154_is_valid_extended_unicast_addr(extended_addr)) {
10038c2ecf20Sopenharmony_ci		dev_info(&usb_dev->dev, "no permanent extended address found, random address set\n");
10048c2ecf20Sopenharmony_ci		ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr);
10058c2ecf20Sopenharmony_ci	} else {
10068c2ecf20Sopenharmony_ci		atusb->hw->phy->perm_extended_addr = extended_addr;
10078c2ecf20Sopenharmony_ci		addr = swab64((__force u64)atusb->hw->phy->perm_extended_addr);
10088c2ecf20Sopenharmony_ci		dev_info(&usb_dev->dev, "Read permanent extended address %8phC from device\n",
10098c2ecf20Sopenharmony_ci			 &addr);
10108c2ecf20Sopenharmony_ci	}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	kfree(buffer);
10138c2ecf20Sopenharmony_ci	return ret;
10148c2ecf20Sopenharmony_ci}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci/* ----- Setup ------------------------------------------------------------- */
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic int atusb_probe(struct usb_interface *interface,
10198c2ecf20Sopenharmony_ci		       const struct usb_device_id *id)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct usb_device *usb_dev = interface_to_usbdev(interface);
10228c2ecf20Sopenharmony_ci	struct ieee802154_hw *hw;
10238c2ecf20Sopenharmony_ci	struct atusb *atusb = NULL;
10248c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	hw = ieee802154_alloc_hw(sizeof(struct atusb), &atusb_ops);
10278c2ecf20Sopenharmony_ci	if (!hw)
10288c2ecf20Sopenharmony_ci		return -ENOMEM;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	atusb = hw->priv;
10318c2ecf20Sopenharmony_ci	atusb->hw = hw;
10328c2ecf20Sopenharmony_ci	atusb->usb_dev = usb_get_dev(usb_dev);
10338c2ecf20Sopenharmony_ci	usb_set_intfdata(interface, atusb);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	atusb->shutdown = 0;
10368c2ecf20Sopenharmony_ci	atusb->err = 0;
10378c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&atusb->work, atusb_work_urbs);
10388c2ecf20Sopenharmony_ci	init_usb_anchor(&atusb->idle_urbs);
10398c2ecf20Sopenharmony_ci	init_usb_anchor(&atusb->rx_urbs);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	if (atusb_alloc_urbs(atusb, ATUSB_NUM_RX_URBS))
10428c2ecf20Sopenharmony_ci		goto fail;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	atusb->tx_dr.bRequestType = ATUSB_REQ_TO_DEV;
10458c2ecf20Sopenharmony_ci	atusb->tx_dr.bRequest = ATUSB_TX;
10468c2ecf20Sopenharmony_ci	atusb->tx_dr.wValue = cpu_to_le16(0);
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	atusb->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
10498c2ecf20Sopenharmony_ci	if (!atusb->tx_urb)
10508c2ecf20Sopenharmony_ci		goto fail;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	hw->parent = &usb_dev->dev;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	atusb_command(atusb, ATUSB_RF_RESET, 0);
10558c2ecf20Sopenharmony_ci	atusb_get_and_conf_chip(atusb);
10568c2ecf20Sopenharmony_ci	atusb_get_and_show_revision(atusb);
10578c2ecf20Sopenharmony_ci	atusb_get_and_show_build(atusb);
10588c2ecf20Sopenharmony_ci	atusb_set_extended_addr(atusb);
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	if ((atusb->fw_ver_maj == 0 && atusb->fw_ver_min >= 3) || atusb->fw_ver_maj > 0)
10618c2ecf20Sopenharmony_ci		hw->flags |= IEEE802154_HW_FRAME_RETRIES;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	ret = atusb_get_and_clear_error(atusb);
10648c2ecf20Sopenharmony_ci	if (ret) {
10658c2ecf20Sopenharmony_ci		dev_err(&atusb->usb_dev->dev,
10668c2ecf20Sopenharmony_ci			"%s: initialization failed, error = %d\n",
10678c2ecf20Sopenharmony_ci			__func__, ret);
10688c2ecf20Sopenharmony_ci		goto fail;
10698c2ecf20Sopenharmony_ci	}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	ret = ieee802154_register_hw(hw);
10728c2ecf20Sopenharmony_ci	if (ret)
10738c2ecf20Sopenharmony_ci		goto fail;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	/* If we just powered on, we're now in P_ON and need to enter TRX_OFF
10768c2ecf20Sopenharmony_ci	 * explicitly. Any resets after that will send us straight to TRX_OFF,
10778c2ecf20Sopenharmony_ci	 * making the command below redundant.
10788c2ecf20Sopenharmony_ci	 */
10798c2ecf20Sopenharmony_ci	atusb_write_reg(atusb, RG_TRX_STATE, STATE_FORCE_TRX_OFF);
10808c2ecf20Sopenharmony_ci	msleep(1);	/* reset => TRX_OFF, tTR13 = 37 us */
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci#if 0
10838c2ecf20Sopenharmony_ci	/* Calculating the maximum time available to empty the frame buffer
10848c2ecf20Sopenharmony_ci	 * on reception:
10858c2ecf20Sopenharmony_ci	 *
10868c2ecf20Sopenharmony_ci	 * According to [1], the inter-frame gap is
10878c2ecf20Sopenharmony_ci	 * R * 20 * 16 us + 128 us
10888c2ecf20Sopenharmony_ci	 * where R is a random number from 0 to 7. Furthermore, we have 20 bit
10898c2ecf20Sopenharmony_ci	 * times (80 us at 250 kbps) of SHR of the next frame before the
10908c2ecf20Sopenharmony_ci	 * transceiver begins storing data in the frame buffer.
10918c2ecf20Sopenharmony_ci	 *
10928c2ecf20Sopenharmony_ci	 * This yields a minimum time of 208 us between the last data of a
10938c2ecf20Sopenharmony_ci	 * frame and the first data of the next frame. This time is further
10948c2ecf20Sopenharmony_ci	 * reduced by interrupt latency in the atusb firmware.
10958c2ecf20Sopenharmony_ci	 *
10968c2ecf20Sopenharmony_ci	 * atusb currently needs about 500 us to retrieve a maximum-sized
10978c2ecf20Sopenharmony_ci	 * frame. We therefore have to allow reception of a new frame to begin
10988c2ecf20Sopenharmony_ci	 * while we retrieve the previous frame.
10998c2ecf20Sopenharmony_ci	 *
11008c2ecf20Sopenharmony_ci	 * [1] "JN-AN-1035 Calculating data rates in an IEEE 802.15.4-based
11018c2ecf20Sopenharmony_ci	 *      network", Jennic 2006.
11028c2ecf20Sopenharmony_ci	 *     http://www.jennic.com/download_file.php?supportFile=JN-AN-1035%20Calculating%20802-15-4%20Data%20Rates-1v0.pdf
11038c2ecf20Sopenharmony_ci	 */
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	atusb_write_subreg(atusb, SR_RX_SAFE_MODE, 1);
11068c2ecf20Sopenharmony_ci#endif
11078c2ecf20Sopenharmony_ci	atusb_write_reg(atusb, RG_IRQ_MASK, 0xff);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	ret = atusb_get_and_clear_error(atusb);
11108c2ecf20Sopenharmony_ci	if (!ret)
11118c2ecf20Sopenharmony_ci		return 0;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	dev_err(&atusb->usb_dev->dev,
11148c2ecf20Sopenharmony_ci		"%s: setup failed, error = %d\n",
11158c2ecf20Sopenharmony_ci		__func__, ret);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	ieee802154_unregister_hw(hw);
11188c2ecf20Sopenharmony_cifail:
11198c2ecf20Sopenharmony_ci	atusb_free_urbs(atusb);
11208c2ecf20Sopenharmony_ci	usb_kill_urb(atusb->tx_urb);
11218c2ecf20Sopenharmony_ci	usb_free_urb(atusb->tx_urb);
11228c2ecf20Sopenharmony_ci	usb_put_dev(usb_dev);
11238c2ecf20Sopenharmony_ci	ieee802154_free_hw(hw);
11248c2ecf20Sopenharmony_ci	return ret;
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_cistatic void atusb_disconnect(struct usb_interface *interface)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	struct atusb *atusb = usb_get_intfdata(interface);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	dev_dbg(&atusb->usb_dev->dev, "%s\n", __func__);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	atusb->shutdown = 1;
11348c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&atusb->work);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	usb_kill_anchored_urbs(&atusb->rx_urbs);
11378c2ecf20Sopenharmony_ci	atusb_free_urbs(atusb);
11388c2ecf20Sopenharmony_ci	usb_kill_urb(atusb->tx_urb);
11398c2ecf20Sopenharmony_ci	usb_free_urb(atusb->tx_urb);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	ieee802154_unregister_hw(atusb->hw);
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	usb_put_dev(atusb->usb_dev);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	ieee802154_free_hw(atusb->hw);
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	usb_set_intfdata(interface, NULL);
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	pr_debug("%s done\n", __func__);
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci/* The devices we work with */
11538c2ecf20Sopenharmony_cistatic const struct usb_device_id atusb_device_table[] = {
11548c2ecf20Sopenharmony_ci	{
11558c2ecf20Sopenharmony_ci		.match_flags		= USB_DEVICE_ID_MATCH_DEVICE |
11568c2ecf20Sopenharmony_ci					  USB_DEVICE_ID_MATCH_INT_INFO,
11578c2ecf20Sopenharmony_ci		.idVendor		= ATUSB_VENDOR_ID,
11588c2ecf20Sopenharmony_ci		.idProduct		= ATUSB_PRODUCT_ID,
11598c2ecf20Sopenharmony_ci		.bInterfaceClass	= USB_CLASS_VENDOR_SPEC
11608c2ecf20Sopenharmony_ci	},
11618c2ecf20Sopenharmony_ci	/* end with null element */
11628c2ecf20Sopenharmony_ci	{}
11638c2ecf20Sopenharmony_ci};
11648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, atusb_device_table);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_cistatic struct usb_driver atusb_driver = {
11678c2ecf20Sopenharmony_ci	.name		= "atusb",
11688c2ecf20Sopenharmony_ci	.probe		= atusb_probe,
11698c2ecf20Sopenharmony_ci	.disconnect	= atusb_disconnect,
11708c2ecf20Sopenharmony_ci	.id_table	= atusb_device_table,
11718c2ecf20Sopenharmony_ci};
11728c2ecf20Sopenharmony_cimodule_usb_driver(atusb_driver);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexander Aring <alex.aring@gmail.com>");
11758c2ecf20Sopenharmony_ciMODULE_AUTHOR("Richard Sharpe <realrichardsharpe@gmail.com>");
11768c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stefan Schmidt <stefan@datenfreihafen.org>");
11778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Werner Almesberger <werner@almesberger.net>");
11788c2ecf20Sopenharmony_ciMODULE_AUTHOR("Josef Filzmaier <j.filzmaier@gmx.at>");
11798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ATUSB IEEE 802.15.4 Driver");
11808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1181