162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org> 462306a36Sopenharmony_ci * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 762306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 862306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1162306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1262306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1362306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1462306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1562306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1662306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/nl80211.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/module.h> 2262306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 2362306a36Sopenharmony_ci#include "ath9k.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic const struct platform_device_id ath9k_platform_id_table[] = { 2662306a36Sopenharmony_ci { 2762306a36Sopenharmony_ci .name = "ath9k", 2862306a36Sopenharmony_ci .driver_data = AR5416_AR9100_DEVID, 2962306a36Sopenharmony_ci }, 3062306a36Sopenharmony_ci { 3162306a36Sopenharmony_ci .name = "ar933x_wmac", 3262306a36Sopenharmony_ci .driver_data = AR9300_DEVID_AR9330, 3362306a36Sopenharmony_ci }, 3462306a36Sopenharmony_ci { 3562306a36Sopenharmony_ci .name = "ar934x_wmac", 3662306a36Sopenharmony_ci .driver_data = AR9300_DEVID_AR9340, 3762306a36Sopenharmony_ci }, 3862306a36Sopenharmony_ci { 3962306a36Sopenharmony_ci .name = "qca955x_wmac", 4062306a36Sopenharmony_ci .driver_data = AR9300_DEVID_QCA955X, 4162306a36Sopenharmony_ci }, 4262306a36Sopenharmony_ci { 4362306a36Sopenharmony_ci .name = "qca953x_wmac", 4462306a36Sopenharmony_ci .driver_data = AR9300_DEVID_AR953X, 4562306a36Sopenharmony_ci }, 4662306a36Sopenharmony_ci { 4762306a36Sopenharmony_ci .name = "qca956x_wmac", 4862306a36Sopenharmony_ci .driver_data = AR9300_DEVID_QCA956X, 4962306a36Sopenharmony_ci }, 5062306a36Sopenharmony_ci {}, 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* return bus cachesize in 4B word units */ 5462306a36Sopenharmony_cistatic void ath_ahb_read_cachesize(struct ath_common *common, int *csz) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci *csz = L1_CACHE_BYTES >> 2; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci ath_err(common, "%s: eeprom data has to be provided externally\n", 6262306a36Sopenharmony_ci __func__); 6362306a36Sopenharmony_ci return false; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic const struct ath_bus_ops ath_ahb_bus_ops = { 6762306a36Sopenharmony_ci .ath_bus_type = ATH_AHB, 6862306a36Sopenharmony_ci .read_cachesize = ath_ahb_read_cachesize, 6962306a36Sopenharmony_ci .eeprom_read = ath_ahb_eeprom_read, 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int ath_ahb_probe(struct platform_device *pdev) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci void __iomem *mem; 7562306a36Sopenharmony_ci struct ath_softc *sc; 7662306a36Sopenharmony_ci struct ieee80211_hw *hw; 7762306a36Sopenharmony_ci struct resource *res; 7862306a36Sopenharmony_ci const struct platform_device_id *id = platform_get_device_id(pdev); 7962306a36Sopenharmony_ci int irq; 8062306a36Sopenharmony_ci int ret = 0; 8162306a36Sopenharmony_ci struct ath_hw *ah; 8262306a36Sopenharmony_ci char hw_name[64]; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (!dev_get_platdata(&pdev->dev)) { 8562306a36Sopenharmony_ci dev_err(&pdev->dev, "no platform data specified\n"); 8662306a36Sopenharmony_ci return -EINVAL; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9062306a36Sopenharmony_ci if (res == NULL) { 9162306a36Sopenharmony_ci dev_err(&pdev->dev, "no memory resource found\n"); 9262306a36Sopenharmony_ci return -ENXIO; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci mem = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 9662306a36Sopenharmony_ci if (mem == NULL) { 9762306a36Sopenharmony_ci dev_err(&pdev->dev, "ioremap failed\n"); 9862306a36Sopenharmony_ci return -ENOMEM; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 10262306a36Sopenharmony_ci if (irq < 0) 10362306a36Sopenharmony_ci return irq; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci ath9k_fill_chanctx_ops(); 10662306a36Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); 10762306a36Sopenharmony_ci if (hw == NULL) { 10862306a36Sopenharmony_ci dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); 10962306a36Sopenharmony_ci return -ENOMEM; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci SET_IEEE80211_DEV(hw, &pdev->dev); 11362306a36Sopenharmony_ci platform_set_drvdata(pdev, hw); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci sc = hw->priv; 11662306a36Sopenharmony_ci sc->hw = hw; 11762306a36Sopenharmony_ci sc->dev = &pdev->dev; 11862306a36Sopenharmony_ci sc->mem = mem; 11962306a36Sopenharmony_ci sc->irq = irq; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); 12262306a36Sopenharmony_ci if (ret) { 12362306a36Sopenharmony_ci dev_err(&pdev->dev, "request_irq failed\n"); 12462306a36Sopenharmony_ci goto err_free_hw; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops); 12862306a36Sopenharmony_ci if (ret) { 12962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to initialize device\n"); 13062306a36Sopenharmony_ci goto err_irq; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ah = sc->sc_ah; 13462306a36Sopenharmony_ci ath9k_hw_name(ah, hw_name, sizeof(hw_name)); 13562306a36Sopenharmony_ci wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n", 13662306a36Sopenharmony_ci hw_name, mem, irq); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci err_irq: 14162306a36Sopenharmony_ci free_irq(irq, sc); 14262306a36Sopenharmony_ci err_free_hw: 14362306a36Sopenharmony_ci ieee80211_free_hw(hw); 14462306a36Sopenharmony_ci return ret; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int ath_ahb_remove(struct platform_device *pdev) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct ieee80211_hw *hw = platform_get_drvdata(pdev); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (hw) { 15262306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci ath9k_deinit_device(sc); 15562306a36Sopenharmony_ci free_irq(sc->irq, sc); 15662306a36Sopenharmony_ci ieee80211_free_hw(sc->hw); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic struct platform_driver ath_ahb_driver = { 16362306a36Sopenharmony_ci .probe = ath_ahb_probe, 16462306a36Sopenharmony_ci .remove = ath_ahb_remove, 16562306a36Sopenharmony_ci .driver = { 16662306a36Sopenharmony_ci .name = "ath9k", 16762306a36Sopenharmony_ci }, 16862306a36Sopenharmony_ci .id_table = ath9k_platform_id_table, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciint ath_ahb_init(void) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci return platform_driver_register(&ath_ahb_driver); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_civoid ath_ahb_exit(void) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci platform_driver_unregister(&ath_ahb_driver); 18162306a36Sopenharmony_ci} 182