diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt76x0/pci.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 127 |
1 files changed, 123 insertions, 4 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index eb383f96ec9a..87997cddf0d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -19,12 +19,113 @@ #include <linux/pci.h> #include "mt76x0.h" +#include "mcu.h" + +static int mt76x0e_start(struct ieee80211_hw *hw) +{ + struct mt76x02_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + + mt76x02_mac_start(dev); + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mac_work, + MT_CALIBRATE_INTERVAL); + ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, + MT_CALIBRATE_INTERVAL); + set_bit(MT76_STATE_RUNNING, &dev->mt76.state); + + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static void mt76x0e_stop_hw(struct mt76x02_dev *dev) +{ + cancel_delayed_work_sync(&dev->cal_work); + cancel_delayed_work_sync(&dev->mac_work); + + if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY, + 0, 1000)) + dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); + mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN); + + mt76x0_mac_stop(dev); + + if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_BUSY, + 0, 1000)) + dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); + mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN); +} + +static void mt76x0e_stop(struct ieee80211_hw *hw) +{ + struct mt76x02_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); + mt76x0e_stop_hw(dev); + mutex_unlock(&dev->mt76.mutex); +} + +static const struct ieee80211_ops mt76x0e_ops = { + .tx = mt76x02_tx, + .start = mt76x0e_start, + .stop = mt76x0e_stop, + .config = mt76x0_config, + .add_interface = mt76x02_add_interface, + .remove_interface = mt76x02_remove_interface, + .configure_filter = mt76x02_configure_filter, +}; + +static int mt76x0e_register_device(struct mt76x02_dev *dev) +{ + int err; + + mt76x0_chip_onoff(dev, true, false); + if (!mt76x02_wait_for_mac(&dev->mt76)) + return -ETIMEDOUT; + + mt76x02_dma_disable(dev); + err = mt76x0e_mcu_init(dev); + if (err < 0) + return err; + + err = mt76x02_dma_init(dev); + if (err < 0) + return err; + + err = mt76x0_init_hardware(dev); + if (err < 0) + return err; + + if (mt76_chip(&dev->mt76) == 0x7610) { + u16 val; + + mt76_clear(dev, MT_COEXCFG0, BIT(0)); + val = mt76x02_eeprom_get(&dev->mt76, MT_EE_NIC_CONF_0); + if (val & MT_EE_NIC_CONF_0_PA_IO_CURRENT) { + u32 data; + + /* set external external PA I/O + * current to 16mA + */ + data = mt76_rr(dev, 0x11c); + val |= 0xc03; + mt76_wr(dev, 0x11c, val); + } + } + + mt76_clear(dev, 0x110, BIT(9)); + mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); + + return 0; +} static int mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct mt76x0_dev *dev; - int ret = -ENODEV; + struct mt76x02_dev *dev; + int ret; ret = pcim_enable_device(pdev); if (ret) @@ -40,7 +141,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - dev = mt76x0_alloc_device(&pdev->dev, NULL); + dev = mt76x0_alloc_device(&pdev->dev, NULL, &mt76x0e_ops); if (!dev) return -ENOMEM; @@ -49,22 +150,40 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev); -/* error: */ + ret = mt76x0e_register_device(dev); + if (ret < 0) + goto error; + + return 0; + +error: ieee80211_free_hw(mt76_hw(dev)); return ret; } +static void mt76x0e_cleanup(struct mt76x02_dev *dev) +{ + clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + mt76x0_chip_onoff(dev, false, false); + mt76x0e_stop_hw(dev); + mt76x02_dma_cleanup(dev); + mt76x02_mcu_cleanup(&dev->mt76); +} + static void mt76x0e_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); mt76_unregister_device(mdev); + mt76x0e_cleanup(dev); ieee80211_free_hw(mdev->hw); } static const struct pci_device_id mt76x0e_device_table[] = { { PCI_DEVICE(0x14c3, 0x7630) }, + { PCI_DEVICE(0x14c3, 0x7650) }, { }, }; |