18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc.
38c2ecf20Sopenharmony_ci * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
48c2ecf20Sopenharmony_ci * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
78c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
88c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
118c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
128c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
138c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
148c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
158c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
168c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/nl80211.h>
208c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
218c2ecf20Sopenharmony_ci#include <linux/module.h>
228c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h>
238c2ecf20Sopenharmony_ci#include "ath9k.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const struct platform_device_id ath9k_platform_id_table[] = {
268c2ecf20Sopenharmony_ci	{
278c2ecf20Sopenharmony_ci		.name = "ath9k",
288c2ecf20Sopenharmony_ci		.driver_data = AR5416_AR9100_DEVID,
298c2ecf20Sopenharmony_ci	},
308c2ecf20Sopenharmony_ci	{
318c2ecf20Sopenharmony_ci		.name = "ar933x_wmac",
328c2ecf20Sopenharmony_ci		.driver_data = AR9300_DEVID_AR9330,
338c2ecf20Sopenharmony_ci	},
348c2ecf20Sopenharmony_ci	{
358c2ecf20Sopenharmony_ci		.name = "ar934x_wmac",
368c2ecf20Sopenharmony_ci		.driver_data = AR9300_DEVID_AR9340,
378c2ecf20Sopenharmony_ci	},
388c2ecf20Sopenharmony_ci	{
398c2ecf20Sopenharmony_ci		.name = "qca955x_wmac",
408c2ecf20Sopenharmony_ci		.driver_data = AR9300_DEVID_QCA955X,
418c2ecf20Sopenharmony_ci	},
428c2ecf20Sopenharmony_ci	{
438c2ecf20Sopenharmony_ci		.name = "qca953x_wmac",
448c2ecf20Sopenharmony_ci		.driver_data = AR9300_DEVID_AR953X,
458c2ecf20Sopenharmony_ci	},
468c2ecf20Sopenharmony_ci	{
478c2ecf20Sopenharmony_ci		.name = "qca956x_wmac",
488c2ecf20Sopenharmony_ci		.driver_data = AR9300_DEVID_QCA956X,
498c2ecf20Sopenharmony_ci	},
508c2ecf20Sopenharmony_ci	{},
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* return bus cachesize in 4B word units */
548c2ecf20Sopenharmony_cistatic void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	*csz = L1_CACHE_BYTES >> 2;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	ath_err(common, "%s: eeprom data has to be provided externally\n",
628c2ecf20Sopenharmony_ci		__func__);
638c2ecf20Sopenharmony_ci	return false;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic const struct ath_bus_ops ath_ahb_bus_ops  = {
678c2ecf20Sopenharmony_ci	.ath_bus_type = ATH_AHB,
688c2ecf20Sopenharmony_ci	.read_cachesize = ath_ahb_read_cachesize,
698c2ecf20Sopenharmony_ci	.eeprom_read = ath_ahb_eeprom_read,
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int ath_ahb_probe(struct platform_device *pdev)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	void __iomem *mem;
758c2ecf20Sopenharmony_ci	struct ath_softc *sc;
768c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw;
778c2ecf20Sopenharmony_ci	struct resource *res;
788c2ecf20Sopenharmony_ci	const struct platform_device_id *id = platform_get_device_id(pdev);
798c2ecf20Sopenharmony_ci	int irq;
808c2ecf20Sopenharmony_ci	int ret = 0;
818c2ecf20Sopenharmony_ci	struct ath_hw *ah;
828c2ecf20Sopenharmony_ci	char hw_name[64];
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (!dev_get_platdata(&pdev->dev)) {
858c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no platform data specified\n");
868c2ecf20Sopenharmony_ci		return -EINVAL;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
908c2ecf20Sopenharmony_ci	if (res == NULL) {
918c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no memory resource found\n");
928c2ecf20Sopenharmony_ci		return -ENXIO;
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	mem = devm_ioremap(&pdev->dev, res->start, resource_size(res));
968c2ecf20Sopenharmony_ci	if (mem == NULL) {
978c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "ioremap failed\n");
988c2ecf20Sopenharmony_ci		return -ENOMEM;
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1028c2ecf20Sopenharmony_ci	if (res == NULL) {
1038c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no IRQ resource found\n");
1048c2ecf20Sopenharmony_ci		return -ENXIO;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	irq = res->start;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	ath9k_fill_chanctx_ops();
1108c2ecf20Sopenharmony_ci	hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
1118c2ecf20Sopenharmony_ci	if (hw == NULL) {
1128c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
1138c2ecf20Sopenharmony_ci		return -ENOMEM;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	SET_IEEE80211_DEV(hw, &pdev->dev);
1178c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, hw);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	sc = hw->priv;
1208c2ecf20Sopenharmony_ci	sc->hw = hw;
1218c2ecf20Sopenharmony_ci	sc->dev = &pdev->dev;
1228c2ecf20Sopenharmony_ci	sc->mem = mem;
1238c2ecf20Sopenharmony_ci	sc->irq = irq;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
1268c2ecf20Sopenharmony_ci	if (ret) {
1278c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "request_irq failed\n");
1288c2ecf20Sopenharmony_ci		goto err_free_hw;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops);
1328c2ecf20Sopenharmony_ci	if (ret) {
1338c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to initialize device\n");
1348c2ecf20Sopenharmony_ci		goto err_irq;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	ah = sc->sc_ah;
1388c2ecf20Sopenharmony_ci	ath9k_hw_name(ah, hw_name, sizeof(hw_name));
1398c2ecf20Sopenharmony_ci	wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n",
1408c2ecf20Sopenharmony_ci		   hw_name, mem, irq);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	return 0;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci err_irq:
1458c2ecf20Sopenharmony_ci	free_irq(irq, sc);
1468c2ecf20Sopenharmony_ci err_free_hw:
1478c2ecf20Sopenharmony_ci	ieee80211_free_hw(hw);
1488c2ecf20Sopenharmony_ci	return ret;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int ath_ahb_remove(struct platform_device *pdev)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw = platform_get_drvdata(pdev);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (hw) {
1568c2ecf20Sopenharmony_ci		struct ath_softc *sc = hw->priv;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		ath9k_deinit_device(sc);
1598c2ecf20Sopenharmony_ci		free_irq(sc->irq, sc);
1608c2ecf20Sopenharmony_ci		ieee80211_free_hw(sc->hw);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return 0;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic struct platform_driver ath_ahb_driver = {
1678c2ecf20Sopenharmony_ci	.probe      = ath_ahb_probe,
1688c2ecf20Sopenharmony_ci	.remove     = ath_ahb_remove,
1698c2ecf20Sopenharmony_ci	.driver		= {
1708c2ecf20Sopenharmony_ci		.name	= "ath9k",
1718c2ecf20Sopenharmony_ci	},
1728c2ecf20Sopenharmony_ci	.id_table    = ath9k_platform_id_table,
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, ath9k_platform_id_table);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ciint ath_ahb_init(void)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	return platform_driver_register(&ath_ahb_driver);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_civoid ath_ahb_exit(void)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	platform_driver_unregister(&ath_ahb_driver);
1858c2ecf20Sopenharmony_ci}
186