18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 48c2ecf20Sopenharmony_ci Copyright (C) 2004 - 2009 Felix Fietkau <nbd@openwrt.org> 58c2ecf20Sopenharmony_ci <http://rt2x00.serialmonkey.com> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci Module: rt2x00soc 118c2ecf20Sopenharmony_ci Abstract: rt2x00 generic soc device routines. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/bug.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "rt2x00.h" 218c2ecf20Sopenharmony_ci#include "rt2x00soc.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci kfree(rt2x00dev->rf); 268c2ecf20Sopenharmony_ci rt2x00dev->rf = NULL; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci kfree(rt2x00dev->eeprom); 298c2ecf20Sopenharmony_ci rt2x00dev->eeprom = NULL; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci iounmap(rt2x00dev->csr.base); 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(rt2x00dev->dev); 378c2ecf20Sopenharmony_ci struct resource *res; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 408c2ecf20Sopenharmony_ci if (!res) 418c2ecf20Sopenharmony_ci return -ENODEV; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci rt2x00dev->csr.base = ioremap(res->start, resource_size(res)); 448c2ecf20Sopenharmony_ci if (!rt2x00dev->csr.base) 458c2ecf20Sopenharmony_ci return -ENOMEM; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); 488c2ecf20Sopenharmony_ci if (!rt2x00dev->eeprom) 498c2ecf20Sopenharmony_ci goto exit; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); 528c2ecf20Sopenharmony_ci if (!rt2x00dev->rf) 538c2ecf20Sopenharmony_ci goto exit; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciexit: 588c2ecf20Sopenharmony_ci rt2x00_probe_err("Failed to allocate registers\n"); 598c2ecf20Sopenharmony_ci rt2x00soc_free_reg(rt2x00dev); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return -ENOMEM; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciint rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 678c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev; 688c2ecf20Sopenharmony_ci int retval; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); 718c2ecf20Sopenharmony_ci if (!hw) { 728c2ecf20Sopenharmony_ci rt2x00_probe_err("Failed to allocate hardware\n"); 738c2ecf20Sopenharmony_ci return -ENOMEM; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, hw); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci rt2x00dev = hw->priv; 798c2ecf20Sopenharmony_ci rt2x00dev->dev = &pdev->dev; 808c2ecf20Sopenharmony_ci rt2x00dev->ops = ops; 818c2ecf20Sopenharmony_ci rt2x00dev->hw = hw; 828c2ecf20Sopenharmony_ci rt2x00dev->irq = platform_get_irq(pdev, 0); 838c2ecf20Sopenharmony_ci rt2x00dev->name = pdev->dev.driver->name; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci rt2x00dev->clk = clk_get(&pdev->dev, NULL); 868c2ecf20Sopenharmony_ci if (IS_ERR(rt2x00dev->clk)) 878c2ecf20Sopenharmony_ci rt2x00dev->clk = NULL; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci retval = rt2x00soc_alloc_reg(rt2x00dev); 928c2ecf20Sopenharmony_ci if (retval) 938c2ecf20Sopenharmony_ci goto exit_free_device; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci retval = rt2x00lib_probe_dev(rt2x00dev); 968c2ecf20Sopenharmony_ci if (retval) 978c2ecf20Sopenharmony_ci goto exit_free_reg; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciexit_free_reg: 1028c2ecf20Sopenharmony_ci rt2x00soc_free_reg(rt2x00dev); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciexit_free_device: 1058c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return retval; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00soc_probe); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciint rt2x00soc_remove(struct platform_device *pdev) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = platform_get_drvdata(pdev); 1148c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * Free all allocated data. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci rt2x00lib_remove_dev(rt2x00dev); 1208c2ecf20Sopenharmony_ci rt2x00soc_free_reg(rt2x00dev); 1218c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00soc_remove); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1288c2ecf20Sopenharmony_ciint rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = platform_get_drvdata(pdev); 1318c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return rt2x00lib_suspend(rt2x00dev); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00soc_suspend); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciint rt2x00soc_resume(struct platform_device *pdev) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = platform_get_drvdata(pdev); 1408c2ecf20Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return rt2x00lib_resume(rt2x00dev); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00soc_resume); 1458c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* 1488c2ecf20Sopenharmony_ci * rt2x00soc module information. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_PROJECT); 1518c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 1528c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("rt2x00 soc library"); 1538c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 154