162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Author: Felix Fietkau <nbd@nbd.name>
562306a36Sopenharmony_ci *	   Lorenzo Bianconi <lorenzo@kernel.org>
662306a36Sopenharmony_ci *	   Sean Wang <sean.wang@mediatek.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/iopoll.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/mmc/host.h>
1462306a36Sopenharmony_ci#include <linux/mmc/sdio_ids.h>
1562306a36Sopenharmony_ci#include <linux/mmc/sdio_func.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "../sdio.h"
1862306a36Sopenharmony_ci#include "mt7615.h"
1962306a36Sopenharmony_ci#include "mac.h"
2062306a36Sopenharmony_ci#include "mcu.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic const struct sdio_device_id mt7663s_table[] = {
2362306a36Sopenharmony_ci	{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7603) },
2462306a36Sopenharmony_ci	{ }	/* Terminating entry */
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic void mt7663s_txrx_worker(struct mt76_worker *w)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
3062306a36Sopenharmony_ci					      txrx_worker);
3162306a36Sopenharmony_ci	struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
3262306a36Sopenharmony_ci	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
3562306a36Sopenharmony_ci		queue_work(mdev->wq, &dev->pm.wake_work);
3662306a36Sopenharmony_ci		return;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci	mt76s_txrx_worker(sdio);
3962306a36Sopenharmony_ci	mt76_connac_pm_unref(&dev->mphy, &dev->pm);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic void mt7663s_init_work(struct work_struct *work)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct mt7615_dev *dev;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	dev = container_of(work, struct mt7615_dev, mcu_work);
4762306a36Sopenharmony_ci	if (mt7663s_mcu_init(dev))
4862306a36Sopenharmony_ci		return;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	mt7615_init_work(dev);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int mt7663s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct mt76_sdio *sdio = &dev->sdio;
5662306a36Sopenharmony_ci	struct mt7663s_intr *irq_data = sdio->intr_data;
5762306a36Sopenharmony_ci	int i, err;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	sdio_claim_host(sdio->func);
6062306a36Sopenharmony_ci	err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));
6162306a36Sopenharmony_ci	sdio_release_host(sdio->func);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (err)
6462306a36Sopenharmony_ci		return err;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	intr->isr = irq_data->isr;
6762306a36Sopenharmony_ci	intr->rec_mb = irq_data->rec_mb;
6862306a36Sopenharmony_ci	intr->tx.wtqcr = irq_data->tx.wtqcr;
6962306a36Sopenharmony_ci	intr->rx.num = irq_data->rx.num;
7062306a36Sopenharmony_ci	for (i = 0; i < 2 ; i++)
7162306a36Sopenharmony_ci		intr->rx.len[i] = irq_data->rx.len[i];
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return 0;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic int mt7663s_probe(struct sdio_func *func,
7762306a36Sopenharmony_ci			 const struct sdio_device_id *id)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	static const struct mt76_driver_ops drv_ops = {
8062306a36Sopenharmony_ci		.txwi_size = MT_USB_TXD_SIZE,
8162306a36Sopenharmony_ci		.drv_flags = MT_DRV_RX_DMA_HDR,
8262306a36Sopenharmony_ci		.tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb,
8362306a36Sopenharmony_ci		.tx_complete_skb = mt7663_usb_sdio_tx_complete_skb,
8462306a36Sopenharmony_ci		.tx_status_data = mt7663_usb_sdio_tx_status_data,
8562306a36Sopenharmony_ci		.rx_skb = mt7615_queue_rx_skb,
8662306a36Sopenharmony_ci		.rx_check = mt7615_rx_check,
8762306a36Sopenharmony_ci		.sta_add = mt7615_mac_sta_add,
8862306a36Sopenharmony_ci		.sta_remove = mt7615_mac_sta_remove,
8962306a36Sopenharmony_ci		.update_survey = mt7615_update_channel,
9062306a36Sopenharmony_ci	};
9162306a36Sopenharmony_ci	static const struct mt76_bus_ops mt7663s_ops = {
9262306a36Sopenharmony_ci		.rr = mt76s_rr,
9362306a36Sopenharmony_ci		.rmw = mt76s_rmw,
9462306a36Sopenharmony_ci		.wr = mt76s_wr,
9562306a36Sopenharmony_ci		.write_copy = mt76s_write_copy,
9662306a36Sopenharmony_ci		.read_copy = mt76s_read_copy,
9762306a36Sopenharmony_ci		.wr_rp = mt76s_wr_rp,
9862306a36Sopenharmony_ci		.rd_rp = mt76s_rd_rp,
9962306a36Sopenharmony_ci		.type = MT76_BUS_SDIO,
10062306a36Sopenharmony_ci	};
10162306a36Sopenharmony_ci	struct ieee80211_ops *ops;
10262306a36Sopenharmony_ci	struct mt7615_dev *dev;
10362306a36Sopenharmony_ci	struct mt76_dev *mdev;
10462306a36Sopenharmony_ci	int ret;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops),
10762306a36Sopenharmony_ci			   GFP_KERNEL);
10862306a36Sopenharmony_ci	if (!ops)
10962306a36Sopenharmony_ci		return -ENOMEM;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops);
11262306a36Sopenharmony_ci	if (!mdev)
11362306a36Sopenharmony_ci		return -ENOMEM;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	dev = container_of(mdev, struct mt7615_dev, mt76);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	INIT_WORK(&dev->mcu_work, mt7663s_init_work);
11862306a36Sopenharmony_ci	dev->reg_map = mt7663_usb_sdio_reg_map;
11962306a36Sopenharmony_ci	dev->ops = ops;
12062306a36Sopenharmony_ci	sdio_set_drvdata(func, dev);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	ret = mt76s_init(mdev, func, &mt7663s_ops);
12362306a36Sopenharmony_ci	if (ret < 0)
12462306a36Sopenharmony_ci		goto error;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	ret = mt76s_hw_init(mdev, func, MT76_CONNAC_SDIO);
12762306a36Sopenharmony_ci	if (ret)
12862306a36Sopenharmony_ci		goto error;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
13162306a36Sopenharmony_ci		    (mt76_rr(dev, MT_HW_REV) & 0xff);
13262306a36Sopenharmony_ci	dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	mdev->sdio.parse_irq = mt7663s_parse_intr;
13562306a36Sopenharmony_ci	mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
13662306a36Sopenharmony_ci					    sizeof(struct mt7663s_intr),
13762306a36Sopenharmony_ci					    GFP_KERNEL);
13862306a36Sopenharmony_ci	if (!mdev->sdio.intr_data) {
13962306a36Sopenharmony_ci		ret = -ENOMEM;
14062306a36Sopenharmony_ci		goto error;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);
14462306a36Sopenharmony_ci	if (ret)
14562306a36Sopenharmony_ci		goto error;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	ret = mt76s_alloc_tx(mdev);
14862306a36Sopenharmony_ci	if (ret)
14962306a36Sopenharmony_ci		goto error;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
15262306a36Sopenharmony_ci				mt7663s_txrx_worker, "sdio-txrx");
15362306a36Sopenharmony_ci	if (ret)
15462306a36Sopenharmony_ci		goto error;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	sched_set_fifo_low(mdev->sdio.txrx_worker.task);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	ret = mt7663_usb_sdio_register_device(dev);
15962306a36Sopenharmony_ci	if (ret)
16062306a36Sopenharmony_ci		goto error;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cierror:
16562306a36Sopenharmony_ci	mt76s_deinit(&dev->mt76);
16662306a36Sopenharmony_ci	mt76_free_device(&dev->mt76);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return ret;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void mt7663s_remove(struct sdio_func *func)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct mt7615_dev *dev = sdio_get_drvdata(func);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
17662306a36Sopenharmony_ci		return;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	ieee80211_unregister_hw(dev->mt76.hw);
17962306a36Sopenharmony_ci	mt76s_deinit(&dev->mt76);
18062306a36Sopenharmony_ci	mt76_free_device(&dev->mt76);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int mt7663s_suspend(struct device *dev)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct sdio_func *func = dev_to_sdio_func(dev);
18662306a36Sopenharmony_ci	struct mt7615_dev *mdev = sdio_get_drvdata(func);
18762306a36Sopenharmony_ci	int err;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&
19062306a36Sopenharmony_ci	    mt7615_firmware_offload(mdev)) {
19162306a36Sopenharmony_ci		int err;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, true);
19462306a36Sopenharmony_ci		if (err < 0)
19562306a36Sopenharmony_ci			return err;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	err = mt7615_mcu_set_fw_ctrl(mdev);
20162306a36Sopenharmony_ci	if (err)
20262306a36Sopenharmony_ci		return err;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	mt76_worker_disable(&mdev->mt76.sdio.txrx_worker);
20562306a36Sopenharmony_ci	mt76_worker_disable(&mdev->mt76.sdio.status_worker);
20662306a36Sopenharmony_ci	mt76_worker_disable(&mdev->mt76.sdio.net_worker);
20762306a36Sopenharmony_ci	mt76_worker_disable(&mdev->mt76.sdio.stat_worker);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	clear_bit(MT76_READING_STATS, &mdev->mphy.state);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	mt76_tx_status_check(&mdev->mt76, true);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return 0;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int mt7663s_resume(struct device *dev)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	struct sdio_func *func = dev_to_sdio_func(dev);
21962306a36Sopenharmony_ci	struct mt7615_dev *mdev = sdio_get_drvdata(func);
22062306a36Sopenharmony_ci	int err;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	mt76_worker_enable(&mdev->mt76.sdio.txrx_worker);
22362306a36Sopenharmony_ci	mt76_worker_enable(&mdev->mt76.sdio.status_worker);
22462306a36Sopenharmony_ci	mt76_worker_enable(&mdev->mt76.sdio.net_worker);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	err = mt7615_mcu_set_drv_ctrl(mdev);
22762306a36Sopenharmony_ci	if (err)
22862306a36Sopenharmony_ci		return err;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&
23162306a36Sopenharmony_ci	    mt7615_firmware_offload(mdev))
23262306a36Sopenharmony_ci		err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, false);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return err;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(sdio, mt7663s_table);
23862306a36Sopenharmony_ciMODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9);
23962306a36Sopenharmony_ciMODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH);
24062306a36Sopenharmony_ciMODULE_FIRMWARE(MT7663_FIRMWARE_N9);
24162306a36Sopenharmony_ciMODULE_FIRMWARE(MT7663_ROM_PATCH);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(mt7663s_pm_ops, mt7663s_suspend, mt7663s_resume);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic struct sdio_driver mt7663s_driver = {
24662306a36Sopenharmony_ci	.name		= KBUILD_MODNAME,
24762306a36Sopenharmony_ci	.probe		= mt7663s_probe,
24862306a36Sopenharmony_ci	.remove		= mt7663s_remove,
24962306a36Sopenharmony_ci	.id_table	= mt7663s_table,
25062306a36Sopenharmony_ci	.drv.pm		= pm_sleep_ptr(&mt7663s_pm_ops),
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_cimodule_sdio_driver(mt7663s_driver);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ciMODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
25562306a36Sopenharmony_ciMODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
25662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
257