154 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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: rt2x00soc11 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 23static 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 34static 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 57exit:58 rt2x00_probe_err("Failed to allocate registers\n");59 rt2x00soc_free_reg(rt2x00dev);60 61 return -ENOMEM;62}63 64int 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 101exit_free_reg:102 rt2x00soc_free_reg(rt2x00dev);103 104exit_free_device:105 ieee80211_free_hw(hw);106 107 return retval;108}109EXPORT_SYMBOL_GPL(rt2x00soc_probe);110 111int 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}125EXPORT_SYMBOL_GPL(rt2x00soc_remove);126 127#ifdef CONFIG_PM128int 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);134}135EXPORT_SYMBOL_GPL(rt2x00soc_suspend);136 137int 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}144EXPORT_SYMBOL_GPL(rt2x00soc_resume);145#endif /* CONFIG_PM */146 147/*148 * rt2x00soc module information.149 */150MODULE_AUTHOR(DRV_PROJECT);151MODULE_VERSION(DRV_VERSION);152MODULE_DESCRIPTION("rt2x00 soc library");153MODULE_LICENSE("GPL");154