ieee802154: drivers: use dev_alloc_skb
[firefly-linux-kernel-4.4.55.git] / drivers / net / ieee802154 / mrf24j40.c
index 07e0b887c350f07bb125b88479626187f814e828..7abb237cb98954e93542454122101c7277d225d2 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/spi/spi.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <net/wpan-phy.h>
+#include <linux/ieee802154.h>
+#include <net/cfg802154.h>
 #include <net/mac802154.h>
-#include <net/ieee802154.h>
 
 /* MRF24J40 Short Address Registers */
 #define REG_RXMCR    0x00  /* Receive MAC control */
@@ -43,6 +39,8 @@
 #define REG_TXSTBL   0x2E  /* TX Stabilization */
 #define REG_INTSTAT  0x31  /* Interrupt Status */
 #define REG_INTCON   0x32  /* Interrupt Control */
+#define REG_GPIO     0x33  /* GPIO */
+#define REG_TRISGPIO 0x34  /* GPIO direction */
 #define REG_RFCTL    0x36  /* RF Control Mode Register */
 #define REG_BBREG1   0x39  /* Baseband Registers */
 #define REG_BBREG2   0x3A  /* */
@@ -63,6 +61,7 @@
 #define REG_SLPCON1    0x220
 #define REG_WAKETIMEL  0x222  /* Wake-up Time Match Value Low */
 #define REG_WAKETIMEH  0x223  /* Wake-up Time Match Value High */
+#define REG_TESTMODE   0x22F  /* Test mode */
 #define REG_RX_FIFO    0x300  /* Receive FIFO */
 
 /* Device configuration: Only channels 11-26 on page 0 are supported. */
 #define RX_FIFO_SIZE 144 /* From datasheet */
 #define SET_CHANNEL_DELAY_US 192 /* From datasheet */
 
+enum mrf24j40_modules { MRF24J40, MRF24J40MA, MRF24J40MC };
+
 /* Device Private Data */
 struct mrf24j40 {
        struct spi_device *spi;
-       struct ieee802154_dev *dev;
+       struct ieee802154_hw *hw;
 
        struct mutex buffer_mutex; /* only used to protect buf */
        struct completion tx_complete;
@@ -331,9 +332,9 @@ out:
        return ret;
 }
 
-static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+static int mrf24j40_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
        u8 val;
        int ret = 0;
 
@@ -382,7 +383,7 @@ err:
        return ret;
 }
 
-static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
+static int mrf24j40_ed(struct ieee802154_hw *hw, u8 *level)
 {
        /* TODO: */
        pr_warn("mrf24j40: ed not implemented\n");
@@ -390,9 +391,9 @@ static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
        return 0;
 }
 
-static int mrf24j40_start(struct ieee802154_dev *dev)
+static int mrf24j40_start(struct ieee802154_hw *hw)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
        u8 val;
        int ret;
 
@@ -407,9 +408,9 @@ static int mrf24j40_start(struct ieee802154_dev *dev)
        return 0;
 }
 
-static void mrf24j40_stop(struct ieee802154_dev *dev)
+static void mrf24j40_stop(struct ieee802154_hw *hw)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
        u8 val;
        int ret;
 
@@ -422,10 +423,10 @@ static void mrf24j40_stop(struct ieee802154_dev *dev)
        write_short_reg(devrec, REG_INTCON, val);
 }
 
-static int mrf24j40_set_channel(struct ieee802154_dev *dev,
+static int mrf24j40_set_channel(struct ieee802154_hw *hw,
                                int page, int channel)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
        u8 val;
        int ret;
 
@@ -453,15 +454,15 @@ static int mrf24j40_set_channel(struct ieee802154_dev *dev,
        return 0;
 }
 
-static int mrf24j40_filter(struct ieee802154_dev *dev,
+static int mrf24j40_filter(struct ieee802154_hw *hw,
                           struct ieee802154_hw_addr_filt *filt,
                           unsigned long changed)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
 
        dev_dbg(printdev(devrec), "filter\n");
 
-       if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+       if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
                /* Short Addr */
                u8 addrh, addrl;
 
@@ -474,7 +475,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
                        "Set short addr to %04hx\n", filt->short_addr);
        }
 
-       if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+       if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
                /* Device Address */
                u8 i, addr[8];
 
@@ -490,7 +491,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
 #endif
        }
 
-       if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+       if (changed & IEEE802154_AFILT_PANID_CHANGED) {
                /* PAN ID */
                u8 panidl, panidh;
 
@@ -502,7 +503,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
                dev_dbg(printdev(devrec), "Set PANID to %04hx\n", filt->pan_id);
        }
 
