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(objp: rt2x00dev->rf); |
26 | rt2x00dev->rf = NULL; |
27 | |
28 | kfree(objp: rt2x00dev->eeprom); |
29 | rt2x00dev->eeprom = NULL; |
30 | |
31 | iounmap(addr: 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(offset: res->start, size: resource_size(res)); |
44 | if (!rt2x00dev->csr.base) |
45 | return -ENOMEM; |
46 | |
47 | rt2x00dev->eeprom = kzalloc(size: rt2x00dev->ops->eeprom_size, GFP_KERNEL); |
48 | if (!rt2x00dev->eeprom) |
49 | goto exit; |
50 | |
51 | rt2x00dev->rf = kzalloc(size: 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(priv_data_len: sizeof(struct rt2x00_dev), ops: ops->hw); |
71 | if (!hw) { |
72 | rt2x00_probe_err("Failed to allocate hardware\n" ); |
73 | return -ENOMEM; |
74 | } |
75 | |
76 | platform_set_drvdata(pdev, data: 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(dev: &pdev->dev, NULL); |
86 | if (IS_ERR(ptr: rt2x00dev->clk)) |
87 | rt2x00dev->clk = NULL; |
88 | |
89 | rt2x00_set_chip_intf(rt2x00dev, intf: 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); |
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 | |