sdio.c (7740B)
1// SPDX-License-Identifier: ISC 2/* Copyright (C) 2021 MediaTek Inc. 3 * 4 */ 5 6#include <linux/kernel.h> 7#include <linux/iopoll.h> 8#include <linux/module.h> 9 10#include <linux/mmc/host.h> 11#include <linux/mmc/sdio_ids.h> 12#include <linux/mmc/sdio_func.h> 13 14#include "mt7921.h" 15#include "../sdio.h" 16#include "mac.h" 17#include "mcu.h" 18 19static const struct sdio_device_id mt7921s_table[] = { 20 { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901) }, 21 { } /* Terminating entry */ 22}; 23 24static void mt7921s_txrx_worker(struct mt76_worker *w) 25{ 26 struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, 27 txrx_worker); 28 struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio); 29 struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); 30 31 if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { 32 queue_work(mdev->wq, &dev->pm.wake_work); 33 return; 34 } 35 36 mt76s_txrx_worker(sdio); 37 mt76_connac_pm_unref(&dev->mphy, &dev->pm); 38} 39 40static void mt7921s_unregister_device(struct mt7921_dev *dev) 41{ 42 struct mt76_connac_pm *pm = &dev->pm; 43 44 cancel_work_sync(&dev->init_work); 45 mt76_unregister_device(&dev->mt76); 46 cancel_delayed_work_sync(&pm->ps_work); 47 cancel_work_sync(&pm->wake_work); 48 49 mt76s_deinit(&dev->mt76); 50 mt7921s_wfsys_reset(dev); 51 mt7921_mcu_exit(dev); 52 53 mt76_free_device(&dev->mt76); 54} 55 56static int mt7921s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr) 57{ 58 struct mt76_sdio *sdio = &dev->sdio; 59 struct mt7921_sdio_intr *irq_data = sdio->intr_data; 60 int i, err; 61 62 sdio_claim_host(sdio->func); 63 err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data)); 64 sdio_release_host(sdio->func); 65 66 if (err < 0) 67 return err; 68 69 if (irq_data->rx.num[0] > 16 || 70 irq_data->rx.num[1] > 128) 71 return -EINVAL; 72 73 intr->isr = irq_data->isr; 74 intr->rec_mb = irq_data->rec_mb; 75 intr->tx.wtqcr = irq_data->tx.wtqcr; 76 intr->rx.num = irq_data->rx.num; 77 for (i = 0; i < 2 ; i++) { 78 if (!i) 79 intr->rx.len[0] = irq_data->rx.len0; 80 else 81 intr->rx.len[1] = irq_data->rx.len1; 82 } 83 84 return 0; 85} 86 87static int mt7921s_probe(struct sdio_func *func, 88 const struct sdio_device_id *id) 89{ 90 static const struct mt76_driver_ops drv_ops = { 91 .txwi_size = MT_SDIO_TXD_SIZE, 92 .survey_flags = SURVEY_INFO_TIME_TX | 93 SURVEY_INFO_TIME_RX | 94 SURVEY_INFO_TIME_BSS_RX, 95 .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb, 96 .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb, 97 .tx_status_data = mt7921_usb_sdio_tx_status_data, 98 .rx_skb = mt7921_queue_rx_skb, 99 .sta_ps = mt7921_sta_ps, 100 .sta_add = mt7921_mac_sta_add, 101 .sta_assoc = mt7921_mac_sta_assoc, 102 .sta_remove = mt7921_mac_sta_remove, 103 .update_survey = mt7921_update_channel, 104 }; 105 static const struct mt76_bus_ops mt7921s_ops = { 106 .rr = mt76s_rr, 107 .rmw = mt76s_rmw, 108 .wr = mt76s_wr, 109 .write_copy = mt76s_write_copy, 110 .read_copy = mt76s_read_copy, 111 .wr_rp = mt76s_wr_rp, 112 .rd_rp = mt76s_rd_rp, 113 .type = MT76_BUS_SDIO, 114 }; 115 static const struct mt7921_hif_ops mt7921_sdio_ops = { 116 .init_reset = mt7921s_init_reset, 117 .reset = mt7921s_mac_reset, 118 .mcu_init = mt7921s_mcu_init, 119 .drv_own = mt7921s_mcu_drv_pmctrl, 120 .fw_own = mt7921s_mcu_fw_pmctrl, 121 }; 122 123 struct mt7921_dev *dev; 124 struct mt76_dev *mdev; 125 int ret; 126 127 mdev = mt76_alloc_device(&func->dev, sizeof(*dev), &mt7921_ops, 128 &drv_ops); 129 if (!mdev) 130 return -ENOMEM; 131 132 dev = container_of(mdev, struct mt7921_dev, mt76); 133 dev->hif_ops = &mt7921_sdio_ops; 134 135 sdio_set_drvdata(func, dev); 136 137 ret = mt76s_init(mdev, func, &mt7921s_ops); 138 if (ret < 0) 139 goto error; 140 141 ret = mt76s_hw_init(mdev, func, MT76_CONNAC2_SDIO); 142 if (ret) 143 goto error; 144 145 mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | 146 (mt76_rr(dev, MT_HW_REV) & 0xff); 147 dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); 148 149 mdev->sdio.parse_irq = mt7921s_parse_intr; 150 mdev->sdio.intr_data = devm_kmalloc(mdev->dev, 151 sizeof(struct mt7921_sdio_intr), 152 GFP_KERNEL); 153 if (!mdev->sdio.intr_data) { 154 ret = -ENOMEM; 155 goto error; 156 } 157 158 ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN); 159 if (ret) 160 goto error; 161 162 ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MCU); 163 if (ret) 164 goto error; 165 166 ret = mt76s_alloc_tx(mdev); 167 if (ret) 168 goto error; 169 170 ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker, 171 mt7921s_txrx_worker, "sdio-txrx"); 172 if (ret) 173 goto error; 174 175 sched_set_fifo_low(mdev->sdio.txrx_worker.task); 176 177 ret = mt7921_register_device(dev); 178 if (ret) 179 goto error; 180 181 return 0; 182 183error: 184 mt76s_deinit(&dev->mt76); 185 mt76_free_device(&dev->mt76); 186 187 return ret; 188} 189 190static void mt7921s_remove(struct sdio_func *func) 191{ 192 struct mt7921_dev *dev = sdio_get_drvdata(func); 193 194 mt7921s_unregister_device(dev); 195} 196 197#ifdef CONFIG_PM 198static int mt7921s_suspend(struct device *__dev) 199{ 200 struct sdio_func *func = dev_to_sdio_func(__dev); 201 struct mt7921_dev *dev = sdio_get_drvdata(func); 202 struct mt76_connac_pm *pm = &dev->pm; 203 struct mt76_dev *mdev = &dev->mt76; 204 int err; 205 206 pm->suspended = true; 207 set_bit(MT76_STATE_SUSPEND, &mdev->phy.state); 208 209 cancel_delayed_work_sync(&pm->ps_work); 210 cancel_work_sync(&pm->wake_work); 211 212 err = mt7921_mcu_drv_pmctrl(dev); 213 if (err < 0) 214 goto restore_suspend; 215 216 /* always enable deep sleep during suspend to reduce 217 * power consumption 218 */ 219 mt76_connac_mcu_set_deep_sleep(mdev, true); 220 221 mt76_txq_schedule_all(&dev->mphy); 222 mt76_worker_disable(&mdev->tx_worker); 223 mt76_worker_disable(&mdev->sdio.status_worker); 224 cancel_work_sync(&mdev->sdio.stat_work); 225 clear_bit(MT76_READING_STATS, &dev->mphy.state); 226 mt76_tx_status_check(mdev, true); 227 228 mt76_worker_schedule(&mdev->sdio.txrx_worker); 229 wait_event_timeout(dev->mt76.sdio.wait, 230 mt76s_txqs_empty(&dev->mt76), 5 * HZ); 231 232 /* It is supposed that SDIO bus is idle at the point */ 233 err = mt76_connac_mcu_set_hif_suspend(mdev, true); 234 if (err) 235 goto restore_worker; 236 237 mt76_worker_disable(&mdev->sdio.txrx_worker); 238 mt76_worker_disable(&mdev->sdio.net_worker); 239 240 err = mt7921_mcu_fw_pmctrl(dev); 241 if (err) 242 goto restore_txrx_worker; 243 244 sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 245 246 return 0; 247 248restore_txrx_worker: 249 mt76_worker_enable(&mdev->sdio.net_worker); 250 mt76_worker_enable(&mdev->sdio.txrx_worker); 251 mt76_connac_mcu_set_hif_suspend(mdev, false); 252 253restore_worker: 254 mt76_worker_enable(&mdev->tx_worker); 255 mt76_worker_enable(&mdev->sdio.status_worker); 256 257 if (!pm->ds_enable) 258 mt76_connac_mcu_set_deep_sleep(mdev, false); 259 260restore_suspend: 261 clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state); 262 pm->suspended = false; 263 264 return err; 265} 266 267static int mt7921s_resume(struct device *__dev) 268{ 269 struct sdio_func *func = dev_to_sdio_func(__dev); 270 struct mt7921_dev *dev = sdio_get_drvdata(func); 271 struct mt76_connac_pm *pm = &dev->pm; 272 struct mt76_dev *mdev = &dev->mt76; 273 int err; 274 275 clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state); 276 277 err = mt7921_mcu_drv_pmctrl(dev); 278 if (err < 0) 279 return err; 280 281 mt76_worker_enable(&mdev->tx_worker); 282 mt76_worker_enable(&mdev->sdio.txrx_worker); 283 mt76_worker_enable(&mdev->sdio.status_worker); 284 mt76_worker_enable(&mdev->sdio.net_worker); 285 286 /* restore previous ds setting */ 287 if (!pm->ds_enable) 288 mt76_connac_mcu_set_deep_sleep(mdev, false); 289 290 err = mt76_connac_mcu_set_hif_suspend(mdev, false); 291 if (err) 292 return err; 293 294 pm->suspended = false; 295 296 return err; 297} 298 299static const struct dev_pm_ops mt7921s_pm_ops = { 300 .suspend = mt7921s_suspend, 301 .resume = mt7921s_resume, 302}; 303#endif 304 305MODULE_DEVICE_TABLE(sdio, mt7921s_table); 306MODULE_FIRMWARE(MT7921_FIRMWARE_WM); 307MODULE_FIRMWARE(MT7921_ROM_PATCH); 308 309static struct sdio_driver mt7921s_driver = { 310 .name = KBUILD_MODNAME, 311 .probe = mt7921s_probe, 312 .remove = mt7921s_remove, 313 .id_table = mt7921s_table, 314#ifdef CONFIG_PM 315 .drv = { 316 .pm = &mt7921s_pm_ops, 317 } 318#endif 319}; 320module_sdio_driver(mt7921s_driver); 321MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); 322MODULE_LICENSE("Dual BSD/GPL");