Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7615/sdio.c
48526 views
// SPDX-License-Identifier: ISC1/* Copyright (C) 2020 MediaTek Inc.2*3* Author: Felix Fietkau <[email protected]>4* Lorenzo Bianconi <[email protected]>5* Sean Wang <[email protected]>6*/78#include <linux/kernel.h>9#include <linux/iopoll.h>10#include <linux/module.h>1112#include <linux/mmc/host.h>13#include <linux/mmc/sdio_ids.h>14#include <linux/mmc/sdio_func.h>1516#include "../sdio.h"17#include "mt7615.h"18#include "mac.h"19#include "mcu.h"2021static const struct sdio_device_id mt7663s_table[] = {22{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7603) },23{ } /* Terminating entry */24};2526static void mt7663s_txrx_worker(struct mt76_worker *w)27{28struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,29txrx_worker);30struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);31struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);3233if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {34queue_work(mdev->wq, &dev->pm.wake_work);35return;36}37mt76s_txrx_worker(sdio);38mt76_connac_pm_unref(&dev->mphy, &dev->pm);39}4041static void mt7663s_init_work(struct work_struct *work)42{43struct mt7615_dev *dev;4445dev = container_of(work, struct mt7615_dev, mcu_work);46if (mt7663s_mcu_init(dev))47return;4849mt7615_init_work(dev);50}5152static int mt7663s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)53{54struct mt76_sdio *sdio = &dev->sdio;55struct mt7663s_intr *irq_data = sdio->intr_data;56int i, err;5758sdio_claim_host(sdio->func);59err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));60sdio_release_host(sdio->func);6162if (err)63return err;6465intr->isr = irq_data->isr;66intr->rec_mb = irq_data->rec_mb;67intr->tx.wtqcr = irq_data->tx.wtqcr;68intr->rx.num = irq_data->rx.num;69for (i = 0; i < 2 ; i++)70intr->rx.len[i] = irq_data->rx.len[i];7172return 0;73}7475static int mt7663s_probe(struct sdio_func *func,76const struct sdio_device_id *id)77{78static const struct mt76_driver_ops drv_ops = {79.txwi_size = MT_USB_TXD_SIZE,80.drv_flags = MT_DRV_RX_DMA_HDR,81.tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb,82.tx_complete_skb = mt7663_usb_sdio_tx_complete_skb,83.tx_status_data = mt7663_usb_sdio_tx_status_data,84.rx_skb = mt7615_queue_rx_skb,85.rx_check = mt7615_rx_check,86.sta_add = mt7615_mac_sta_add,87.sta_remove = mt7615_mac_sta_remove,88.update_survey = mt7615_update_channel,89.set_channel = mt7615_set_channel,90};91static const struct mt76_bus_ops mt7663s_ops = {92.rr = mt76s_rr,93.rmw = mt76s_rmw,94.wr = mt76s_wr,95.write_copy = mt76s_write_copy,96.read_copy = mt76s_read_copy,97.wr_rp = mt76s_wr_rp,98.rd_rp = mt76s_rd_rp,99.type = MT76_BUS_SDIO,100};101struct ieee80211_ops *ops;102struct mt7615_dev *dev;103struct mt76_dev *mdev;104int ret;105106ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops),107GFP_KERNEL);108if (!ops)109return -ENOMEM;110111mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops);112if (!mdev)113return -ENOMEM;114115dev = container_of(mdev, struct mt7615_dev, mt76);116117INIT_WORK(&dev->mcu_work, mt7663s_init_work);118dev->reg_map = mt7663_usb_sdio_reg_map;119dev->ops = ops;120sdio_set_drvdata(func, dev);121122ret = mt76s_init(mdev, func, &mt7663s_ops);123if (ret < 0)124goto error;125126ret = mt76s_hw_init(mdev, func, MT76_CONNAC_SDIO);127if (ret)128goto error;129130mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |131(mt76_rr(dev, MT_HW_REV) & 0xff);132dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);133134mdev->sdio.parse_irq = mt7663s_parse_intr;135mdev->sdio.intr_data = devm_kmalloc(mdev->dev,136sizeof(struct mt7663s_intr),137GFP_KERNEL);138if (!mdev->sdio.intr_data) {139ret = -ENOMEM;140goto error;141}142143ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);144if (ret)145goto error;146147ret = mt76s_alloc_tx(mdev);148if (ret)149goto error;150151ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,152mt7663s_txrx_worker, "sdio-txrx");153if (ret)154goto error;155156sched_set_fifo_low(mdev->sdio.txrx_worker.task);157158ret = mt7663_usb_sdio_register_device(dev);159if (ret)160goto error;161162return 0;163164error:165mt76s_deinit(&dev->mt76);166mt76_free_device(&dev->mt76);167168return ret;169}170171static void mt7663s_remove(struct sdio_func *func)172{173struct mt7615_dev *dev = sdio_get_drvdata(func);174175if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))176return;177178ieee80211_unregister_hw(dev->mt76.hw);179mt76s_deinit(&dev->mt76);180mt76_free_device(&dev->mt76);181}182183static int mt7663s_suspend(struct device *dev)184{185struct sdio_func *func = dev_to_sdio_func(dev);186struct mt7615_dev *mdev = sdio_get_drvdata(func);187int err;188189if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&190mt7615_firmware_offload(mdev)) {191int err;192193err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, true, true);194if (err < 0)195return err;196}197198sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);199200err = mt7615_mcu_set_fw_ctrl(mdev);201if (err)202return err;203204mt76_worker_disable(&mdev->mt76.sdio.txrx_worker);205mt76_worker_disable(&mdev->mt76.sdio.status_worker);206mt76_worker_disable(&mdev->mt76.sdio.net_worker);207mt76_worker_disable(&mdev->mt76.sdio.stat_worker);208209clear_bit(MT76_READING_STATS, &mdev->mphy.state);210211mt76_tx_status_check(&mdev->mt76, true);212213return 0;214}215216static int mt7663s_resume(struct device *dev)217{218struct sdio_func *func = dev_to_sdio_func(dev);219struct mt7615_dev *mdev = sdio_get_drvdata(func);220int err;221222mt76_worker_enable(&mdev->mt76.sdio.txrx_worker);223mt76_worker_enable(&mdev->mt76.sdio.status_worker);224mt76_worker_enable(&mdev->mt76.sdio.net_worker);225226err = mt7615_mcu_set_drv_ctrl(mdev);227if (err)228return err;229230if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&231mt7615_firmware_offload(mdev))232err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, false, true);233234return err;235}236237MODULE_DEVICE_TABLE(sdio, mt7663s_table);238MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9);239MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH);240MODULE_FIRMWARE(MT7663_FIRMWARE_N9);241MODULE_FIRMWARE(MT7663_ROM_PATCH);242243static DEFINE_SIMPLE_DEV_PM_OPS(mt7663s_pm_ops, mt7663s_suspend, mt7663s_resume);244245static struct sdio_driver mt7663s_driver = {246.name = KBUILD_MODNAME,247.probe = mt7663s_probe,248.remove = mt7663s_remove,249.id_table = mt7663s_table,250.drv.pm = pm_sleep_ptr(&mt7663s_pm_ops),251};252module_sdio_driver(mt7663s_driver);253254MODULE_AUTHOR("Sean Wang <[email protected]>");255MODULE_AUTHOR("Lorenzo Bianconi <[email protected]>");256MODULE_DESCRIPTION("MediaTek MT7663S (SDIO) wireless driver");257MODULE_LICENSE("Dual BSD/GPL");258259260