These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / ieee802154 / cc2520.c
index f833b8b..e65b605 100644 (file)
@@ -196,6 +196,7 @@ struct cc2520_private {
        u8 *buf;                        /* SPI TX/Rx data buffer */
        struct mutex buffer_mutex;      /* SPI buffer mutex */
        bool is_tx;                     /* Flag for sync b/w Tx and Rx */
+       bool amplified;                 /* Flag for CC2591 */
        int fifo_pin;                   /* FIFO GPIO pin number */
        struct work_struct fifop_irqwork;/* Workqueue for FIFOP */
        spinlock_t lock;                /* Lock for is_tx*/
@@ -589,22 +590,23 @@ cc2520_filter(struct ieee802154_hw *hw,
              struct ieee802154_hw_addr_filt *filt, unsigned long changed)
 {
        struct cc2520_private *priv = hw->priv;
+       int ret = 0;
 
        if (changed & IEEE802154_AFILT_PANID_CHANGED) {
                u16 panid = le16_to_cpu(filt->pan_id);
 
                dev_vdbg(&priv->spi->dev,
                         "cc2520_filter called for pan id\n");
-               cc2520_write_ram(priv, CC2520RAM_PANID,
-                                sizeof(panid), (u8 *)&panid);
+               ret = cc2520_write_ram(priv, CC2520RAM_PANID,
+                                      sizeof(panid), (u8 *)&panid);
        }
 
        if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
                dev_vdbg(&priv->spi->dev,
                         "cc2520_filter called for IEEE addr\n");
-               cc2520_write_ram(priv, CC2520RAM_IEEEADDR,
-                                sizeof(filt->ieee_addr),
-                                (u8 *)&filt->ieee_addr);
+               ret = cc2520_write_ram(priv, CC2520RAM_IEEEADDR,
+                                      sizeof(filt->ieee_addr),
+                                      (u8 *)&filt->ieee_addr);
        }
 
        if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
@@ -612,20 +614,113 @@ cc2520_filter(struct ieee802154_hw *hw,
 
                dev_vdbg(&priv->spi->dev,
                         "cc2520_filter called for saddr\n");
-               cc2520_write_ram(priv, CC2520RAM_SHORTADDR,
-                                sizeof(addr), (u8 *)&addr);
+               ret = cc2520_write_ram(priv, CC2520RAM_SHORTADDR,
+                                      sizeof(addr), (u8 *)&addr);
        }
 
        if (changed & IEEE802154_AFILT_PANC_CHANGED) {
                dev_vdbg(&priv->spi->dev,
                         "cc2520_filter called for panc change\n");
                if (filt->pan_coord)
-                       cc2520_write_register(priv, CC2520_FRMFILT0, 0x02);
+                       ret = cc2520_write_register(priv, CC2520_FRMFILT0,
+                                                   0x02);
                else
-                       cc2520_write_register(priv, CC2520_FRMFILT0, 0x00);
+                       ret = cc2520_write_register(priv, CC2520_FRMFILT0,
+                                                   0x00);
        }
 
-       return 0;
+       return ret;
+}
+
+static inline int cc2520_set_tx_power(struct cc2520_private *priv, s32 mbm)
+{
+       u8 power;
+
+       switch (mbm) {
+       case 500:
+               power = 0xF7;
+               break;
+       case 300:
+               power = 0xF2;
+               break;
+       case 200:
+               power = 0xAB;
+               break;
+       case 100:
+               power = 0x13;
+               break;
+       case 0:
+               power = 0x32;
+               break;
+       case -200:
+               power = 0x81;
+               break;
+       case -400:
+               power = 0x88;
+               break;
+       case -700:
+               power = 0x2C;
+               break;
+       case -1800:
+               power = 0x03;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return cc2520_write_register(priv, CC2520_TXPOWER, power);
+}
+
+static inline int cc2520_cc2591_set_tx_power(struct cc2520_private *priv,
+                                            s32 mbm)
+{
+       u8 power;
+
+       switch (mbm) {
+       case 1700:
+               power = 0xF9;
+               break;
+       case 1600:
+               power = 0xF0;
+               break;
+       case 1400:
+               power = 0xA0;
+               break;
+       case 1100:
+               power = 0x2C;
+               break;
+       case -100:
+               power = 0x03;
+               break;
+       case -800:
+               power = 0x01;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return cc2520_write_register(priv, CC2520_TXPOWER, power);
+}
+
+#define CC2520_MAX_TX_POWERS 0x8
+static const s32 cc2520_powers[CC2520_MAX_TX_POWERS + 1] = {
+       500, 300, 200, 100, 0, -200, -400, -700, -1800,
+};
+
+#define CC2520_CC2591_MAX_TX_POWERS 0x5
+static const s32 cc2520_cc2591_powers[CC2520_CC2591_MAX_TX_POWERS + 1] = {
+       1700, 1600, 1400, 1100, -100, -800,
+};
+
+static int
+cc2520_set_txpower(struct ieee802154_hw *hw, s32 mbm)
+{
+       struct cc2520_private *priv = hw->priv;
+
+       if (!priv->amplified)
+               return cc2520_set_tx_power(priv, mbm);
+
+       return cc2520_cc2591_set_tx_power(priv, mbm);
 }
 
 static const struct ieee802154_ops cc2520_ops = {
@@ -636,6 +731,7 @@ static const struct ieee802154_ops cc2520_ops = {
        .ed = cc2520_ed,
        .set_channel = cc2520_set_channel,
        .set_hw_addr_filt = cc2520_filter,
+       .set_txpower = cc2520_set_txpower,
 };
 
 static int cc2520_register(struct cc2520_private *priv)
@@ -649,13 +745,25 @@ static int cc2520_register(struct cc2520_private *priv)
        priv->hw->priv = priv;
        priv->hw->parent = &priv->spi->dev;
        priv->hw->extra_tx_headroom = 0;
-       priv->hw->vif_data_size = sizeof(*priv);
        ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr);
 
        /* We do support only 2.4 Ghz */
-       priv->hw->phy->channels_supported[0] = 0x7FFF800;
-       priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
-                         IEEE802154_HW_AFILT;
+       priv->hw->phy->supported.channels[0] = 0x7FFF800;
+       priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT;
+
+       priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER;
+
+       if (!priv->amplified) {
+               priv->hw->phy->supported.tx_powers = cc2520_powers;
+               priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_powers);
+               priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[4];
+       } else {
+               priv->hw->phy->supported.tx_powers = cc2520_cc2591_powers;
+               priv->hw->phy->supported.tx_powers_size = ARRAY_SIZE(cc2520_cc2591_powers);
+               priv->hw->phy->transmit_power = priv->hw->phy->supported.tx_powers[0];
+       }
+
+       priv->hw->phy->current_channel = 11;
 
        dev_vdbg(&priv->spi->dev, "registered cc2520\n");
        ret = ieee802154_register_hw(priv->hw);
@@ -725,6 +833,7 @@ static int cc2520_get_platform_data(struct spi_device *spi,
                if (!spi_pdata)
                        return -ENOENT;
                *pdata = *spi_pdata;
+               priv->fifo_pin = pdata->fifo;
                return 0;
        }
 
@@ -738,7 +847,9 @@ static int cc2520_get_platform_data(struct spi_device *spi,
        pdata->vreg = of_get_named_gpio(np, "vreg-gpio", 0);
        pdata->reset = of_get_named_gpio(np, "reset-gpio", 0);
 
-       pdata->amplified = of_property_read_bool(np, "amplified");
+       /* CC2591 front end for CC2520 */
+       if (of_property_read_bool(np, "amplified"))
+               priv->amplified = true;
 
        return 0;
 }
@@ -781,11 +892,7 @@ static int cc2520_hw_init(struct cc2520_private *priv)
         * amplifier. See section 8 page 17 of TI application note AN065.
         * http://www.ti.com/lit/an/swra229a/swra229a.pdf
         */
-       if (pdata.amplified) {
-               ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF9);
-               if (ret)
-                       goto err_ret;
-
+       if (priv->amplified) {
                ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x16);
                if (ret)
                        goto err_ret;
@@ -806,10 +913,6 @@ static int cc2520_hw_init(struct cc2520_private *priv)
                if (ret)
                        goto err_ret;
        } else {
-               ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF7);
-               if (ret)
-                       goto err_ret;
-
                ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11);
                if (ret)
                        goto err_ret;
@@ -904,6 +1007,9 @@ static int cc2520_probe(struct spi_device *spi)
        spin_lock_init(&priv->lock);
        init_completion(&priv->tx_complete);
 
+       /* Assumption that CC2591 is not connected */
+       priv->amplified = false;
+
        /* Request all the gpio's */
        if (!gpio_is_valid(pdata.fifo)) {
                dev_err(&spi->dev, "fifo gpio is not valid\n");
@@ -1046,8 +1152,6 @@ MODULE_DEVICE_TABLE(of, cc2520_of_ids);
 static struct spi_driver cc2520_driver = {
        .driver = {
                .name = "cc2520",
-               .bus = &spi_bus_type,
-               .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(cc2520_of_ids),
        },
        .id_table = cc2520_ids,