Diff
Modified: trunk/drivers/net/wireless/Kconfig (7834 => 7835)
--- trunk/drivers/net/wireless/Kconfig 2009-11-17 10:32:54 UTC (rev 7834)
+++ trunk/drivers/net/wireless/Kconfig 2009-11-17 10:36:21 UTC (rev 7835)
@@ -47,7 +47,7 @@
the ADF7025. This Ethernet like driver implements a custom
software PHY. Say Y if you want it compiled into the kernel.
To compile this driver as a module, choose M here. The module will
- be called adf702xnet.
+ be called adf702x.
config ARLAN
tristate "Aironet Arlan 655 & IC2200 DS support"
Modified: trunk/drivers/net/wireless/Makefile (7834 => 7835)
--- trunk/drivers/net/wireless/Makefile 2009-11-17 10:32:54 UTC (rev 7834)
+++ trunk/drivers/net/wireless/Makefile 2009-11-17 10:36:21 UTC (rev 7835)
@@ -7,7 +7,7 @@
obj-$(CONFIG_STRIP) += strip.o
obj-$(CONFIG_ARLAN) += arlan.o
-obj-$(CONFIG_ADF702X) += adf702xnet.o
+obj-$(CONFIG_ADF702X) += adf702x.o
arlan-objs := arlan-main.o arlan-proc.o
Copied: trunk/drivers/net/wireless/adf702x.c (from rev 7834, trunk/drivers/net/wireless/adf702xnet.c) (0 => 7835)
--- trunk/drivers/net/wireless/adf702x.c (rev 0)
+++ trunk/drivers/net/wireless/adf702x.c 2009-11-17 10:36:21 UTC (rev 7835)
@@ -0,0 +1,795 @@
+/*
+ * ADF702x Narrow-Band Short-Range Radio Transceiver
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+#include <asm/bfin_sport.h>
+
+#include <linux/spi/adf702x.h>
+
+/*
+ * DEBUG LEVEL
+ * 0 OFF
+ * 1 ERRORS
+ * 2 ERRORS + TRACE
+ * 3 ERRORS + TRACE + PACKET DUMP
+ */
+
+#define ADF_DEBUG 0
+#define DBG(n, args...) do { if (ADF_DEBUG >= (n)) pr_debug(args); } while (0)
+
+struct adf702x_priv {
+ struct spi_device *spi;
+ struct net_device *ndev;
+ struct sk_buff *tx_skb;
+ struct delayed_work tx_work;
+ struct work_struct tx_done_work;
+ wait_queue_head_t waitq;
+ dma_addr_t dma_handle;
+ spinlock_t lock;
+ unsigned rx_preample:1;
+ unsigned rx:1;
+ unsigned rx_size;
+ u32 *rx_buf;
+ u32 *tx_buf;
+
+ /* Base reg base of SPORT controller */
+ struct sport_register *sport;
+ unsigned dma_ch_rx;
+ unsigned dma_ch_tx;
+ unsigned irq_sport_err;
+ unsigned gpio_int_rfs;
+};
+
+static const u16 sym2chip[] = {
+ 0x744A,
+ 0x44AC,
+ 0x4AC3,
+ 0xAC39,
+ 0xC39B,
+ 0x39B7,
+ 0x9B74,
+ 0xB744,
+ 0xDEE2,
+ 0xEE26,
+ 0xE269,
+ 0x2693,
+ 0x6931,
+ 0x931D,
+ 0x31DE,
+ 0x1DEE,
+};
+
+#define MAGIC (0xA54662DA)
+#define RX_HEADERSIZE 4 /* ?(PREAMPLE) + MAGIC + LEN_HI + LEN_LO */
+#define TX_HEADERSIZE 5 /* PREAMPLE + PREAMPLE + MAGIC + LEN_HI + LEN_LO */
+#define FIFO_WA 6 /* Transfer additional words to workaround DMA FIFO issues */
+#define BITERR 4 /* MAX Bit Errors Allowed */
+#define REG0_DELAY 40 /* PLL settling delay in us */
+
+#define MAX_PACKET_SIZE (1550 * 4)
+
+/*
+ * ONES: A instruction only DSPs feature
+ * a XOR b -> return counted ONES (BIT Errors)
+ */
+static inline unsigned short adf702x_xor_ones(unsigned int a, unsigned int b)
+{
+ unsigned short val;
+
+ __asm__ __volatile__ (
+ "%0 = %1 ^ %2;"
+ "%0.l = ONES %0;"
+ : "=d"(val) : "d"(a), "d"(b)
+ );
+ return val;
+}
+
+/*
+ * Get 32-bit chip from 8-bit symbol
+ */
+static inline unsigned int adf702x_getchip(unsigned char sym)
+{
+ return (sym2chip[sym >> 4] << 16) | sym2chip[sym & 0xF];
+}
+
+/*
+ * Test packet MAGIC
+ */
+static inline int adf702x_testmagic(struct adf702x_priv *lp)
+{
+ if (adf702x_xor_ones(lp->rx_buf[1], MAGIC) < BITERR)
+ return 1;
+
+ if (adf702x_xor_ones(lp->rx_buf[0], MAGIC) < BITERR)
+ return 0;
+
+ return -1;
+}
+
+/*
+ * Get 8-bit symbol from 32-bit chip
+ * Returns: symbol or -1 in case of an unrecoverable error
+ */
+static int adf702x_getsymbol(unsigned int chip)
+{
+ int symhi, symlo;
+ unsigned chiphi, chiplo;
+
+ chiphi = chip >> 16;
+ chiplo = chip & 0xFFFF;
+
+ for (symhi = 0; symhi < ARRAY_SIZE(sym2chip); symhi++)
+ if (adf702x_xor_ones(chiphi, sym2chip[symhi]) < BITERR)
+ break;
+
+ if (symhi >= ARRAY_SIZE(sym2chip))
+ return -1;
+
+ for (symlo = 0; symlo < ARRAY_SIZE(sym2chip); symlo++)
+ if (adf702x_xor_ones(chiplo, sym2chip[symlo]) < BITERR)
+ break;
+
+ if (symlo >= ARRAY_SIZE(sym2chip))
+ return -1;
+
+ return (symhi << 4) | symlo;
+}
+
+/*
+ * Get Packet size from header
+ * Returns: size or 42 in case of an unrecoverable error
+ */
+inline unsigned short adf702x_getrxsize(struct adf702x_priv *lp, int offset)
+{
+ int size = adf702x_getsymbol(lp->rx_buf[offset + 1]) << 8 |
+ adf702x_getsymbol(lp->rx_buf[offset + 2]);
+
+ if (size > 0)
+ return size;
+
+ DBG(1, "%s :BITERR\n", __func__);
+ lp->ndev->stats.rx_errors++;
+ return 64; /* Keep the Receiver busy for some time */
+}
+
+static int adf702x_spi_write(struct spi_device *spi, unsigned int data)
+{
+ u16 msg[2];
+
+ msg[0] = data >> 16;
+ msg[1] = data;
+
+ return spi_write(spi, (u8 *)msg, 4);
+}
+
+static int adf702x_init(struct spi_device *spi)
+{
+ struct adf702x_platform_data *pdata = spi->dev.platform_data;
+
+ switch (pdata->adf702x_model) {
+ case MODEL_ADF7025:
+ adf702x_spi_write(spi, pdata->adf702x_regs[2]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[0]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[1]);
+ udelay(1000);
+ adf702x_spi_write(spi, pdata->adf702x_regs[3]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[4]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[6]);
+ udelay(300);
+ adf702x_spi_write(spi, pdata->adf702x_regs[5]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[9]);
+ break;
+ case MODEL_ADF7021:
+ adf702x_spi_write(spi, pdata->adf702x_regs[1]);
+ udelay(800);
+ adf702x_spi_write(spi, pdata->adf702x_regs[3]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[6]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[5]);
+ udelay(300);
+ adf702x_spi_write(spi, pdata->adf702x_regs[11]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[12]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[0]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[4]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[10]);
+ adf702x_spi_write(spi, pdata->adf702x_regs[2]);
+ break;
+ default:
+ dev_err(&spi->dev, "model not supported\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void adf702x_rx(struct spi_device *spi)
+{
+ struct adf702x_platform_data *pdata = spi->dev.platform_data;
+ adf702x_spi_write(spi, pdata->adf702x_regs[0]);
+ udelay(REG0_DELAY);
+ DBG(2, "%s():\n", __func__);
+}
+
+static void adf702x_tx(struct spi_device *spi)
+{
+ struct adf702x_platform_data *pdata = spi->dev.platform_data;
+ adf702x_spi_write(spi, pdata->tx_reg);
+ udelay(REG0_DELAY);
+ DBG(2, "%s():\n", __func__);
+}
+
+static void adf702x_sport_init(struct adf702x_priv *lp)
+{
+ struct adf702x_platform_data *pdata = lp->spi->dev.platform_data;
+
+ lp->sport->tcr2 = SLEN(32-1);
+ lp->sport->tcr1 = TCKFE | LATFS | DITFS | ITFS;
+ lp->sport->rcr2 = SLEN(32-1);
+ lp->sport->rcr1 = RCKFE | LARFS;
+
+ /*
+ * The ADF7025 requires SPORT TCLK generated externally
+ * it should be within 2% of CDR_CLK/32.
+ */
+ if (pdata->adf702x_model == MODEL_ADF7025) {
+ lp->sport->tcr1 = TCKFE | LATFS | DITFS | ITFS | ITCLK;
+ lp->sport->tclkdiv = pdata->adf7025_tclkdiv;
+ }
+}
+
+static void adf702x_setup_rx(struct adf702x_priv *lp)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lp->lock, flags);
+ lp->rx_preample = 1;
+ lp->rx = 0;
+ set_dma_x_count(lp->dma_ch_rx, RX_HEADERSIZE);
+ set_dma_start_addr(lp->dma_ch_rx, (unsigned long)lp->rx_buf);
+ enable_dma(lp->dma_ch_rx);
+ lp->sport->rcr1 |= RSPEN;
+ SSYNC();
+ spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static void adf702x_tx_work(struct work_struct *work)
+{
+ struct adf702x_priv *lp = container_of(work,
+ struct adf702x_priv, tx_work.work);
+
+ DBG(2, "%s: %s(): txDataCount(%d)\n",
+ lp->ndev->name, __func__, lp->tx_skb->len);
+
+ DBG(2, "GPIO = %d rx = %d\n", gpio_get_value(lp->gpio_int_rfs), lp->rx);
+
+ /*
+ * Do some media sense here
+ * Sleep while the media is busy
+ */
+
+ wait_event(lp->waitq, !(lp->rx || gpio_get_value(lp->gpio_int_rfs)));
+
+ lp->sport->rcr1 &= ~RSPEN;
+ SSYNC();
+ disable_dma(lp->dma_ch_rx);
+ clear_dma_irqstat(lp->dma_ch_rx);
+
+ adf702x_tx(lp->spi);
+
+ set_dma_x_count(lp->dma_ch_tx, lp->tx_skb->len + TX_HEADERSIZE + FIFO_WA);
+ set_dma_start_addr(lp->dma_ch_tx, (unsigned long)lp->tx_buf);
+ enable_dma(lp->dma_ch_tx);
+
+ lp->sport->tcr1 |= TSPEN;;
+ SSYNC();
+
+ lp->ndev->stats.tx_packets++;
+ lp->ndev->stats.tx_bytes += lp->tx_skb->len;
+}
+
+static void adf702x_tx_done_work(struct work_struct *work)
+{
+ struct adf702x_priv *lp = container_of(work,
+ struct adf702x_priv, tx_done_work);
+
+ DBG(2, "%s: %s(): \n", lp->ndev->name, __func__);
+
+ adf702x_setup_rx(lp);
+ adf702x_rx(lp->spi);
+
+ if (lp->tx_skb) {
+ dev_kfree_skb(lp->tx_skb);
+ lp->tx_skb = NULL;
+ }
+
+ netif_wake_queue(lp->ndev);
+}
+
+static int adf702x_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct adf702x_priv *lp = netdev_priv(dev);
+ unsigned char *buf_ptr = skb->data;
+ int i;
+ unsigned char delay;
+
+ DBG(2, "%s: %s(): transmitting %d bytes\n",
+ dev->name, __func__, skb->len);
+
+ if (!skb->len)
+ return 0;
+
+ /* Only one packet at a time. Once TXDONE interrupt is serviced, the
+ * queue will be restarted.
+ */
+ netif_stop_queue(dev);
+ /* save the timestamp */
+ lp->ndev->trans_start = jiffies;
+ /* Remember the skb for deferred processing */
+ lp->tx_skb = skb;
+
+ BUG_ON(lp->tx_skb->len > 0xFFFF);
+
+ lp->tx_buf[3] = adf702x_getchip(skb->len >> 8);
+ lp->tx_buf[4] = adf702x_getchip(skb->len & 0xFF);
+
+ DBG(3, "TX TX: ");
+ for (i = 0; i < skb->len; i++) {
+ lp->tx_buf[TX_HEADERSIZE + i] = adf702x_getchip(buf_ptr[i]);
+ DBG(3, "%x ", buf_ptr[i]);
+ }
+ DBG(3, "\n");
+
+ /* Avoid contentions
+ * Schedule transmission randomly (0..64ms)
+ * This allows other nodes to snip in
+ */
+
+ get_random_bytes(&delay, sizeof(delay));
+ schedule_delayed_work(&lp->tx_work, msecs_to_jiffies(delay >> 2));
+
+ return 0;
+}
+
+static int adf702x_receive(struct net_device *dev)
+{
+ struct sk_buff *skb;
+ struct adf702x_priv *lp = netdev_priv(dev);
+ int i, ret;
+ u8 *data;
+
+ DBG(2, "%s: %s(): \n", lp->ndev->name, __func__);
+
+ skb = dev_alloc_skb(lp->rx_size + NET_IP_ALIGN);
+ if (!skb) {
+ dev->stats.rx_dropped++;
+ return -ENOMEM;
+ }
+
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ data = "" lp->rx_size);
+
+ DBG(3, "RX RX: ");
+ for (i = 0; i < lp->rx_size; i++) {
+ data[i] = ret = adf702x_getsymbol(lp->rx_buf[i]);
+ if (ret < 0) {
+ dev->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ DBG(1, "\nRX BITERR chip = %x\n", lp->rx_buf[i]);
+ return -EIO;
+ }
+ DBG(3, "%x ", data[i]);
+ }
+ DBG(3, "\n");
+
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* No MAC filtering
+ * we're always in Promiscuous Mode
+ */
+
+ netif_rx(skb);
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += lp->rx_size;
+
+ return 0;
+}
+
+static irqreturn_t adf702x_sport_err_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct adf702x_priv *lp = netdev_priv(dev);
+ unsigned int stat = lp->sport->stat;
+
+ DBG(2, "%s: %s(): \n", lp->ndev->name, __func__);
+ /* Overflow in RX FIFO */
+ if (stat & ROVF)
+ DBG(1, "%s: %s(): ROVF\n", lp->ndev->name, __func__);
+
+ /* These should not happen */
+ if (stat & (TOVF | TUVF | RUVF)) {
+ DBG(1, "SPORT Error:%s %s %s\n",
+ (stat & TOVF) ? "TX overflow" : "",
+ (stat & TUVF) ? "TX underflow" : "",
+ (stat & RUVF) ? "RX underflow" : "");
+ }
+
+ disable_dma(lp->dma_ch_rx);
+ clear_dma_irqstat(lp->dma_ch_rx);
+
+ lp->sport->stat = ROVF | RUVF | TUVF | TOVF; /* Clear ROVF bit */
+ lp->sport->rcr1 &= ~RSPEN;
+ SSYNC();
+
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
+ adf702x_setup_rx(lp);
+ wake_up(&lp->waitq);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t adf702x_tx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct adf702x_priv *lp = netdev_priv(dev);
+
+ DBG(2, "%s:%s(): got TXDone\n",
+ dev->name, __func__);
+ lp->sport->tcr1 &= ~TSPEN;
+ disable_dma(lp->dma_ch_tx);
+ clear_dma_irqstat(lp->dma_ch_tx);
+ SSYNC();
+ schedule_work(&lp->tx_done_work);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t adf702x_rx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct adf702x_priv *lp = netdev_priv(dev);
+ int offset;
+ disable_dma(lp->dma_ch_rx);
+ clear_dma_irqstat(lp->dma_ch_rx);
+
+ if (lp->rx_preample) {
+ /*
+ * Keep the SPORT enabled
+ * The FIFO associated with the SPORT acts as buffer -
+ * while we setup the DMA for the remaining chips.
+ */
+
+ offset = adf702x_testmagic(lp);
+ if (offset >= 0) {
+ lp->rx_size = adf702x_getrxsize(lp, offset);
+ if (offset == 1) {
+ set_dma_x_count(lp->dma_ch_rx, lp->rx_size);
+ set_dma_start_addr(lp->dma_ch_rx,
+ (unsigned long)lp->rx_buf);
+ } else {
+ lp->rx_buf[0] = lp->rx_buf[3];
+ set_dma_x_count(lp->dma_ch_rx, lp->rx_size - 1);
+ set_dma_start_addr(lp->dma_ch_rx,
+ (unsigned long)&lp->rx_buf[1]);
+ }
+ enable_dma(lp->dma_ch_rx);
+ SSYNC();
+ lp->rx = 1;
+ lp->rx_preample = 0;
+
+ DBG(2, "%s:%s(): got RX data %d\n",
+ dev->name, __func__, lp->rx_size);
+
+ return IRQ_HANDLED;
+
+ } else {
+ DBG(1, "%s:%s(): Failed MAGIC\n",
+ dev->name, __func__);
+ lp->sport->rcr1 &= ~RSPEN;
+ SSYNC();
+ dev->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ }
+ } else {
+ lp->sport->rcr1 &= ~RSPEN;
+ SSYNC();
+ adf702x_receive(dev);
+ }
+
+ adf702x_setup_rx(lp);
+ wake_up(&lp->waitq);
+
+ return IRQ_HANDLED;
+}
+
+static int adf702x_net_open(struct net_device *dev)
+{
+ struct adf702x_priv *lp = netdev_priv(dev);
+ struct adf702x_platform_data *pdata = lp->spi->dev.platform_data;
+ unsigned int syncword;
+
+ DBG(2, "%s: %s()\n", dev->name, __func__);
+
+ adf702x_sport_init(lp);
+
+ set_dma_config(lp->dma_ch_rx,
+ set_bfin_dma_config(DIR_WRITE, DMA_FLOW_STOP,
+ INTR_ON_BUF, DIMENSION_LINEAR,
+ DATA_SIZE_32, DMA_SYNC_RESTART));
+
+ set_dma_config(lp->dma_ch_tx,
+ set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
+ INTR_ON_BUF, DIMENSION_LINEAR,
+ DATA_SIZE_32, DMA_SYNC_RESTART));
+
+ set_dma_x_modify(lp->dma_ch_rx, 4);
+ set_dma_x_modify(lp->dma_ch_tx, 4);
+
+ switch (pdata->adf702x_model) {
+ case MODEL_ADF7025:
+ syncword = 0xAA000000 | (pdata->adf702x_regs[5] >> 8);
+ break;
+ case MODEL_ADF7021:
+ syncword = 0xAA000000 | (pdata->adf702x_regs[11] >> 8);
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ lp->tx_buf[0] = syncword;
+ lp->tx_buf[1] = syncword;
+ lp->tx_buf[2] = MAGIC;
+
+ adf702x_setup_rx(lp);
+
+ dma_enable_irq(lp->dma_ch_rx);
+ adf702x_rx(lp->spi);
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int adf702x_net_close(struct net_device *dev)
+{
+ struct adf702x_priv *lp = netdev_priv(dev);
+ DBG(2, "%s: %s()\n", dev->name, __func__);
+
+ netif_stop_queue(dev);
+ dma_disable_irq(lp->dma_ch_rx);
+
+ return 0;
+}
+
+static const struct net_device_ops adf702x_netdev_ops = {
+ .ndo_open = adf702x_net_open,
+ .ndo_stop = adf702x_net_close,
+ .ndo_start_xmit = adf702x_net_xmit,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static int __devinit adf702x_probe(struct spi_device *spi)
+{
+ struct net_device *ndev;
+ struct adf702x_priv *lp;
+ struct adf702x_platform_data *pdata = spi->dev.platform_data;
+ int err;
+
+ if (!pdata) {
+ dev_dbg(&spi->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ ndev = alloc_etherdev(sizeof(*lp));
+ if (!ndev) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ dev_set_drvdata(&spi->dev, ndev);
+ SET_NETDEV_DEV(ndev, &spi->dev);
+
+ ndev->netdev_ops = &adf702x_netdev_ops;
+
+ /*
+ * MAC address? we use a
+ * random one ...
+ */
+
+ random_ether_addr(ndev->dev_addr);
+
+ ndev->mtu = 576;
+ ndev->tx_queue_len = 10;
+ ndev->watchdog_timeo = 0;
+
+ err = register_netdev(ndev);
+ if (err) {
+ dev_err(&spi->dev, "failed to register netdev\n");
+ goto out1;
+ }
+
+ lp = netdev_priv(ndev);
+ lp->ndev = ndev;
+ lp->spi = spi;
+
+ lp->sport = (struct sport_register *) pdata->regs_base;
+ lp->dma_ch_rx = pdata->dma_ch_rx;
+ lp->dma_ch_tx = pdata->dma_ch_tx;
+ lp->irq_sport_err = pdata->irq_sport_err;
+ lp->gpio_int_rfs = pdata->gpio_int_rfs;
+
+ err = peripheral_request_list(pdata->pin_req, dev_name(&spi->dev));
+ if (err) {
+ dev_err(&spi->dev, "failed to request SPORT\n");
+ goto out2;
+ }
+
+ err = request_dma(lp->dma_ch_rx, "SPORT RX Data");
+ if (err) {
+ dev_err(&spi->dev, "failed to request RX dma %d\n", lp->dma_ch_rx);
+ goto out3;
+ }
+
+ err = request_dma(lp->dma_ch_tx, "SPORT TX Data");
+ if (err) {
+ dev_err(&spi->dev, "failed to request TX dma %d\n", lp->dma_ch_tx);
+ goto out4;
+ }
+
+ err = set_dma_callback(lp->dma_ch_rx, adf702x_rx_interrupt, ndev);
+ if (err) {
+ dev_err(&spi->dev, "failed to request RX irq\n");
+ goto out5;
+ }
+
+ err = set_dma_callback(lp->dma_ch_tx, adf702x_tx_interrupt, ndev);
+ if (err) {
+ dev_err(&spi->dev, "failed to request TX irq\n");
+ goto out5;
+ }
+
+ dma_disable_irq(lp->dma_ch_rx);
+
+ if (lp->irq_sport_err) {
+ err = request_irq(lp->irq_sport_err, adf702x_sport_err_irq, 0,
+ "ADF702x SPORT_ERROR", ndev);
+ if (err) {
+ dev_err(&spi->dev, "unable to request SPORT status interrupt\n");
+ goto out5;
+ }
+ }
+
+ lp->rx_buf = dma_alloc_coherent(NULL, MAX_PACKET_SIZE,
+ &lp->dma_handle, GFP_KERNEL);
+
+ if (lp->rx_buf == NULL) {
+ err = -ENOMEM;
+ goto out6;
+ }
+
+ lp->tx_buf = dma_alloc_coherent(NULL, MAX_PACKET_SIZE,
+ &lp->dma_handle, GFP_KERNEL);
+
+ if (lp->rx_buf == NULL) {
+ err = -ENOMEM;
+ goto out7;
+ }
+
+ /*
+ * This GPIO is connected to the ADF702X INT
+ * The ADF702X SWD feature starts the SPORT RX DMA (INT connected to SPORT RFS)
+ * While the initial transfer runs (Preample, MAGIC and Packet length), we sense
+ * this GPIO to see if there is an ongoing transfer.
+ */
+
+ err = gpio_request(lp->gpio_int_rfs, "ADF702X-INT");
+ if (err)
+ goto out8;
+
+ gpio_direction_input(lp->gpio_int_rfs);
+
+ err = adf702x_init(lp->spi);
+ if (err)
+ goto out9;
+
+ spin_lock_init(&lp->lock);
+ INIT_DELAYED_WORK(&lp->tx_work, adf702x_tx_work);
+ INIT_WORK(&lp->tx_done_work, adf702x_tx_done_work);
+ init_waitqueue_head(&lp->waitq);
+
+ dev_info(&spi->dev, "ADF702XNet Wireless Ethernet driver");
+
+ return 0;
+
+out9:
+ gpio_free(lp->gpio_int_rfs);
+out8:
+ dma_free_coherent(NULL, MAX_PACKET_SIZE, lp->tx_buf, lp->dma_handle);
+out7:
+ dma_free_coherent(NULL, MAX_PACKET_SIZE, lp->rx_buf, lp->dma_handle);
+out6:
+ if (lp->irq_sport_err)
+ free_irq(lp->irq_sport_err, ndev);
+out5:
+ free_dma(lp->dma_ch_tx);
+out4:
+ free_dma(lp->dma_ch_rx);
+out3:
+ peripheral_free_list(pdata->pin_req);
+out2:
+ unregister_netdev(ndev);
+out1:
+ free_netdev(ndev);
+ dev_set_drvdata(&spi->dev, NULL);
+out:
+ return err;
+}
+
+static int __devexit adf702x_remove(struct spi_device *spi)
+{
+ struct adf702x_platform_data *pdata = spi->dev.platform_data;
+ struct net_device *dev = dev_get_drvdata(&spi->dev);
+ struct adf702x_priv *lp = netdev_priv(dev);
+
+ dma_free_coherent(NULL, MAX_PACKET_SIZE, lp->rx_buf, lp->dma_handle);
+ dma_free_coherent(NULL, MAX_PACKET_SIZE, lp->tx_buf, lp->dma_handle);
+
+ if (lp->irq_sport_err)
+ free_irq(lp->irq_sport_err, dev);
+
+ gpio_free(lp->gpio_int_rfs);
+ free_dma(lp->dma_ch_rx);
+ free_dma(lp->dma_ch_tx);
+ peripheral_free_list(pdata->pin_req);
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+ dev_set_drvdata(&spi->dev, NULL);
+ return 0;
+}
+
+static struct spi_driver adf702x_spi_driver = {
+ .driver = {
+ .name = "adf702x",
+ .owner = THIS_MODULE,
+ },
+ .probe = adf702x_probe,
+ .remove = __devexit_p(adf702x_remove),
+};
+
+static int __init adf702x_init_module(void)
+{
+ return spi_register_driver(&adf702x_spi_driver);;
+}
+
+static void __exit adf702x_exit_module(void)
+{
+ spi_unregister_driver(&adf702x_spi_driver);
+}
+
+module_init(adf702x_init_module);
+module_exit(adf702x_exit_module);
+MODULE_AUTHOR("Michael Hennerich <[email protected]>");
+MODULE_DESCRIPTION("ADF702XNet Wireless Ethernet driver");
+MODULE_LICENSE("GPL");
Deleted: trunk/drivers/net/wireless/adf702xnet.c (7834 => 7835)
--- trunk/drivers/net/wireless/adf702xnet.c 2009-11-17 10:32:54 UTC (rev 7834)
+++ trunk/drivers/net/wireless/adf702xnet.c 2009-11-17 10:36:21 UTC (rev 7835)
@@ -1,795 +0,0 @@
-/*
- * ADF702x Narrow-Band Short-Range Radio Transceiver
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/random.h>
-#include <linux/spinlock.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <asm/dma.h>
-#include <asm/portmux.h>
-#include <asm/bfin_sport.h>
-
-#include <linux/spi/adf702x.h>
-
-/*
- * DEBUG LEVEL
- * 0 OFF
- * 1 ERRORS
- * 2 ERRORS + TRACE
- * 3 ERRORS + TRACE + PACKET DUMP
- */
-
-#define ADF_DEBUG 0
-#define DBG(n, args...) do { if (ADF_DEBUG >= (n)) pr_debug(args); } while (0)
-
-struct adf702x_priv {
- struct spi_device *spi;
- struct net_device *ndev;
- struct sk_buff *tx_skb;
- struct delayed_work tx_work;
- struct work_struct tx_done_work;
- wait_queue_head_t waitq;
- dma_addr_t dma_handle;
- spinlock_t lock;
- unsigned rx_preample:1;
- unsigned rx:1;
- unsigned rx_size;
- u32 *rx_buf;
- u32 *tx_buf;
-
- /* Base reg base of SPORT controller */
- struct sport_register *sport;
- unsigned dma_ch_rx;
- unsigned dma_ch_tx;
- unsigned irq_sport_err;
- unsigned gpio_int_rfs;
-};
-
-static const u16 sym2chip[] = {
- 0x744A,
- 0x44AC,
- 0x4AC3,
- 0xAC39,
- 0xC39B,
- 0x39B7,
- 0x9B74,
- 0xB744,
- 0xDEE2,
- 0xEE26,
- 0xE269,
- 0x2693,
- 0x6931,
- 0x931D,
- 0x31DE,
- 0x1DEE,
-};
-
-#define MAGIC (0xA54662DA)
-#define RX_HEADERSIZE 4 /* ?(PREAMPLE) + MAGIC + LEN_HI + LEN_LO */
-#define TX_HEADERSIZE 5 /* PREAMPLE + PREAMPLE + MAGIC + LEN_HI + LEN_LO */
-#define FIFO_WA 6 /* Transfer additional words to workaround DMA FIFO issues */
-#define BITERR 4 /* MAX Bit Errors Allowed */
-#define REG0_DELAY 40 /* PLL settling delay in us */
-
-#define MAX_PACKET_SIZE (1550 * 4)
-
-/*
- * ONES: A instruction only DSPs feature
- * a XOR b -> return counted ONES (BIT Errors)
- */
-static inline unsigned short adf702x_xor_ones(unsigned int a, unsigned int b)
-{
- unsigned short val;
-
- __asm__ __volatile__ (
- "%0 = %1 ^ %2;"
- "%0.l = ONES %0;"
- : "=d"(val) : "d"(a), "d"(b)
- );
- return val;
-}
-
-/*
- * Get 32-bit chip from 8-bit symbol
- */
-static inline unsigned int adf702x_getchip(unsigned char sym)
-{
- return (sym2chip[sym >> 4] << 16) | sym2chip[sym & 0xF];
-}
-
-/*
- * Test packet MAGIC
- */
-static inline int adf702x_testmagic(struct adf702x_priv *lp)
-{
- if (adf702x_xor_ones(lp->rx_buf[1], MAGIC) < BITERR)
- return 1;
-
- if (adf702x_xor_ones(lp->rx_buf[0], MAGIC) < BITERR)
- return 0;
-
- return -1;
-}
-
-/*
- * Get 8-bit symbol from 32-bit chip
- * Returns: symbol or -1 in case of an unrecoverable error
- */
-static int adf702x_getsymbol(unsigned int chip)
-{
- int symhi, symlo;
- unsigned chiphi, chiplo;
-
- chiphi = chip >> 16;
- chiplo = chip & 0xFFFF;
-
- for (symhi = 0; symhi < ARRAY_SIZE(sym2chip); symhi++)
- if (adf702x_xor_ones(chiphi, sym2chip[symhi]) < BITERR)
- break;
-
- if (symhi >= ARRAY_SIZE(sym2chip))
- return -1;
-
- for (symlo = 0; symlo < ARRAY_SIZE(sym2chip); symlo++)
- if (adf702x_xor_ones(chiplo, sym2chip[symlo]) < BITERR)
- break;
-
- if (symlo >= ARRAY_SIZE(sym2chip))
- return -1;
-
- return (symhi << 4) | symlo;
-}
-
-/*
- * Get Packet size from header
- * Returns: size or 42 in case of an unrecoverable error
- */
-inline unsigned short adf702x_getrxsize(struct adf702x_priv *lp, int offset)
-{
- int size = adf702x_getsymbol(lp->rx_buf[offset + 1]) << 8 |
- adf702x_getsymbol(lp->rx_buf[offset + 2]);
-
- if (size > 0)
- return size;
-
- DBG(1, "%s :BITERR\n", __func__);
- lp->ndev->stats.rx_errors++;
- return 64; /* Keep the Receiver busy for some time */
-}
-
-static int adf702x_spi_write(struct spi_device *spi, unsigned int data)
-{
- u16 msg[2];
-
- msg[0] = data >> 16;
- msg[1] = data;
-
- return spi_write(spi, (u8 *)msg, 4);
-}
-
-static int adf702x_init(struct spi_device *spi)
-{
- struct adf702x_platform_data *pdata = spi->dev.platform_data;
-
- switch (pdata->adf702x_model) {
- case MODEL_ADF7025:
- adf702x_spi_write(spi, pdata->adf702x_regs[2]);
- adf702x_spi_write(spi, pdata->adf702x_regs[0]);
- adf702x_spi_write(spi, pdata->adf702x_regs[1]);
- udelay(1000);
- adf702x_spi_write(spi, pdata->adf702x_regs[3]);
- adf702x_spi_write(spi, pdata->adf702x_regs[4]);
- adf702x_spi_write(spi, pdata->adf702x_regs[6]);
- udelay(300);
- adf702x_spi_write(spi, pdata->adf702x_regs[5]);
- adf702x_spi_write(spi, pdata->adf702x_regs[9]);
- break;
- case MODEL_ADF7021:
- adf702x_spi_write(spi, pdata->adf702x_regs[1]);
- udelay(800);
- adf702x_spi_write(spi, pdata->adf702x_regs[3]);
- adf702x_spi_write(spi, pdata->adf702x_regs[6]);
- adf702x_spi_write(spi, pdata->adf702x_regs[5]);
- udelay(300);
- adf702x_spi_write(spi, pdata->adf702x_regs[11]);
- adf702x_spi_write(spi, pdata->adf702x_regs[12]);
- adf702x_spi_write(spi, pdata->adf702x_regs[0]);
- adf702x_spi_write(spi, pdata->adf702x_regs[4]);
- adf702x_spi_write(spi, pdata->adf702x_regs[10]);
- adf702x_spi_write(spi, pdata->adf702x_regs[2]);
- break;
- default:
- dev_err(&spi->dev, "model not supported\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void adf702x_rx(struct spi_device *spi)
-{
- struct adf702x_platform_data *pdata = spi->dev.platform_data;
- adf702x_spi_write(spi, pdata->adf702x_regs[0]);
- udelay(REG0_DELAY);
- DBG(2, "%s():\n", __func__);
-}
-
-static void adf702x_tx(struct spi_device *spi)
-{
- struct adf702x_platform_data *pdata = spi->dev.platform_data;
- adf702x_spi_write(spi, pdata->tx_reg);
- udelay(REG0_DELAY);
- DBG(2, "%s():\n", __func__);
-}
-
-static void adf702x_sport_init(struct adf702x_priv *lp)
-{
- struct adf702x_platform_data *pdata = lp->spi->dev.platform_data;
-
- lp->sport->tcr2 = SLEN(32-1);
- lp->sport->tcr1 = TCKFE | LATFS | DITFS | ITFS;
- lp->sport->rcr2 = SLEN(32-1);
- lp->sport->rcr1 = RCKFE | LARFS;
-
- /*
- * The ADF7025 requires SPORT TCLK generated externally
- * it should be within 2% of CDR_CLK/32.
- */
- if (pdata->adf702x_model == MODEL_ADF7025) {
- lp->sport->tcr1 = TCKFE | LATFS | DITFS | ITFS | ITCLK;
- lp->sport->tclkdiv = pdata->adf7025_tclkdiv;
- }
-}
-
-static void adf702x_setup_rx(struct adf702x_priv *lp)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&lp->lock, flags);
- lp->rx_preample = 1;
- lp->rx = 0;
- set_dma_x_count(lp->dma_ch_rx, RX_HEADERSIZE);
- set_dma_start_addr(lp->dma_ch_rx, (unsigned long)lp->rx_buf);
- enable_dma(lp->dma_ch_rx);
- lp->sport->rcr1 |= RSPEN;
- SSYNC();
- spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-static void adf702x_tx_work(struct work_struct *work)
-{
- struct adf702x_priv *lp = container_of(work,
- struct adf702x_priv, tx_work.work);
-
- DBG(2, "%s: %s(): txDataCount(%d)\n",
- lp->ndev->name, __func__, lp->tx_skb->len);
-
- DBG(2, "GPIO = %d rx = %d\n", gpio_get_value(lp->gpio_int_rfs), lp->rx);
-
- /*
- * Do some media sense here
- * Sleep while the media is busy
- */
-
- wait_event(lp->waitq, !(lp->rx || gpio_get_value(lp->gpio_int_rfs)));
-
- lp->sport->rcr1 &= ~RSPEN;
- SSYNC();
- disable_dma(lp->dma_ch_rx);
- clear_dma_irqstat(lp->dma_ch_rx);
-
- adf702x_tx(lp->spi);
-
- set_dma_x_count(lp->dma_ch_tx, lp->tx_skb->len + TX_HEADERSIZE + FIFO_WA);
- set_dma_start_addr(lp->dma_ch_tx, (unsigned long)lp->tx_buf);
- enable_dma(lp->dma_ch_tx);
-
- lp->sport->tcr1 |= TSPEN;;
- SSYNC();
-
- lp->ndev->stats.tx_packets++;
- lp->ndev->stats.tx_bytes += lp->tx_skb->len;
-}
-
-static void adf702x_tx_done_work(struct work_struct *work)
-{
- struct adf702x_priv *lp = container_of(work,
- struct adf702x_priv, tx_done_work);
-
- DBG(2, "%s: %s(): \n", lp->ndev->name, __func__);
-
- adf702x_setup_rx(lp);
- adf702x_rx(lp->spi);
-
- if (lp->tx_skb) {
- dev_kfree_skb(lp->tx_skb);
- lp->tx_skb = NULL;
- }
-
- netif_wake_queue(lp->ndev);
-}
-
-static int adf702x_net_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct adf702x_priv *lp = netdev_priv(dev);
- unsigned char *buf_ptr = skb->data;
- int i;
- unsigned char delay;
-
- DBG(2, "%s: %s(): transmitting %d bytes\n",
- dev->name, __func__, skb->len);
-
- if (!skb->len)
- return 0;
-
- /* Only one packet at a time. Once TXDONE interrupt is serviced, the
- * queue will be restarted.
- */
- netif_stop_queue(dev);
- /* save the timestamp */
- lp->ndev->trans_start = jiffies;
- /* Remember the skb for deferred processing */
- lp->tx_skb = skb;
-
- BUG_ON(lp->tx_skb->len > 0xFFFF);
-
- lp->tx_buf[3] = adf702x_getchip(skb->len >> 8);
- lp->tx_buf[4] = adf702x_getchip(skb->len & 0xFF);
-
- DBG(3, "TX TX: ");
- for (i = 0; i < skb->len; i++) {
- lp->tx_buf[TX_HEADERSIZE + i] = adf702x_getchip(buf_ptr[i]);
- DBG(3, "%x ", buf_ptr[i]);
- }
- DBG(3, "\n");
-
- /* Avoid contentions
- * Schedule transmission randomly (0..64ms)
- * This allows other nodes to snip in
- */
-
- get_random_bytes(&delay, sizeof(delay));
- schedule_delayed_work(&lp->tx_work, msecs_to_jiffies(delay >> 2));
-
- return 0;
-}
-
-static int adf702x_receive(struct net_device *dev)
-{
- struct sk_buff *skb;
- struct adf702x_priv *lp = netdev_priv(dev);
- int i, ret;
- u8 *data;
-
- DBG(2, "%s: %s(): \n", lp->ndev->name, __func__);
-
- skb = dev_alloc_skb(lp->rx_size + NET_IP_ALIGN);
- if (!skb) {
- dev->stats.rx_dropped++;
- return -ENOMEM;
- }
-
- skb_reserve(skb, NET_IP_ALIGN);
-
- data = "" lp->rx_size);
-
- DBG(3, "RX RX: ");
- for (i = 0; i < lp->rx_size; i++) {
- data[i] = ret = adf702x_getsymbol(lp->rx_buf[i]);
- if (ret < 0) {
- dev->stats.rx_errors++;
- dev_kfree_skb(skb);
- DBG(1, "\nRX BITERR chip = %x\n", lp->rx_buf[i]);
- return -EIO;
- }
- DBG(3, "%x ", data[i]);
- }
- DBG(3, "\n");
-
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
-
- /* No MAC filtering
- * we're always in Promiscuous Mode
- */
-
- netif_rx(skb);
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += lp->rx_size;
-
- return 0;
-}
-
-static irqreturn_t adf702x_sport_err_irq(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct adf702x_priv *lp = netdev_priv(dev);
- unsigned int stat = lp->sport->stat;
-
- DBG(2, "%s: %s(): \n", lp->ndev->name, __func__);
- /* Overflow in RX FIFO */
- if (stat & ROVF)
- DBG(1, "%s: %s(): ROVF\n", lp->ndev->name, __func__);
-
- /* These should not happen */
- if (stat & (TOVF | TUVF | RUVF)) {
- DBG(1, "SPORT Error:%s %s %s\n",
- (stat & TOVF) ? "TX overflow" : "",
- (stat & TUVF) ? "TX underflow" : "",
- (stat & RUVF) ? "RX underflow" : "");
- }
-
- disable_dma(lp->dma_ch_rx);
- clear_dma_irqstat(lp->dma_ch_rx);
-
- lp->sport->stat = ROVF | RUVF | TUVF | TOVF; /* Clear ROVF bit */
- lp->sport->rcr1 &= ~RSPEN;
- SSYNC();
-
- dev->stats.rx_over_errors++;
- dev->stats.rx_errors++;
- adf702x_setup_rx(lp);
- wake_up(&lp->waitq);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t adf702x_tx_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct adf702x_priv *lp = netdev_priv(dev);
-
- DBG(2, "%s:%s(): got TXDone\n",
- dev->name, __func__);
- lp->sport->tcr1 &= ~TSPEN;
- disable_dma(lp->dma_ch_tx);
- clear_dma_irqstat(lp->dma_ch_tx);
- SSYNC();
- schedule_work(&lp->tx_done_work);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t adf702x_rx_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct adf702x_priv *lp = netdev_priv(dev);
- int offset;
- disable_dma(lp->dma_ch_rx);
- clear_dma_irqstat(lp->dma_ch_rx);
-
- if (lp->rx_preample) {
- /*
- * Keep the SPORT enabled
- * The FIFO associated with the SPORT acts as buffer -
- * while we setup the DMA for the remaining chips.
- */
-
- offset = adf702x_testmagic(lp);
- if (offset >= 0) {
- lp->rx_size = adf702x_getrxsize(lp, offset);
- if (offset == 1) {
- set_dma_x_count(lp->dma_ch_rx, lp->rx_size);
- set_dma_start_addr(lp->dma_ch_rx,
- (unsigned long)lp->rx_buf);
- } else {
- lp->rx_buf[0] = lp->rx_buf[3];
- set_dma_x_count(lp->dma_ch_rx, lp->rx_size - 1);
- set_dma_start_addr(lp->dma_ch_rx,
- (unsigned long)&lp->rx_buf[1]);
- }
- enable_dma(lp->dma_ch_rx);
- SSYNC();
- lp->rx = 1;
- lp->rx_preample = 0;
-
- DBG(2, "%s:%s(): got RX data %d\n",
- dev->name, __func__, lp->rx_size);
-
- return IRQ_HANDLED;
-
- } else {
- DBG(1, "%s:%s(): Failed MAGIC\n",
- dev->name, __func__);
- lp->sport->rcr1 &= ~RSPEN;
- SSYNC();
- dev->stats.rx_dropped++;
- dev->stats.rx_errors++;
- }
- } else {
- lp->sport->rcr1 &= ~RSPEN;
- SSYNC();
- adf702x_receive(dev);
- }
-
- adf702x_setup_rx(lp);
- wake_up(&lp->waitq);
-
- return IRQ_HANDLED;
-}
-
-static int adf702x_net_open(struct net_device *dev)
-{
- struct adf702x_priv *lp = netdev_priv(dev);
- struct adf702x_platform_data *pdata = lp->spi->dev.platform_data;
- unsigned int syncword;
-
- DBG(2, "%s: %s()\n", dev->name, __func__);
-
- adf702x_sport_init(lp);
-
- set_dma_config(lp->dma_ch_rx,
- set_bfin_dma_config(DIR_WRITE, DMA_FLOW_STOP,
- INTR_ON_BUF, DIMENSION_LINEAR,
- DATA_SIZE_32, DMA_SYNC_RESTART));
-
- set_dma_config(lp->dma_ch_tx,
- set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
- INTR_ON_BUF, DIMENSION_LINEAR,
- DATA_SIZE_32, DMA_SYNC_RESTART));
-
- set_dma_x_modify(lp->dma_ch_rx, 4);
- set_dma_x_modify(lp->dma_ch_tx, 4);
-
- switch (pdata->adf702x_model) {
- case MODEL_ADF7025:
- syncword = 0xAA000000 | (pdata->adf702x_regs[5] >> 8);
- break;
- case MODEL_ADF7021:
- syncword = 0xAA000000 | (pdata->adf702x_regs[11] >> 8);
- break;
- default:
- return -ENODEV;
- }
-
- lp->tx_buf[0] = syncword;
- lp->tx_buf[1] = syncword;
- lp->tx_buf[2] = MAGIC;
-
- adf702x_setup_rx(lp);
-
- dma_enable_irq(lp->dma_ch_rx);
- adf702x_rx(lp->spi);
- netif_start_queue(dev);
-
- return 0;
-}
-
-static int adf702x_net_close(struct net_device *dev)
-{
- struct adf702x_priv *lp = netdev_priv(dev);
- DBG(2, "%s: %s()\n", dev->name, __func__);
-
- netif_stop_queue(dev);
- dma_disable_irq(lp->dma_ch_rx);
-
- return 0;
-}
-
-static const struct net_device_ops adf702x_netdev_ops = {
- .ndo_open = adf702x_net_open,
- .ndo_stop = adf702x_net_close,
- .ndo_start_xmit = adf702x_net_xmit,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
-};
-
-static int __devinit adf702x_probe(struct spi_device *spi)
-{
- struct net_device *ndev;
- struct adf702x_priv *lp;
- struct adf702x_platform_data *pdata = spi->dev.platform_data;
- int err;
-
- if (!pdata) {
- dev_dbg(&spi->dev, "no platform data?\n");
- return -ENODEV;
- }
-
- ndev = alloc_etherdev(sizeof(*lp));
- if (!ndev) {
- err = -ENOMEM;
- goto out;
- }
-
- dev_set_drvdata(&spi->dev, ndev);
- SET_NETDEV_DEV(ndev, &spi->dev);
-
- ndev->netdev_ops = &adf702x_netdev_ops;
-
- /*
- * MAC address? we use a
- * random one ...
- */
-
- random_ether_addr(ndev->dev_addr);
-
- ndev->mtu = 576;
- ndev->tx_queue_len = 10;
- ndev->watchdog_timeo = 0;
-
- err = register_netdev(ndev);
- if (err) {
- dev_err(&spi->dev, "failed to register netdev\n");
- goto out1;
- }
-
- lp = netdev_priv(ndev);
- lp->ndev = ndev;
- lp->spi = spi;
-
- lp->sport = (struct sport_register *) pdata->regs_base;
- lp->dma_ch_rx = pdata->dma_ch_rx;
- lp->dma_ch_tx = pdata->dma_ch_tx;
- lp->irq_sport_err = pdata->irq_sport_err;
- lp->gpio_int_rfs = pdata->gpio_int_rfs;
-
- err = peripheral_request_list(pdata->pin_req, dev_name(&spi->dev));
- if (err) {
- dev_err(&spi->dev, "failed to request SPORT\n");
- goto out2;
- }
-
- err = request_dma(lp->dma_ch_rx, "SPORT RX Data");
- if (err) {
- dev_err(&spi->dev, "failed to request RX dma %d\n", lp->dma_ch_rx);
- goto out3;
- }
-
- err = request_dma(lp->dma_ch_tx, "SPORT TX Data");
- if (err) {
- dev_err(&spi->dev, "failed to request TX dma %d\n", lp->dma_ch_tx);
- goto out4;
- }
-
- err = set_dma_callback(lp->dma_ch_rx, adf702x_rx_interrupt, ndev);
- if (err) {
- dev_err(&spi->dev, "failed to request RX irq\n");
- goto out5;
- }
-
- err = set_dma_callback(lp->dma_ch_tx, adf702x_tx_interrupt, ndev);
- if (err) {
- dev_err(&spi->dev, "failed to request TX irq\n");
- goto out5;
- }
-
- dma_disable_irq(lp->dma_ch_rx);
-
- if (lp->irq_sport_err) {
- err = request_irq(lp->irq_sport_err, adf702x_sport_err_irq, 0,
- "ADF702x SPORT_ERROR", ndev);
- if (err) {
- dev_err(&spi->dev, "unable to request SPORT status interrupt\n");
- goto out5;
- }
- }
-
- lp->rx_buf = dma_alloc_coherent(NULL, MAX_PACKET_SIZE,
- &lp->dma_handle, GFP_KERNEL);
-
- if (lp->rx_buf == NULL) {
- err = -ENOMEM;
- goto out6;
- }
-
- lp->tx_buf = dma_alloc_coherent(NULL, MAX_PACKET_SIZE,
- &lp->dma_handle, GFP_KERNEL);
-
- if (lp->rx_buf == NULL) {
- err = -ENOMEM;
- goto out7;
- }
-
- /*
- * This GPIO is connected to the ADF702X INT
- * The ADF702X SWD feature starts the SPORT RX DMA (INT connected to SPORT RFS)
- * While the initial transfer runs (Preample, MAGIC and Packet length), we sense
- * this GPIO to see if there is an ongoing transfer.
- */
-
- err = gpio_request(lp->gpio_int_rfs, "ADF702X-INT");
- if (err)
- goto out8;
-
- gpio_direction_input(lp->gpio_int_rfs);
-
- err = adf702x_init(lp->spi);
- if (err)
- goto out9;
-
- spin_lock_init(&lp->lock);
- INIT_DELAYED_WORK(&lp->tx_work, adf702x_tx_work);
- INIT_WORK(&lp->tx_done_work, adf702x_tx_done_work);
- init_waitqueue_head(&lp->waitq);
-
- dev_info(&spi->dev, "ADF702XNet Wireless Ethernet driver");
-
- return 0;
-
-out9:
- gpio_free(lp->gpio_int_rfs);
-out8:
- dma_free_coherent(NULL, MAX_PACKET_SIZE, lp->tx_buf, lp->dma_handle);
-out7:
- dma_free_coherent(NULL, MAX_PACKET_SIZE, lp->rx_buf, lp->dma_handle);
-out6:
- if (lp->irq_sport_err)
- free_irq(lp->irq_sport_err, ndev);
-out5:
- free_dma(lp->dma_ch_tx);
-out4:
- free_dma(lp->dma_ch_rx);
-out3:
- peripheral_free_list(pdata->pin_req);
-out2:
- unregister_netdev(ndev);
-out1:
- free_netdev(ndev);
- dev_set_drvdata(&spi->dev, NULL);
-out:
- return err;
-}
-
-static int __devexit adf702x_remove(struct spi_device *spi)
-{
- struct adf702x_platform_data *pdata = spi->dev.platform_data;
- struct net_device *dev = dev_get_drvdata(&spi->dev);
- struct adf702x_priv *lp = netdev_priv(dev);
-
- dma_free_coherent(NULL, MAX_PACKET_SIZE, lp->rx_buf, lp->dma_handle);
- dma_free_coherent(NULL, MAX_PACKET_SIZE, lp->tx_buf, lp->dma_handle);
-
- if (lp->irq_sport_err)
- free_irq(lp->irq_sport_err, dev);
-
- gpio_free(lp->gpio_int_rfs);
- free_dma(lp->dma_ch_rx);
- free_dma(lp->dma_ch_tx);
- peripheral_free_list(pdata->pin_req);
-
- unregister_netdev(dev);
- free_netdev(dev);
- dev_set_drvdata(&spi->dev, NULL);
- return 0;
-}
-
-static struct spi_driver adf702x_spi_driver = {
- .driver = {
- .name = "adf702x",
- .owner = THIS_MODULE,
- },
- .probe = adf702x_probe,
- .remove = __devexit_p(adf702x_remove),
-};
-
-static int __init adf702x_init_module(void)
-{
- return spi_register_driver(&adf702x_spi_driver);;
-}
-
-static void __exit adf702x_exit_module(void)
-{
- spi_unregister_driver(&adf702x_spi_driver);
-}
-
-module_init(adf702x_init_module);
-module_exit(adf702x_exit_module);
-MODULE_AUTHOR("Michael Hennerich <[email protected]>");
-MODULE_DESCRIPTION("ADF702XNet Wireless Ethernet driver");
-MODULE_LICENSE("GPL");