1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 4 Copyright (C) 2004 - 2009 Felix Fietkau <nbd@openwrt.org> 5 <http://rt2x00.serialmonkey.com> 6 7 */ 8 9 /* 10 Module: rt2x00soc 11 Abstract: rt2x00 generic soc device routines. 12 */ 13 14 #include <linux/bug.h> 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/platform_device.h> 18 #include <linux/slab.h> 19 20 #include "rt2x00.h" 21 #include "rt2x00soc.h" 22 23 static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev) 24 { 25 kfree(rt2x00dev->rf); 26 rt2x00dev->rf = NULL; 27 28 kfree(rt2x00dev->eeprom); 29 rt2x00dev->eeprom = NULL; 30 31 iounmap(rt2x00dev->csr.base); 32 } 33 34 static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) 35 { 36 struct platform_device *pdev = to_platform_device(rt2x00dev->dev); 37 struct resource *res; 38 39 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 40 if (!res) 41 return -ENODEV; 42 43 rt2x00dev->csr.base = ioremap(res->start, resource_size(res)); 44 if (!rt2x00dev->csr.base) 45 return -ENOMEM; 46 47 rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); 48 if (!rt2x00dev->eeprom) 49 goto exit; 50 51 rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); 52 if (!rt2x00dev->rf) 53 goto exit; 54 55 return 0; 56 57 exit: 58 rt2x00_probe_err("Failed to allocate registers\n"); 59 rt2x00soc_free_reg(rt2x00dev); 60 61 return -ENOMEM; 62 } 63 64 int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) 65 { 66 struct ieee80211_hw *hw; 67 struct rt2x00_dev *rt2x00dev; 68 int retval; 69 70 hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); 71 if (!hw) { 72 rt2x00_probe_err("Failed to allocate hardware\n"); 73 return -ENOMEM; 74 } 75 76 platform_set_drvdata(pdev, hw); 77 78 rt2x00dev = hw->priv; 79 rt2x00dev->dev = &pdev->dev; 80 rt2x00dev->ops = ops; 81 rt2x00dev->hw = hw; 82 rt2x00dev->irq = platform_get_irq(pdev, 0); 83 rt2x00dev->name = pdev->dev.driver->name; 84 85 rt2x00dev->clk = clk_get(&pdev->dev, NULL); 86 if (IS_ERR(rt2x00dev->clk)) 87 rt2x00dev->clk = NULL; 88 89 rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); 90 91 retval = rt2x00soc_alloc_reg(rt2x00dev); 92 if (retval) 93 goto exit_free_device; 94 95 retval = rt2x00lib_probe_dev(rt2x00dev); 96 if (retval) 97 goto exit_free_reg; 98 99 return 0; 100 101 exit_free_reg: 102 rt2x00soc_free_reg(rt2x00dev); 103 104 exit_free_device: 105 ieee80211_free_hw(hw); 106 107 return retval; 108 } 109 EXPORT_SYMBOL_GPL(rt2x00soc_probe); 110 111 int rt2x00soc_remove(struct platform_device *pdev) 112 { 113 struct ieee80211_hw *hw = platform_get_drvdata(pdev); 114 struct rt2x00_dev *rt2x00dev = hw->priv; 115 116 /* 117 * Free all allocated data. 118 */ 119 rt2x00lib_remove_dev(rt2x00dev); 120 rt2x00soc_free_reg(rt2x00dev); 121 ieee80211_free_hw(hw); 122 123 return 0; 124 } 125 EXPORT_SYMBOL_GPL(rt2x00soc_remove); 126 127 #ifdef CONFIG_PM 128 int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) 129 { 130 struct ieee80211_hw *hw = platform_get_drvdata(pdev); 131 struct rt2x00_dev *rt2x00dev = hw->priv; 132 133 return rt2x00lib_suspend(rt2x00dev, state); 134 } 135 EXPORT_SYMBOL_GPL(rt2x00soc_suspend); 136 137 int rt2x00soc_resume(struct platform_device *pdev) 138 { 139 struct ieee80211_hw *hw = platform_get_drvdata(pdev); 140 struct rt2x00_dev *rt2x00dev = hw->priv; 141 142 return rt2x00lib_resume(rt2x00dev); 143 } 144 EXPORT_SYMBOL_GPL(rt2x00soc_resume); 145 #endif /* CONFIG_PM */ 146 147 /* 148 * rt2x00soc module information. 149 */ 150 MODULE_AUTHOR(DRV_PROJECT); 151 MODULE_VERSION(DRV_VERSION); 152 MODULE_DESCRIPTION("rt2x00 soc library"); 153 MODULE_LICENSE("GPL"); 154