-       if (changed & IEEE802515_AFILT_PANC_CHANGED) {
+       if (changed & IEEE802154_AFILT_PANC_CHANGED) {
                /* Pan Coordinator */
                u8 val;
                int ret;
@@ -543,7 +544,7 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec)
        val |= 4; /* SET RXDECINV */
        write_short_reg(devrec, REG_BBREG1, val);
 
-       skb = alloc_skb(len, GFP_KERNEL);
+       skb = dev_alloc_skb(len);
        if (!skb) {
                ret = -ENOMEM;
                goto out;
@@ -563,7 +564,7 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec)
        /* TODO: Other drivers call ieee20154_rx_irqsafe() here (eg: cc2040,
         * also from a workqueue).  I think irqsafe is not necessary here.
         * Can someone confirm? */
-       ieee802154_rx_irqsafe(devrec->dev, skb, lqi);
+       ieee802154_rx_irqsafe(devrec->hw, skb, lqi);
 
        dev_dbg(printdev(devrec), "RX Handled\n");
 
@@ -580,7 +581,7 @@ out:
 
 static struct ieee802154_ops mrf24j40_ops = {
        .owner = THIS_MODULE,
-       .xmit = mrf24j40_tx,
+       .xmit_sync = mrf24j40_tx,
        .ed = mrf24j40_ed,
        .start = mrf24j40_start,
        .stop = mrf24j40_stop,
@@ -691,6 +692,28 @@ static int mrf24j40_hw_init(struct mrf24j40 *devrec)
        if (ret)
                goto err_ret;
 
+       if (spi_get_device_id(devrec->spi)->driver_data == MRF24J40MC) {
+               /* Enable external amplifier.
+                * From MRF24J40MC datasheet section 1.3: Operation.
+                */
+               read_long_reg(devrec, REG_TESTMODE, &val);
+               val |= 0x7; /* Configure GPIO 0-2 to control amplifier */
+               write_long_reg(devrec, REG_TESTMODE, val);
+
+               read_short_reg(devrec, REG_TRISGPIO, &val);
+               val |= 0x8; /* Set GPIO3 as output. */
+               write_short_reg(devrec, REG_TRISGPIO, val);
+
+               read_short_reg(devrec, REG_GPIO, &val);
+               val |= 0x8; /* Set GPIO3 HIGH to enable U5 voltage regulator */
+               write_short_reg(devrec, REG_GPIO, val);
+
+               /* Reduce TX pwr to meet FCC requirements.
+                * From MRF24J40MC datasheet section 3.1.1
+                */
+               write_long_reg(devrec, REG_RFCON3, 0x28);
+       }
+
        return 0;
 
 err_ret:
@@ -722,17 +745,17 @@ static int mrf24j40_probe(struct spi_device *spi)
 
        /* Register with the 802154 subsystem */
 
-       devrec->dev = ieee802154_alloc_device(0, &mrf24j40_ops);
-       if (!devrec->dev)
+       devrec->hw = ieee802154_alloc_hw(0, &mrf24j40_ops);
+       if (!devrec->hw)
                goto err_ret;
 
-       devrec->dev->priv = devrec;
-       devrec->dev->parent = &devrec->spi->dev;
-       devrec->dev->phy->channels_supported[0] = CHANNEL_MASK;
-       devrec->dev->flags = IEEE802154_HW_OMIT_CKSUM|IEEE802154_HW_AACK;
+       devrec->hw->priv = devrec;
+       devrec->hw->parent = &devrec->spi->dev;
+       devrec->hw->phy->channels_supported[0] = CHANNEL_MASK;
+       devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM|IEEE802154_HW_AACK;
 
        dev_dbg(printdev(devrec), "registered mrf24j40\n");
-       ret = ieee802154_register_device(devrec->dev);
+       ret = ieee802154_register_hw(devrec->hw);
        if (ret)
                goto err_register_device;
 
@@ -757,9 +780,9 @@ static int mrf24j40_probe(struct spi_device *spi)
 
 err_irq:
 err_hw_init:
-       ieee802154_unregister_device(devrec->dev);
+       ieee802154_unregister_hw(devrec->hw);
 err_register_device:
-       ieee802154_free_device(devrec->dev);
+       ieee802154_free_hw(devrec->hw);
 err_ret:
        return ret;
 }
@@ -770,8 +793,8 @@ static int mrf24j40_remove(struct spi_device *spi)
 
        dev_dbg(printdev(devrec), "remove\n");
 
-       ieee802154_unregister_device(devrec->dev);
-       ieee802154_free_device(devrec->dev);
+       ieee802154_unregister_hw(devrec->hw);
+       ieee802154_free_hw(devrec->hw);
        /* TODO: Will ieee802154_free_device() wait until ->xmit() is
         * complete? */
 
@@ -779,8 +802,9 @@ static int mrf24j40_remove(struct spi_device *spi)
 }
 
 static const struct spi_device_id mrf24j40_ids[] = {
-       { "mrf24j40", 0 },
-       { "mrf24j40ma", 0 },
+       { "mrf24j40", MRF24J40 },
+       { "mrf24j40ma", MRF24J40MA },
+       { "mrf24j40mc", MRF24J40MC },
        { },
 };
 MODULE_DEVICE_TABLE(spi, mrf24j40_ids);