Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /* Copyright (C) 2021 MediaTek Inc.
0003  *
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/iopoll.h>
0008 #include <linux/module.h>
0009 
0010 #include <linux/mmc/host.h>
0011 #include <linux/mmc/sdio_ids.h>
0012 #include <linux/mmc/sdio_func.h>
0013 
0014 #include "mt7921.h"
0015 #include "../sdio.h"
0016 #include "mac.h"
0017 #include "mcu.h"
0018 
0019 static const struct sdio_device_id mt7921s_table[] = {
0020     { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901) },
0021     { } /* Terminating entry */
0022 };
0023 
0024 static void mt7921s_txrx_worker(struct mt76_worker *w)
0025 {
0026     struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
0027                           txrx_worker);
0028     struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
0029     struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
0030 
0031     if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
0032         queue_work(mdev->wq, &dev->pm.wake_work);
0033         return;
0034     }
0035 
0036     mt76s_txrx_worker(sdio);
0037     mt76_connac_pm_unref(&dev->mphy, &dev->pm);
0038 }
0039 
0040 static void mt7921s_unregister_device(struct mt7921_dev *dev)
0041 {
0042     struct mt76_connac_pm *pm = &dev->pm;
0043 
0044     cancel_work_sync(&dev->init_work);
0045     mt76_unregister_device(&dev->mt76);
0046     cancel_delayed_work_sync(&pm->ps_work);
0047     cancel_work_sync(&pm->wake_work);
0048 
0049     mt76s_deinit(&dev->mt76);
0050     mt7921s_wfsys_reset(dev);
0051     skb_queue_purge(&dev->mt76.mcu.res_q);
0052 
0053     mt76_free_device(&dev->mt76);
0054 }
0055 
0056 static int mt7921s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)
0057 {
0058     struct mt76_sdio *sdio = &dev->sdio;
0059     struct mt7921_sdio_intr *irq_data = sdio->intr_data;
0060     int i, err;
0061 
0062     sdio_claim_host(sdio->func);
0063     err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));
0064     sdio_release_host(sdio->func);
0065 
0066     if (err < 0)
0067         return err;
0068 
0069     if (irq_data->rx.num[0] > 16 ||
0070         irq_data->rx.num[1] > 128)
0071         return -EINVAL;
0072 
0073     intr->isr = irq_data->isr;
0074     intr->rec_mb = irq_data->rec_mb;
0075     intr->tx.wtqcr = irq_data->tx.wtqcr;
0076     intr->rx.num = irq_data->rx.num;
0077     for (i = 0; i < 2 ; i++) {
0078         if (!i)
0079             intr->rx.len[0] = irq_data->rx.len0;
0080         else
0081             intr->rx.len[1] = irq_data->rx.len1;
0082     }
0083 
0084     return 0;
0085 }
0086 
0087 static int mt7921s_probe(struct sdio_func *func,
0088              const struct sdio_device_id *id)
0089 {
0090     static const struct mt76_driver_ops drv_ops = {
0091         .txwi_size = MT_SDIO_TXD_SIZE,
0092         .survey_flags = SURVEY_INFO_TIME_TX |
0093                 SURVEY_INFO_TIME_RX |
0094                 SURVEY_INFO_TIME_BSS_RX,
0095         .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb,
0096         .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb,
0097         .tx_status_data = mt7921_usb_sdio_tx_status_data,
0098         .rx_skb = mt7921_queue_rx_skb,
0099         .sta_ps = mt7921_sta_ps,
0100         .sta_add = mt7921_mac_sta_add,
0101         .sta_assoc = mt7921_mac_sta_assoc,
0102         .sta_remove = mt7921_mac_sta_remove,
0103         .update_survey = mt7921_update_channel,
0104     };
0105     static const struct mt76_bus_ops mt7921s_ops = {
0106         .rr = mt76s_rr,
0107         .rmw = mt76s_rmw,
0108         .wr = mt76s_wr,
0109         .write_copy = mt76s_write_copy,
0110         .read_copy = mt76s_read_copy,
0111         .wr_rp = mt76s_wr_rp,
0112         .rd_rp = mt76s_rd_rp,
0113         .type = MT76_BUS_SDIO,
0114     };
0115     static const struct mt7921_hif_ops mt7921_sdio_ops = {
0116         .init_reset = mt7921s_init_reset,
0117         .reset = mt7921s_mac_reset,
0118         .mcu_init = mt7921s_mcu_init,
0119         .drv_own = mt7921s_mcu_drv_pmctrl,
0120         .fw_own = mt7921s_mcu_fw_pmctrl,
0121     };
0122 
0123     struct mt7921_dev *dev;
0124     struct mt76_dev *mdev;
0125     int ret;
0126 
0127     mdev = mt76_alloc_device(&func->dev, sizeof(*dev), &mt7921_ops,
0128                  &drv_ops);
0129     if (!mdev)
0130         return -ENOMEM;
0131 
0132     dev = container_of(mdev, struct mt7921_dev, mt76);
0133     dev->hif_ops = &mt7921_sdio_ops;
0134 
0135     sdio_set_drvdata(func, dev);
0136 
0137     ret = mt76s_init(mdev, func, &mt7921s_ops);
0138     if (ret < 0)
0139         goto error;
0140 
0141     ret = mt76s_hw_init(mdev, func, MT76_CONNAC2_SDIO);
0142     if (ret)
0143         goto error;
0144 
0145     mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
0146             (mt76_rr(dev, MT_HW_REV) & 0xff);
0147     dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
0148 
0149     mdev->sdio.parse_irq = mt7921s_parse_intr;
0150     mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
0151                         sizeof(struct mt7921_sdio_intr),
0152                         GFP_KERNEL);
0153     if (!mdev->sdio.intr_data) {
0154         ret = -ENOMEM;
0155         goto error;
0156     }
0157 
0158     ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);
0159     if (ret)
0160         goto error;
0161 
0162     ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MCU);
0163     if (ret)
0164         goto error;
0165 
0166     ret = mt76s_alloc_tx(mdev);
0167     if (ret)
0168         goto error;
0169 
0170     ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
0171                 mt7921s_txrx_worker, "sdio-txrx");
0172     if (ret)
0173         goto error;
0174 
0175     sched_set_fifo_low(mdev->sdio.txrx_worker.task);
0176 
0177     ret = mt7921_register_device(dev);
0178     if (ret)
0179         goto error;
0180 
0181     return 0;
0182 
0183 error:
0184     mt76s_deinit(&dev->mt76);
0185     mt76_free_device(&dev->mt76);
0186 
0187     return ret;
0188 }
0189 
0190 static void mt7921s_remove(struct sdio_func *func)
0191 {
0192     struct mt7921_dev *dev = sdio_get_drvdata(func);
0193 
0194     mt7921s_unregister_device(dev);
0195 }
0196 
0197 #ifdef CONFIG_PM
0198 static int mt7921s_suspend(struct device *__dev)
0199 {
0200     struct sdio_func *func = dev_to_sdio_func(__dev);
0201     struct mt7921_dev *dev = sdio_get_drvdata(func);
0202     struct mt76_connac_pm *pm = &dev->pm;
0203     struct mt76_dev *mdev = &dev->mt76;
0204     int err;
0205 
0206     pm->suspended = true;
0207     set_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
0208 
0209     cancel_delayed_work_sync(&pm->ps_work);
0210     cancel_work_sync(&pm->wake_work);
0211 
0212     err = mt7921_mcu_drv_pmctrl(dev);
0213     if (err < 0)
0214         goto restore_suspend;
0215 
0216     /* always enable deep sleep during suspend to reduce
0217      * power consumption
0218      */
0219     mt76_connac_mcu_set_deep_sleep(mdev, true);
0220 
0221     mt76_txq_schedule_all(&dev->mphy);
0222     mt76_worker_disable(&mdev->tx_worker);
0223     mt76_worker_disable(&mdev->sdio.status_worker);
0224     cancel_work_sync(&mdev->sdio.stat_work);
0225     clear_bit(MT76_READING_STATS, &dev->mphy.state);
0226     mt76_tx_status_check(mdev, true);
0227 
0228     mt76_worker_schedule(&mdev->sdio.txrx_worker);
0229     wait_event_timeout(dev->mt76.sdio.wait,
0230                mt76s_txqs_empty(&dev->mt76), 5 * HZ);
0231 
0232     /* It is supposed that SDIO bus is idle at the point */
0233     err = mt76_connac_mcu_set_hif_suspend(mdev, true);
0234     if (err)
0235         goto restore_worker;
0236 
0237     mt76_worker_disable(&mdev->sdio.txrx_worker);
0238     mt76_worker_disable(&mdev->sdio.net_worker);
0239 
0240     err = mt7921_mcu_fw_pmctrl(dev);
0241     if (err)
0242         goto restore_txrx_worker;
0243 
0244     sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
0245 
0246     return 0;
0247 
0248 restore_txrx_worker:
0249     mt76_worker_enable(&mdev->sdio.net_worker);
0250     mt76_worker_enable(&mdev->sdio.txrx_worker);
0251     mt76_connac_mcu_set_hif_suspend(mdev, false);
0252 
0253 restore_worker:
0254     mt76_worker_enable(&mdev->tx_worker);
0255     mt76_worker_enable(&mdev->sdio.status_worker);
0256 
0257     if (!pm->ds_enable)
0258         mt76_connac_mcu_set_deep_sleep(mdev, false);
0259 
0260 restore_suspend:
0261     clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
0262     pm->suspended = false;
0263 
0264     return err;
0265 }
0266 
0267 static int mt7921s_resume(struct device *__dev)
0268 {
0269     struct sdio_func *func = dev_to_sdio_func(__dev);
0270     struct mt7921_dev *dev = sdio_get_drvdata(func);
0271     struct mt76_connac_pm *pm = &dev->pm;
0272     struct mt76_dev *mdev = &dev->mt76;
0273     int err;
0274 
0275     clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state);
0276 
0277     err = mt7921_mcu_drv_pmctrl(dev);
0278     if (err < 0)
0279         return err;
0280 
0281     mt76_worker_enable(&mdev->tx_worker);
0282     mt76_worker_enable(&mdev->sdio.txrx_worker);
0283     mt76_worker_enable(&mdev->sdio.status_worker);
0284     mt76_worker_enable(&mdev->sdio.net_worker);
0285 
0286     /* restore previous ds setting */
0287     if (!pm->ds_enable)
0288         mt76_connac_mcu_set_deep_sleep(mdev, false);
0289 
0290     err = mt76_connac_mcu_set_hif_suspend(mdev, false);
0291     if (err)
0292         return err;
0293 
0294     pm->suspended = false;
0295 
0296     return err;
0297 }
0298 
0299 static const struct dev_pm_ops mt7921s_pm_ops = {
0300     .suspend = mt7921s_suspend,
0301     .resume = mt7921s_resume,
0302 };
0303 #endif
0304 
0305 MODULE_DEVICE_TABLE(sdio, mt7921s_table);
0306 MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
0307 MODULE_FIRMWARE(MT7921_ROM_PATCH);
0308 
0309 static struct sdio_driver mt7921s_driver = {
0310     .name       = KBUILD_MODNAME,
0311     .probe      = mt7921s_probe,
0312     .remove     = mt7921s_remove,
0313     .id_table   = mt7921s_table,
0314 #ifdef CONFIG_PM
0315     .drv = {
0316         .pm = &mt7921s_pm_ops,
0317     }
0318 #endif
0319 };
0320 module_sdio_driver(mt7921s_driver);
0321 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
0322 MODULE_LICENSE("Dual BSD/GPL");