brintos

brintos / linux-shallow public Read only

0
0
Text · 28.2 KiB · 2b70341 Raw
1193 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Driver for TI CC2520 802.15.4 Wireless-PAN Networking controller3 *4 * Copyright (C) 2014 Varka Bhadram <varkab@cdac.in>5 *		      Md.Jamal Mohiuddin <mjmohiuddin@cdac.in>6 *		      P Sowjanya <sowjanyap@cdac.in>7 */8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/gpio/consumer.h>11#include <linux/delay.h>12#include <linux/spi/spi.h>13#include <linux/property.h>14#include <linux/workqueue.h>15#include <linux/interrupt.h>16#include <linux/skbuff.h>17#include <linux/ieee802154.h>18#include <linux/crc-ccitt.h>19#include <linux/unaligned.h>20 21#include <net/mac802154.h>22#include <net/cfg802154.h>23 24#define	SPI_COMMAND_BUFFER	325#define	HIGH			126#define	LOW			027#define	STATE_IDLE		028#define	RSSI_VALID		029#define	RSSI_OFFSET		7830 31#define	CC2520_RAM_SIZE		64032#define	CC2520_FIFO_SIZE	12833 34#define	CC2520RAM_TXFIFO	0x10035#define	CC2520RAM_RXFIFO	0x18036#define	CC2520RAM_IEEEADDR	0x3EA37#define	CC2520RAM_PANID		0x3F238#define	CC2520RAM_SHORTADDR	0x3F439 40#define	CC2520_FREG_MASK	0x3F41 42/* status byte values */43#define	CC2520_STATUS_XOSC32M_STABLE	BIT(7)44#define	CC2520_STATUS_RSSI_VALID	BIT(6)45#define	CC2520_STATUS_TX_UNDERFLOW	BIT(3)46 47/* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */48#define	CC2520_MINCHANNEL		1149#define	CC2520_MAXCHANNEL		2650#define	CC2520_CHANNEL_SPACING		551 52/* command strobes */53#define	CC2520_CMD_SNOP			0x0054#define	CC2520_CMD_IBUFLD		0x0255#define	CC2520_CMD_SIBUFEX		0x0356#define	CC2520_CMD_SSAMPLECCA		0x0457#define	CC2520_CMD_SRES			0x0f58#define	CC2520_CMD_MEMORY_MASK		0x0f59#define	CC2520_CMD_MEMORY_READ		0x1060#define	CC2520_CMD_MEMORY_WRITE		0x2061#define	CC2520_CMD_RXBUF		0x3062#define	CC2520_CMD_RXBUFCP		0x3863#define	CC2520_CMD_RXBUFMOV		0x3264#define	CC2520_CMD_TXBUF		0x3A65#define	CC2520_CMD_TXBUFCP		0x3E66#define	CC2520_CMD_RANDOM		0x3C67#define	CC2520_CMD_SXOSCON		0x4068#define	CC2520_CMD_STXCAL		0x4169#define	CC2520_CMD_SRXON		0x4270#define	CC2520_CMD_STXON		0x4371#define	CC2520_CMD_STXONCCA		0x4472#define	CC2520_CMD_SRFOFF		0x4573#define	CC2520_CMD_SXOSCOFF		0x4674#define	CC2520_CMD_SFLUSHRX		0x4775#define	CC2520_CMD_SFLUSHTX		0x4876#define	CC2520_CMD_SACK			0x4977#define	CC2520_CMD_SACKPEND		0x4A78#define	CC2520_CMD_SNACK		0x4B79#define	CC2520_CMD_SRXMASKBITSET	0x4C80#define	CC2520_CMD_SRXMASKBITCLR	0x4D81#define	CC2520_CMD_RXMASKAND		0x4E82#define	CC2520_CMD_RXMASKOR		0x4F83#define	CC2520_CMD_MEMCP		0x5084#define	CC2520_CMD_MEMCPR		0x5285#define	CC2520_CMD_MEMXCP		0x5486#define	CC2520_CMD_MEMXWR		0x5687#define	CC2520_CMD_BCLR			0x5888#define	CC2520_CMD_BSET			0x5989#define	CC2520_CMD_CTR_UCTR		0x6090#define	CC2520_CMD_CBCMAC		0x6491#define	CC2520_CMD_UCBCMAC		0x6692#define	CC2520_CMD_CCM			0x6893#define	CC2520_CMD_UCCM			0x6A94#define	CC2520_CMD_ECB			0x7095#define	CC2520_CMD_ECBO			0x7296#define	CC2520_CMD_ECBX			0x7497#define	CC2520_CMD_INC			0x7898#define	CC2520_CMD_ABORT		0x7F99#define	CC2520_CMD_REGISTER_READ	0x80100#define	CC2520_CMD_REGISTER_WRITE	0xC0101 102/* status registers */103#define	CC2520_CHIPID			0x40104#define	CC2520_VERSION			0x42105#define	CC2520_EXTCLOCK			0x44106#define	CC2520_MDMCTRL0			0x46107#define	CC2520_MDMCTRL1			0x47108#define	CC2520_FREQEST			0x48109#define	CC2520_RXCTRL			0x4A110#define	CC2520_FSCTRL			0x4C111#define	CC2520_FSCAL0			0x4E112#define	CC2520_FSCAL1			0x4F113#define	CC2520_FSCAL2			0x50114#define	CC2520_FSCAL3			0x51115#define	CC2520_AGCCTRL0			0x52116#define	CC2520_AGCCTRL1			0x53117#define	CC2520_AGCCTRL2			0x54118#define	CC2520_AGCCTRL3			0x55119#define	CC2520_ADCTEST0			0x56120#define	CC2520_ADCTEST1			0x57121#define	CC2520_ADCTEST2			0x58122#define	CC2520_MDMTEST0			0x5A123#define	CC2520_MDMTEST1			0x5B124#define	CC2520_DACTEST0			0x5C125#define	CC2520_DACTEST1			0x5D126#define	CC2520_ATEST			0x5E127#define	CC2520_DACTEST2			0x5F128#define	CC2520_PTEST0			0x60129#define	CC2520_PTEST1			0x61130#define	CC2520_RESERVED			0x62131#define	CC2520_DPUBIST			0x7A132#define	CC2520_ACTBIST			0x7C133#define	CC2520_RAMBIST			0x7E134 135/* frame registers */136#define	CC2520_FRMFILT0			0x00137#define	CC2520_FRMFILT1			0x01138#define	CC2520_SRCMATCH			0x02139#define	CC2520_SRCSHORTEN0		0x04140#define	CC2520_SRCSHORTEN1		0x05141#define	CC2520_SRCSHORTEN2		0x06142#define	CC2520_SRCEXTEN0		0x08143#define	CC2520_SRCEXTEN1		0x09144#define	CC2520_SRCEXTEN2		0x0A145#define	CC2520_FRMCTRL0			0x0C146#define	CC2520_FRMCTRL1			0x0D147#define	CC2520_RXENABLE0		0x0E148#define	CC2520_RXENABLE1		0x0F149#define	CC2520_EXCFLAG0			0x10150#define	CC2520_EXCFLAG1			0x11151#define	CC2520_EXCFLAG2			0x12152#define	CC2520_EXCMASKA0		0x14153#define	CC2520_EXCMASKA1		0x15154#define	CC2520_EXCMASKA2		0x16155#define	CC2520_EXCMASKB0		0x18156#define	CC2520_EXCMASKB1		0x19157#define	CC2520_EXCMASKB2		0x1A158#define	CC2520_EXCBINDX0		0x1C159#define	CC2520_EXCBINDX1		0x1D160#define	CC2520_EXCBINDY0		0x1E161#define	CC2520_EXCBINDY1		0x1F162#define	CC2520_GPIOCTRL0		0x20163#define	CC2520_GPIOCTRL1		0x21164#define	CC2520_GPIOCTRL2		0x22165#define	CC2520_GPIOCTRL3		0x23166#define	CC2520_GPIOCTRL4		0x24167#define	CC2520_GPIOCTRL5		0x25168#define	CC2520_GPIOPOLARITY		0x26169#define	CC2520_GPIOCTRL			0x28170#define	CC2520_DPUCON			0x2A171#define	CC2520_DPUSTAT			0x2C172#define	CC2520_FREQCTRL			0x2E173#define	CC2520_FREQTUNE			0x2F174#define	CC2520_TXPOWER			0x30175#define	CC2520_TXCTRL			0x31176#define	CC2520_FSMSTAT0			0x32177#define	CC2520_FSMSTAT1			0x33178#define	CC2520_FIFOPCTRL		0x34179#define	CC2520_FSMCTRL			0x35180#define	CC2520_CCACTRL0			0x36181#define	CC2520_CCACTRL1			0x37182#define	CC2520_RSSI			0x38183#define	CC2520_RSSISTAT			0x39184#define	CC2520_RXFIRST			0x3C185#define	CC2520_RXFIFOCNT		0x3E186#define	CC2520_TXFIFOCNT		0x3F187 188/* CC2520_FRMFILT0 */189#define FRMFILT0_FRAME_FILTER_EN	BIT(0)190#define FRMFILT0_PAN_COORDINATOR	BIT(1)191 192/* CC2520_FRMCTRL0 */193#define FRMCTRL0_AUTOACK		BIT(5)194#define FRMCTRL0_AUTOCRC		BIT(6)195 196/* CC2520_FRMCTRL1 */197#define FRMCTRL1_SET_RXENMASK_ON_TX	BIT(0)198#define FRMCTRL1_IGNORE_TX_UNDERF	BIT(1)199 200/* Driver private information */201struct cc2520_private {202	struct spi_device *spi;		/* SPI device structure */203	struct ieee802154_hw *hw;	/* IEEE-802.15.4 device */204	u8 *buf;			/* SPI TX/Rx data buffer */205	struct mutex buffer_mutex;	/* SPI buffer mutex */206	bool is_tx;			/* Flag for sync b/w Tx and Rx */207	bool amplified;			/* Flag for CC2591 */208	struct gpio_desc *fifo_pin;	/* FIFO GPIO pin number */209	struct work_struct fifop_irqwork;/* Workqueue for FIFOP */210	spinlock_t lock;		/* Lock for is_tx*/211	struct completion tx_complete;	/* Work completion for Tx */212	bool promiscuous;               /* Flag for promiscuous mode */213};214 215/* Generic Functions */216static int217cc2520_cmd_strobe(struct cc2520_private *priv, u8 cmd)218{219	int ret;220	struct spi_message msg;221	struct spi_transfer xfer = {222		.len = 0,223		.tx_buf = priv->buf,224		.rx_buf = priv->buf,225	};226 227	spi_message_init(&msg);228	spi_message_add_tail(&xfer, &msg);229 230	mutex_lock(&priv->buffer_mutex);231	priv->buf[xfer.len++] = cmd;232	dev_vdbg(&priv->spi->dev,233		 "command strobe buf[0] = %02x\n",234		 priv->buf[0]);235 236	ret = spi_sync(priv->spi, &msg);237	dev_vdbg(&priv->spi->dev,238		 "buf[0] = %02x\n", priv->buf[0]);239	mutex_unlock(&priv->buffer_mutex);240 241	return ret;242}243 244static int245cc2520_get_status(struct cc2520_private *priv, u8 *status)246{247	int ret;248	struct spi_message msg;249	struct spi_transfer xfer = {250		.len = 0,251		.tx_buf = priv->buf,252		.rx_buf = priv->buf,253	};254 255	spi_message_init(&msg);256	spi_message_add_tail(&xfer, &msg);257 258	mutex_lock(&priv->buffer_mutex);259	priv->buf[xfer.len++] = CC2520_CMD_SNOP;260	dev_vdbg(&priv->spi->dev,261		 "get status command buf[0] = %02x\n", priv->buf[0]);262 263	ret = spi_sync(priv->spi, &msg);264	if (!ret)265		*status = priv->buf[0];266	dev_vdbg(&priv->spi->dev,267		 "buf[0] = %02x\n", priv->buf[0]);268	mutex_unlock(&priv->buffer_mutex);269 270	return ret;271}272 273static int274cc2520_write_register(struct cc2520_private *priv, u8 reg, u8 value)275{276	int status;277	struct spi_message msg;278	struct spi_transfer xfer = {279		.len = 0,280		.tx_buf = priv->buf,281		.rx_buf = priv->buf,282	};283 284	spi_message_init(&msg);285	spi_message_add_tail(&xfer, &msg);286 287	mutex_lock(&priv->buffer_mutex);288 289	if (reg <= CC2520_FREG_MASK) {290		priv->buf[xfer.len++] = CC2520_CMD_REGISTER_WRITE | reg;291		priv->buf[xfer.len++] = value;292	} else {293		priv->buf[xfer.len++] = CC2520_CMD_MEMORY_WRITE;294		priv->buf[xfer.len++] = reg;295		priv->buf[xfer.len++] = value;296	}297	status = spi_sync(priv->spi, &msg);298	if (msg.status)299		status = msg.status;300 301	mutex_unlock(&priv->buffer_mutex);302 303	return status;304}305 306static int307cc2520_write_ram(struct cc2520_private *priv, u16 reg, u8 len, u8 *data)308{309	int status;310	struct spi_message msg;311	struct spi_transfer xfer_head = {312		.len        = 0,313		.tx_buf        = priv->buf,314		.rx_buf        = priv->buf,315	};316 317	struct spi_transfer xfer_buf = {318		.len = len,319		.tx_buf = data,320	};321 322	mutex_lock(&priv->buffer_mutex);323	priv->buf[xfer_head.len++] = (CC2520_CMD_MEMORY_WRITE |324						((reg >> 8) & 0xff));325	priv->buf[xfer_head.len++] = reg & 0xff;326 327	spi_message_init(&msg);328	spi_message_add_tail(&xfer_head, &msg);329	spi_message_add_tail(&xfer_buf, &msg);330 331	status = spi_sync(priv->spi, &msg);332	dev_dbg(&priv->spi->dev, "spi status = %d\n", status);333	if (msg.status)334		status = msg.status;335 336	mutex_unlock(&priv->buffer_mutex);337	return status;338}339 340static int341cc2520_read_register(struct cc2520_private *priv, u8 reg, u8 *data)342{343	int status;344	struct spi_message msg;345	struct spi_transfer xfer1 = {346		.len = 0,347		.tx_buf = priv->buf,348		.rx_buf = priv->buf,349	};350 351	struct spi_transfer xfer2 = {352		.len = 1,353		.rx_buf = data,354	};355 356	spi_message_init(&msg);357	spi_message_add_tail(&xfer1, &msg);358	spi_message_add_tail(&xfer2, &msg);359 360	mutex_lock(&priv->buffer_mutex);361	priv->buf[xfer1.len++] = CC2520_CMD_MEMORY_READ;362	priv->buf[xfer1.len++] = reg;363 364	status = spi_sync(priv->spi, &msg);365	dev_dbg(&priv->spi->dev,366		"spi status = %d\n", status);367	if (msg.status)368		status = msg.status;369 370	mutex_unlock(&priv->buffer_mutex);371 372	return status;373}374 375static int376cc2520_write_txfifo(struct cc2520_private *priv, u8 pkt_len, u8 *data, u8 len)377{378	int status;379 380	/* length byte must include FCS even381	 * if it is calculated in the hardware382	 */383	int len_byte = pkt_len;384 385	struct spi_message msg;386 387	struct spi_transfer xfer_head = {388		.len = 0,389		.tx_buf = priv->buf,390		.rx_buf = priv->buf,391	};392	struct spi_transfer xfer_len = {393		.len = 1,394		.tx_buf = &len_byte,395	};396	struct spi_transfer xfer_buf = {397		.len = len,398		.tx_buf = data,399	};400 401	spi_message_init(&msg);402	spi_message_add_tail(&xfer_head, &msg);403	spi_message_add_tail(&xfer_len, &msg);404	spi_message_add_tail(&xfer_buf, &msg);405 406	mutex_lock(&priv->buffer_mutex);407	priv->buf[xfer_head.len++] = CC2520_CMD_TXBUF;408	dev_vdbg(&priv->spi->dev,409		 "TX_FIFO cmd buf[0] = %02x\n", priv->buf[0]);410 411	status = spi_sync(priv->spi, &msg);412	dev_vdbg(&priv->spi->dev, "status = %d\n", status);413	if (msg.status)414		status = msg.status;415	dev_vdbg(&priv->spi->dev, "status = %d\n", status);416	dev_vdbg(&priv->spi->dev, "buf[0] = %02x\n", priv->buf[0]);417	mutex_unlock(&priv->buffer_mutex);418 419	return status;420}421 422static int423cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len)424{425	int status;426	struct spi_message msg;427 428	struct spi_transfer xfer_head = {429		.len = 0,430		.tx_buf = priv->buf,431		.rx_buf = priv->buf,432	};433	struct spi_transfer xfer_buf = {434		.len = len,435		.rx_buf = data,436	};437 438	spi_message_init(&msg);439	spi_message_add_tail(&xfer_head, &msg);440	spi_message_add_tail(&xfer_buf, &msg);441 442	mutex_lock(&priv->buffer_mutex);443	priv->buf[xfer_head.len++] = CC2520_CMD_RXBUF;444 445	dev_vdbg(&priv->spi->dev, "read rxfifo buf[0] = %02x\n", priv->buf[0]);446	dev_vdbg(&priv->spi->dev, "buf[1] = %02x\n", priv->buf[1]);447 448	status = spi_sync(priv->spi, &msg);449	dev_vdbg(&priv->spi->dev, "status = %d\n", status);450	if (msg.status)451		status = msg.status;452	dev_vdbg(&priv->spi->dev, "status = %d\n", status);453	dev_vdbg(&priv->spi->dev,454		 "return status buf[0] = %02x\n", priv->buf[0]);455	dev_vdbg(&priv->spi->dev, "length buf[1] = %02x\n", priv->buf[1]);456 457	mutex_unlock(&priv->buffer_mutex);458 459	return status;460}461 462static int cc2520_start(struct ieee802154_hw *hw)463{464	return cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRXON);465}466 467static void cc2520_stop(struct ieee802154_hw *hw)468{469	cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRFOFF);470}471 472static int473cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb)474{475	struct cc2520_private *priv = hw->priv;476	unsigned long flags;477	int rc;478	u8 status = 0;479	u8 pkt_len;480 481	/* In promiscuous mode we disable AUTOCRC so we can get the raw CRC482	 * values on RX. This means we need to manually add the CRC on TX.483	 */484	if (priv->promiscuous) {485		u16 crc = crc_ccitt(0, skb->data, skb->len);486 487		put_unaligned_le16(crc, skb_put(skb, 2));488		pkt_len = skb->len;489	} else {490		pkt_len = skb->len + 2;491	}492 493	rc = cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX);494	if (rc)495		goto err_tx;496 497	rc = cc2520_write_txfifo(priv, pkt_len, skb->data, skb->len);498	if (rc)499		goto err_tx;500 501	rc = cc2520_get_status(priv, &status);502	if (rc)503		goto err_tx;504 505	if (status & CC2520_STATUS_TX_UNDERFLOW) {506		rc = -EINVAL;507		dev_err(&priv->spi->dev, "cc2520 tx underflow exception\n");508		goto err_tx;509	}510 511	spin_lock_irqsave(&priv->lock, flags);512	WARN_ON(priv->is_tx);513	priv->is_tx = 1;514	spin_unlock_irqrestore(&priv->lock, flags);515 516	rc = cc2520_cmd_strobe(priv, CC2520_CMD_STXONCCA);517	if (rc)518		goto err;519 520	rc = wait_for_completion_interruptible(&priv->tx_complete);521	if (rc < 0)522		goto err;523 524	cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHTX);525	cc2520_cmd_strobe(priv, CC2520_CMD_SRXON);526 527	return rc;528err:529	spin_lock_irqsave(&priv->lock, flags);530	priv->is_tx = 0;531	spin_unlock_irqrestore(&priv->lock, flags);532err_tx:533	return rc;534}535 536static int cc2520_rx(struct cc2520_private *priv)537{538	u8 len = 0, lqi = 0, bytes = 1;539	struct sk_buff *skb;540 541	/* Read single length byte from the radio. */542	cc2520_read_rxfifo(priv, &len, bytes);543 544	if (!ieee802154_is_valid_psdu_len(len)) {545		/* Corrupted frame received, clear frame buffer by546		 * reading entire buffer.547		 */548		dev_dbg(&priv->spi->dev, "corrupted frame received\n");549		len = IEEE802154_MTU;550	}551 552	skb = dev_alloc_skb(len);553	if (!skb)554		return -ENOMEM;555 556	if (cc2520_read_rxfifo(priv, skb_put(skb, len), len)) {557		dev_dbg(&priv->spi->dev, "frame reception failed\n");558		kfree_skb(skb);559		return -EINVAL;560	}561 562	/* In promiscuous mode, we configure the radio to include the563	 * CRC (AUTOCRC==0) and we pass on the packet unconditionally. If not564	 * in promiscuous mode, we check the CRC here, but leave the565	 * RSSI/LQI/CRC_OK bytes as they will get removed in the mac layer.566	 */567	if (!priv->promiscuous) {568		bool crc_ok;569 570		/* Check if the CRC is valid. With AUTOCRC set, the most571		 * significant bit of the last byte returned from the CC2520572		 * is CRC_OK flag. See section 20.3.4 of the datasheet.573		 */574		crc_ok = skb->data[len - 1] & BIT(7);575 576		/* If we failed CRC drop the packet in the driver layer. */577		if (!crc_ok) {578			dev_dbg(&priv->spi->dev, "CRC check failed\n");579			kfree_skb(skb);580			return -EINVAL;581		}582 583		/* To calculate LQI, the lower 7 bits of the last byte (the584		 * correlation value provided by the radio) must be scaled to585		 * the range 0-255. According to section 20.6, the correlation586		 * value ranges from 50-110. Ideally this would be calibrated587		 * per hardware design, but we use roughly the datasheet values588		 * to get close enough while avoiding floating point.589		 */590		lqi = skb->data[len - 1] & 0x7f;591		if (lqi < 50)592			lqi = 50;593		else if (lqi > 113)594			lqi = 113;595		lqi = (lqi - 50) * 4;596	}597 598	ieee802154_rx_irqsafe(priv->hw, skb, lqi);599 600	dev_vdbg(&priv->spi->dev, "RXFIFO: %x %x\n", len, lqi);601 602	return 0;603}604 605static int606cc2520_ed(struct ieee802154_hw *hw, u8 *level)607{608	struct cc2520_private *priv = hw->priv;609	u8 status = 0xff;610	u8 rssi;611	int ret;612 613	ret = cc2520_read_register(priv, CC2520_RSSISTAT, &status);614	if (ret)615		return ret;616 617	if (status != RSSI_VALID)618		return -EINVAL;619 620	ret = cc2520_read_register(priv, CC2520_RSSI, &rssi);621	if (ret)622		return ret;623 624	/* level = RSSI(rssi) - OFFSET [dBm] : offset is 76dBm */625	*level = rssi - RSSI_OFFSET;626 627	return 0;628}629 630static int631cc2520_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)632{633	struct cc2520_private *priv = hw->priv;634	int ret;635 636	dev_dbg(&priv->spi->dev, "trying to set channel\n");637 638	WARN_ON(page != 0);639	WARN_ON(channel < CC2520_MINCHANNEL);640	WARN_ON(channel > CC2520_MAXCHANNEL);641 642	ret = cc2520_write_register(priv, CC2520_FREQCTRL,643				    11 + 5 * (channel - 11));644 645	return ret;646}647 648static int649cc2520_filter(struct ieee802154_hw *hw,650	      struct ieee802154_hw_addr_filt *filt, unsigned long changed)651{652	struct cc2520_private *priv = hw->priv;653	int ret = 0;654 655	if (changed & IEEE802154_AFILT_PANID_CHANGED) {656		u16 panid = le16_to_cpu(filt->pan_id);657 658		dev_vdbg(&priv->spi->dev, "%s called for pan id\n", __func__);659		ret = cc2520_write_ram(priv, CC2520RAM_PANID,660				       sizeof(panid), (u8 *)&panid);661	}662 663	if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {664		dev_vdbg(&priv->spi->dev,665			 "%s called for IEEE addr\n", __func__);666		ret = cc2520_write_ram(priv, CC2520RAM_IEEEADDR,667				       sizeof(filt->ieee_addr),668				       (u8 *)&filt->ieee_addr);669	}670 671	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {672		u16 addr = le16_to_cpu(filt->short_addr);673 674		dev_vdbg(&priv->spi->dev, "%s called for saddr\n", __func__);675		ret = cc2520_write_ram(priv, CC2520RAM_SHORTADDR,676				       sizeof(addr), (u8 *)&addr);677	}678 679	if (changed & IEEE802154_AFILT_PANC_CHANGED) {680		u8 frmfilt0;681 682		dev_vdbg(&priv->spi->dev,683			 "%s called for panc change\n", __func__);684 685		cc2520_read_register(priv, CC2520_FRMFILT0, &frmfilt0);686 687		if (filt->pan_coord)688			frmfilt0 |= FRMFILT0_PAN_COORDINATOR;689		else690			frmfilt0 &= ~FRMFILT0_PAN_COORDINATOR;691 692		ret = cc2520_write_register(priv, CC2520_FRMFILT0, frmfilt0);693	}694 695	return ret;696}697 698static inline int cc2520_set_tx_power(struct cc2520_private *priv, s32 mbm)699{700	u8 power;701 702	switch (mbm) {703	case 500:704		power = 0xF7;705		break;706	case 300:707		power = 0xF2;708		break;709	case 200:710		power = 0xAB;711		break;712	case 100:713		power = 0x13;714		break;715	case 0:716		power = 0x32;717		break;718	case -200:719		power = 0x81;720		break;721	case -400:722		power = 0x88;723		break;724	case -700:725		power = 0x2C;726		break;727	case -1800:728		power = 0x03;729		break;730	default:731		return -EINVAL;732	}733 734	return cc2520_write_register(priv, CC2520_TXPOWER, power);735}736 737static inline int cc2520_cc2591_set_tx_power(struct cc2520_private *priv,738					     s32 mbm)739{740	u8 power;741 742	switch (mbm) {743	case 1700:744		power = 0xF9;745		break;746	case 1600:747		power = 0xF0;748		break;749	case 1400:750		power = 0xA0;751		break;752	case 1100:753		power = 0x2C;754		break;755	case -100:756		power = 0x03;757		break;758	case -800:759		power = 0x01;760		break;761	default:762		return -EINVAL;763	}764 765	return cc2520_write_register(priv, CC2520_TXPOWER, power);766}767 768#define CC2520_MAX_TX_POWERS 0x8769static const s32 cc2520_powers[CC2520_MAX_TX_POWERS + 1] = {770	500, 300, 200, 100, 0, -200, -400, -700, -1800,771};772 773#define CC2520_CC2591_MAX_TX_POWERS 0x5774static const s32 cc2520_cc2591_powers[CC2520_CC2591_MAX_TX_POWERS + 1] = {775	1700, 1600, 1400, 1100, -100, -800,776};777 778static int779cc2520_set_txpower(struct ieee802154_hw *hw, s32 mbm)780{781	struct cc2520_private *priv = hw->priv;782 783	if (!priv->amplified)784		return cc2520_set_tx_power(priv, mbm);785 786	return cc2520_cc2591_set_tx_power(priv, mbm);787}788 789static int790cc2520_set_promiscuous_mode(struct ieee802154_hw *hw, bool on)791{792	struct cc2520_private *priv = hw->priv;793	u8 frmfilt0;794 795	dev_dbg(&priv->spi->dev, "%s : mode %d\n", __func__, on);796 797	priv->promiscuous = on;798 799	cc2520_read_register(priv, CC2520_FRMFILT0, &frmfilt0);800 801	if (on) {802		/* Disable automatic ACK, automatic CRC, and frame filtering. */803		cc2520_write_register(priv, CC2520_FRMCTRL0, 0);804		frmfilt0 &= ~FRMFILT0_FRAME_FILTER_EN;805	} else {806		cc2520_write_register(priv, CC2520_FRMCTRL0, FRMCTRL0_AUTOACK |807							     FRMCTRL0_AUTOCRC);808		frmfilt0 |= FRMFILT0_FRAME_FILTER_EN;809	}810	return cc2520_write_register(priv, CC2520_FRMFILT0, frmfilt0);811}812 813static const struct ieee802154_ops cc2520_ops = {814	.owner = THIS_MODULE,815	.start = cc2520_start,816	.stop = cc2520_stop,817	.xmit_sync = cc2520_tx,818	.ed = cc2520_ed,819	.set_channel = cc2520_set_channel,820	.set_hw_addr_filt = cc2520_filter,821	.set_txpower = cc2520_set_txpower,822	.set_promiscuous_mode = cc2520_set_promiscuous_mode,823};824 825static int cc2520_register(struct cc2520_private *priv)826{827	int ret = -ENOMEM;828 829	priv->hw = ieee802154_alloc_hw(sizeof(*priv), &cc2520_ops);830	if (!priv->hw)831		goto err_ret;832 833	priv->hw->priv = priv;834	priv->hw->parent = &priv->spi->dev;835	priv->hw->extra_tx_headroom = 0;836	ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr);837 838	/* We do support only 2.4 Ghz */839	priv->hw->phy->supported.channels[0] = 0x7FFF800;840	priv->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |841			  IEEE802154_HW_PROMISCUOUS;842 843	priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER;844 845	if (!priv->amplified) {846		priv->hw->phy->supported.tx_powers = cc2520_powers;847		priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_powers);848		priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[4];849	} else {850		priv->hw->phy->supported.tx_powers = cc2520_cc2591_powers;851		priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_cc2591_powers);852		priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[0];853	}854 855	priv->hw->phy->current_channel = 11;856 857	dev_vdbg(&priv->spi->dev, "registered cc2520\n");858	ret = ieee802154_register_hw(priv->hw);859	if (ret)860		goto err_free_device;861 862	return 0;863 864err_free_device:865	ieee802154_free_hw(priv->hw);866err_ret:867	return ret;868}869 870static void cc2520_fifop_irqwork(struct work_struct *work)871{872	struct cc2520_private *priv873		= container_of(work, struct cc2520_private, fifop_irqwork);874 875	dev_dbg(&priv->spi->dev, "fifop interrupt received\n");876 877	if (gpiod_get_value(priv->fifo_pin))878		cc2520_rx(priv);879	else880		dev_dbg(&priv->spi->dev, "rxfifo overflow\n");881 882	cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHRX);883	cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHRX);884}885 886static irqreturn_t cc2520_fifop_isr(int irq, void *data)887{888	struct cc2520_private *priv = data;889 890	schedule_work(&priv->fifop_irqwork);891 892	return IRQ_HANDLED;893}894 895static irqreturn_t cc2520_sfd_isr(int irq, void *data)896{897	struct cc2520_private *priv = data;898	unsigned long flags;899 900	spin_lock_irqsave(&priv->lock, flags);901	if (priv->is_tx) {902		priv->is_tx = 0;903		spin_unlock_irqrestore(&priv->lock, flags);904		dev_dbg(&priv->spi->dev, "SFD for TX\n");905		complete(&priv->tx_complete);906	} else {907		spin_unlock_irqrestore(&priv->lock, flags);908		dev_dbg(&priv->spi->dev, "SFD for RX\n");909	}910 911	return IRQ_HANDLED;912}913 914static int cc2520_hw_init(struct cc2520_private *priv)915{916	u8 status = 0, state = 0xff;917	int ret;918	int timeout = 100;919 920	ret = cc2520_read_register(priv, CC2520_FSMSTAT1, &state);921	if (ret)922		goto err_ret;923 924	if (state != STATE_IDLE)925		return -EINVAL;926 927	do {928		ret = cc2520_get_status(priv, &status);929		if (ret)930			goto err_ret;931 932		if (timeout-- <= 0) {933			dev_err(&priv->spi->dev, "oscillator start failed!\n");934			return -ETIMEDOUT;935		}936		udelay(1);937	} while (!(status & CC2520_STATUS_XOSC32M_STABLE));938 939	dev_vdbg(&priv->spi->dev, "oscillator brought up\n");940 941	/* If the CC2520 is connected to a CC2591 amplifier, we must both942	 * configure GPIOs on the CC2520 to correctly configure the CC2591943	 * and change a couple settings of the CC2520 to work with the944	 * amplifier. See section 8 page 17 of TI application note AN065.945	 * http://www.ti.com/lit/an/swra229a/swra229a.pdf946	 */947	if (priv->amplified) {948		ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x16);949		if (ret)950			goto err_ret;951 952		ret = cc2520_write_register(priv, CC2520_GPIOCTRL0, 0x46);953		if (ret)954			goto err_ret;955 956		ret = cc2520_write_register(priv, CC2520_GPIOCTRL5, 0x47);957		if (ret)958			goto err_ret;959 960		ret = cc2520_write_register(priv, CC2520_GPIOPOLARITY, 0x1e);961		if (ret)962			goto err_ret;963 964		ret = cc2520_write_register(priv, CC2520_TXCTRL, 0xc1);965		if (ret)966			goto err_ret;967	} else {968		ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11);969		if (ret)970			goto err_ret;971	}972 973	/* Registers default value: section 28.1 in Datasheet */974 975	/* Set the CCA threshold to -50 dBm. This seems to have been copied976	 * from the TinyOS CC2520 driver and is much higher than the -84 dBm977	 * threshold suggested in the datasheet.978	 */979	ret = cc2520_write_register(priv, CC2520_CCACTRL0, 0x1A);980	if (ret)981		goto err_ret;982 983	ret = cc2520_write_register(priv, CC2520_MDMCTRL0, 0x85);984	if (ret)985		goto err_ret;986 987	ret = cc2520_write_register(priv, CC2520_MDMCTRL1, 0x14);988	if (ret)989		goto err_ret;990 991	ret = cc2520_write_register(priv, CC2520_RXCTRL, 0x3f);992	if (ret)993		goto err_ret;994 995	ret = cc2520_write_register(priv, CC2520_FSCTRL, 0x5a);996	if (ret)997		goto err_ret;998 999	ret = cc2520_write_register(priv, CC2520_FSCAL1, 0x2b);1000	if (ret)1001		goto err_ret;1002 1003	ret = cc2520_write_register(priv, CC2520_ADCTEST0, 0x10);1004	if (ret)1005		goto err_ret;1006 1007	ret = cc2520_write_register(priv, CC2520_ADCTEST1, 0x0e);1008	if (ret)1009		goto err_ret;1010 1011	ret = cc2520_write_register(priv, CC2520_ADCTEST2, 0x03);1012	if (ret)1013		goto err_ret;1014 1015	/* Configure registers correctly for this driver. */1016	ret = cc2520_write_register(priv, CC2520_FRMCTRL1,1017				    FRMCTRL1_SET_RXENMASK_ON_TX |1018				    FRMCTRL1_IGNORE_TX_UNDERF);1019	if (ret)1020		goto err_ret;1021 1022	ret = cc2520_write_register(priv, CC2520_FIFOPCTRL, 127);1023	if (ret)1024		goto err_ret;1025 1026	return 0;1027 1028err_ret:1029	return ret;1030}1031 1032static int cc2520_probe(struct spi_device *spi)1033{1034	struct cc2520_private *priv;1035	struct gpio_desc *fifop;1036	struct gpio_desc *cca;1037	struct gpio_desc *sfd;1038	struct gpio_desc *reset;1039	struct gpio_desc *vreg;1040	int ret;1041 1042	priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);1043	if (!priv)1044		return -ENOMEM;1045 1046	spi_set_drvdata(spi, priv);1047 1048	/* CC2591 front end for CC2520 */1049	/* Assumption that CC2591 is not connected */1050	priv->amplified = false;1051	if (device_property_read_bool(&spi->dev, "amplified"))1052		priv->amplified = true;1053 1054	priv->spi = spi;1055 1056	priv->buf = devm_kzalloc(&spi->dev,1057				 SPI_COMMAND_BUFFER, GFP_KERNEL);1058	if (!priv->buf)1059		return -ENOMEM;1060 1061	mutex_init(&priv->buffer_mutex);1062	INIT_WORK(&priv->fifop_irqwork, cc2520_fifop_irqwork);1063	spin_lock_init(&priv->lock);1064	init_completion(&priv->tx_complete);1065 1066	/* Request all the gpio's */1067	priv->fifo_pin = devm_gpiod_get(&spi->dev, "fifo", GPIOD_IN);1068	if (IS_ERR(priv->fifo_pin)) {1069		dev_err(&spi->dev, "fifo gpio is not valid\n");1070		ret = PTR_ERR(priv->fifo_pin);1071		goto err_hw_init;1072	}1073 1074	cca = devm_gpiod_get(&spi->dev, "cca", GPIOD_IN);1075	if (IS_ERR(cca)) {1076		dev_err(&spi->dev, "cca gpio is not valid\n");1077		ret = PTR_ERR(cca);1078		goto err_hw_init;1079	}1080 1081	fifop = devm_gpiod_get(&spi->dev, "fifop", GPIOD_IN);1082	if (IS_ERR(fifop)) {1083		dev_err(&spi->dev, "fifop gpio is not valid\n");1084		ret = PTR_ERR(fifop);1085		goto err_hw_init;1086	}1087 1088	sfd = devm_gpiod_get(&spi->dev, "sfd", GPIOD_IN);1089	if (IS_ERR(sfd)) {1090		dev_err(&spi->dev, "sfd gpio is not valid\n");1091		ret = PTR_ERR(sfd);1092		goto err_hw_init;1093	}1094 1095	reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);1096	if (IS_ERR(reset)) {1097		dev_err(&spi->dev, "reset gpio is not valid\n");1098		ret = PTR_ERR(reset);1099		goto err_hw_init;1100	}1101 1102	vreg = devm_gpiod_get(&spi->dev, "vreg", GPIOD_OUT_LOW);1103	if (IS_ERR(vreg)) {1104		dev_err(&spi->dev, "vreg gpio is not valid\n");1105		ret = PTR_ERR(vreg);1106		goto err_hw_init;1107	}1108 1109	gpiod_set_value(vreg, HIGH);1110	usleep_range(100, 150);1111 1112	gpiod_set_value(reset, HIGH);1113	usleep_range(200, 250);1114 1115	ret = cc2520_hw_init(priv);1116	if (ret)1117		goto err_hw_init;1118 1119	/* Set up fifop interrupt */1120	ret = devm_request_irq(&spi->dev,1121			       gpiod_to_irq(fifop),1122			       cc2520_fifop_isr,1123			       IRQF_TRIGGER_RISING,1124			       dev_name(&spi->dev),1125			       priv);1126	if (ret) {1127		dev_err(&spi->dev, "could not get fifop irq\n");1128		goto err_hw_init;1129	}1130 1131	/* Set up sfd interrupt */1132	ret = devm_request_irq(&spi->dev,1133			       gpiod_to_irq(sfd),1134			       cc2520_sfd_isr,1135			       IRQF_TRIGGER_FALLING,1136			       dev_name(&spi->dev),1137			       priv);1138	if (ret) {1139		dev_err(&spi->dev, "could not get sfd irq\n");1140		goto err_hw_init;1141	}1142 1143	ret = cc2520_register(priv);1144	if (ret)1145		goto err_hw_init;1146 1147	return 0;1148 1149err_hw_init:1150	mutex_destroy(&priv->buffer_mutex);1151	flush_work(&priv->fifop_irqwork);1152	return ret;1153}1154 1155static void cc2520_remove(struct spi_device *spi)1156{1157	struct cc2520_private *priv = spi_get_drvdata(spi);1158 1159	mutex_destroy(&priv->buffer_mutex);1160	flush_work(&priv->fifop_irqwork);1161 1162	ieee802154_unregister_hw(priv->hw);1163	ieee802154_free_hw(priv->hw);1164}1165 1166static const struct spi_device_id cc2520_ids[] = {1167	{"cc2520", },1168	{},1169};1170MODULE_DEVICE_TABLE(spi, cc2520_ids);1171 1172static const struct of_device_id cc2520_of_ids[] = {1173	{.compatible = "ti,cc2520", },1174	{},1175};1176MODULE_DEVICE_TABLE(of, cc2520_of_ids);1177 1178/* SPI driver structure */1179static struct spi_driver cc2520_driver = {1180	.driver = {1181		.name = "cc2520",1182		.of_match_table = cc2520_of_ids,1183	},1184	.id_table = cc2520_ids,1185	.probe = cc2520_probe,1186	.remove = cc2520_remove,1187};1188module_spi_driver(cc2520_driver);1189 1190MODULE_AUTHOR("Varka Bhadram <varkab@cdac.in>");1191MODULE_DESCRIPTION("CC2520 Transceiver Driver");1192MODULE_LICENSE("GPL v2");1193