net: stmmac: Add support for optional reset control
[linux-block.git] / drivers / net / ethernet / stmicro / stmmac / stmmac_platform.c
CommitLineData
bfab27a1
GC
1/*******************************************************************************
2 This contains the functions to handle the platform driver.
3
4 Copyright (C) 2007-2011 STMicroelectronics Ltd
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms and conditions of the GNU General Public License,
8 version 2, as published by the Free Software Foundation.
9
10 This program is distributed in the hope it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 more details.
14
15 You should have received a copy of the GNU General Public License along with
16 this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18
19 The full GNU General Public License is included in this distribution in
20 the file called "COPYING".
21
22 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
23*******************************************************************************/
24
25#include <linux/platform_device.h>
26#include <linux/io.h>
6a228452
SR
27#include <linux/of.h>
28#include <linux/of_net.h>
bfab27a1
GC
29#include "stmmac.h"
30
6a228452 31#ifdef CONFIG_OF
979857bb 32static int stmmac_probe_config_dt(struct platform_device *pdev,
1dd06ae8
GKH
33 struct plat_stmmacenet_data *plat,
34 const char **mac)
6a228452
SR
35{
36 struct device_node *np = pdev->dev.of_node;
25c83b5c 37 struct stmmac_dma_cfg *dma_cfg;
6a228452
SR
38
39 if (!np)
40 return -ENODEV;
41
42 *mac = of_get_mac_address(np);
43 plat->interface = of_get_phy_mode(np);
25c83b5c 44
9cbadf09
SK
45 /* Get max speed of operation from device tree */
46 if (of_property_read_u32(np, "max-speed", &plat->max_speed))
47 plat->max_speed = -1;
48
25c83b5c
SK
49 plat->bus_id = of_alias_get_id(np, "ethernet");
50 if (plat->bus_id < 0)
51 plat->bus_id = 0;
52
53 of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr);
54
6a228452
SR
55 plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
56 sizeof(struct stmmac_mdio_bus_data),
57 GFP_KERNEL);
58
59 /*
60 * Currently only the properties needed on SPEAr600
61 * are provided. All other properties should be added
62 * once needed on other platforms.
63 */
84c9f8c4
DN
64 if (of_device_is_compatible(np, "st,spear600-gmac") ||
65 of_device_is_compatible(np, "snps,dwmac-3.70a") ||
66 of_device_is_compatible(np, "snps,dwmac")) {
6a228452
SR
67 plat->has_gmac = 1;
68 plat->pmt = 1;
69 }
70
25c83b5c
SK
71 if (of_device_is_compatible(np, "snps,dwmac-3.610") ||
72 of_device_is_compatible(np, "snps,dwmac-3.710")) {
73 plat->enh_desc = 1;
74 plat->bugged_jumbo = 1;
75 plat->force_sf_dma_mode = 1;
76 }
77
64c3b252
BA
78 if (of_find_property(np, "snps,pbl", NULL)) {
79 dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
80 GFP_KERNEL);
81 if (!dma_cfg)
82 return -ENOMEM;
83 plat->dma_cfg = dma_cfg;
84 of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
85 dma_cfg->fixed_burst =
86 of_property_read_bool(np, "snps,fixed-burst");
87 dma_cfg->mixed_burst =
88 of_property_read_bool(np, "snps,mixed-burst");
89 }
e2a240c7
SZ
90 plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
91 if (plat->force_thresh_dma_mode) {
92 plat->force_sf_dma_mode = 0;
93 pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
356f9e74 94 }
25c83b5c 95
6a228452
SR
96 return 0;
97}
98#else
979857bb 99static int stmmac_probe_config_dt(struct platform_device *pdev,
1dd06ae8
GKH
100 struct plat_stmmacenet_data *plat,
101 const char **mac)
6a228452
SR
102{
103 return -ENOSYS;
104}
105#endif /* CONFIG_OF */
106
bfab27a1
GC
107/**
108 * stmmac_pltfr_probe
109 * @pdev: platform device pointer
110 * Description: platform_device probe function. It allocates
111 * the necessary resources and invokes the main to init
112 * the net device, register the mdio bus etc.
113 */
979857bb 114static int stmmac_pltfr_probe(struct platform_device *pdev)
bfab27a1
GC
115{
116 int ret = 0;
117 struct resource *res;
3f8bdecd 118 struct device *dev = &pdev->dev;
bfab27a1
GC
119 void __iomem *addr = NULL;
120 struct stmmac_priv *priv = NULL;
6a228452
SR
121 struct plat_stmmacenet_data *plat_dat = NULL;
122 const char *mac = NULL;
bfab27a1
GC
123
124 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5760f427
SMP
125 addr = devm_ioremap_resource(dev, res);
126 if (IS_ERR(addr))
127 return PTR_ERR(addr);
6a228452 128
f91b29f5 129 plat_dat = dev_get_platdata(&pdev->dev);
6a228452 130 if (pdev->dev.of_node) {
d741434c
SK
131 if (!plat_dat)
132 plat_dat = devm_kzalloc(&pdev->dev,
6a228452
SR
133 sizeof(struct plat_stmmacenet_data),
134 GFP_KERNEL);
135 if (!plat_dat) {
136 pr_err("%s: ERROR: no memory", __func__);
3f8bdecd 137 return -ENOMEM;
6a228452
SR
138 }
139
140 ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
141 if (ret) {
142 pr_err("%s: main dt probe failed", __func__);
3f8bdecd 143 return ret;
6a228452 144 }
6a228452 145 }
cf3f047b
GC
146
147 /* Custom initialisation (if needed)*/
148 if (plat_dat->init) {
149 ret = plat_dat->init(pdev);
150 if (unlikely(ret))
3f8bdecd 151 return ret;
cf3f047b
GC
152 }
153
154 priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
c5e4ddbd 155 if (IS_ERR(priv)) {
cf3f047b 156 pr_err("%s: main driver probe failed", __func__);
c5e4ddbd 157 return PTR_ERR(priv);
bfab27a1
GC
158 }
159
6a228452
SR
160 /* Get MAC address if available (DT) */
161 if (mac)
162 memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
163
bfab27a1
GC
164 /* Get the MAC information */
165 priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
166 if (priv->dev->irq == -ENXIO) {
167 pr_err("%s: ERROR: MAC IRQ configuration "
168 "information not found\n", __func__);
3f8bdecd 169 return -ENXIO;
bfab27a1
GC
170 }
171
172 /*
173 * On some platforms e.g. SPEAr the wake up irq differs from the mac irq
174 * The external wake up irq can be passed through the platform code
175 * named as "eth_wake_irq"
176 *
177 * In case the wake up interrupt is not passed from the platform
178 * so the driver will continue to use the mac irq (ndev->irq)
179 */
180 priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
181 if (priv->wol_irq == -ENXIO)
182 priv->wol_irq = priv->dev->irq;
183
d765955d
GC
184 priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
185
bfab27a1
GC
186 platform_set_drvdata(pdev, priv->dev);
187
bfab27a1
GC
188 pr_debug("STMMAC platform driver registration completed");
189
190 return 0;
bfab27a1
GC
191}
192
193/**
194 * stmmac_pltfr_remove
195 * @pdev: platform device pointer
196 * Description: this function calls the main to free the net resources
197 * and calls the platforms hook and release the resources (e.g. mem).
198 */
199static int stmmac_pltfr_remove(struct platform_device *pdev)
200{
201 struct net_device *ndev = platform_get_drvdata(pdev);
202 struct stmmac_priv *priv = netdev_priv(ndev);
bfab27a1
GC
203 int ret = stmmac_dvr_remove(ndev);
204
bfab27a1
GC
205 if (priv->plat->exit)
206 priv->plat->exit(pdev);
207
bfab27a1
GC
208 return ret;
209}
210
211#ifdef CONFIG_PM
212static int stmmac_pltfr_suspend(struct device *dev)
bfab27a1 213{
3256251f 214 int ret;
bfab27a1 215 struct net_device *ndev = dev_get_drvdata(dev);
33a23e22 216 struct stmmac_priv *priv = netdev_priv(ndev);
3256251f 217 struct platform_device *pdev = to_platform_device(dev);
bfab27a1 218
33a23e22
SK
219 ret = stmmac_suspend(ndev);
220 if (priv->plat->exit)
221 priv->plat->exit(pdev);
3256251f
FV
222
223 return ret;
bfab27a1
GC
224}
225
33a23e22 226static int stmmac_pltfr_resume(struct device *dev)
bfab27a1
GC
227{
228 struct net_device *ndev = dev_get_drvdata(dev);
33a23e22 229 struct stmmac_priv *priv = netdev_priv(ndev);
3256251f
FV
230 struct platform_device *pdev = to_platform_device(dev);
231
33a23e22
SK
232 if (priv->plat->init)
233 priv->plat->init(pdev);
bfab27a1 234
33a23e22 235 return stmmac_resume(ndev);
bfab27a1
GC
236}
237
bfab27a1
GC
238#endif /* CONFIG_PM */
239
33a23e22
SK
240static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops,
241 stmmac_pltfr_suspend, stmmac_pltfr_resume);
242
6a228452 243static const struct of_device_id stmmac_dt_ids[] = {
84c9f8c4 244 { .compatible = "st,spear600-gmac"},
25c83b5c 245 { .compatible = "snps,dwmac-3.610"},
84c9f8c4 246 { .compatible = "snps,dwmac-3.70a"},
25c83b5c 247 { .compatible = "snps,dwmac-3.710"},
84c9f8c4 248 { .compatible = "snps,dwmac"},
6a228452
SR
249 { /* sentinel */ }
250};
251MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
252
ba27ec66 253struct platform_driver stmmac_pltfr_driver = {
bfab27a1
GC
254 .probe = stmmac_pltfr_probe,
255 .remove = stmmac_pltfr_remove,
256 .driver = {
257 .name = STMMAC_RESOURCE_NAME,
258 .owner = THIS_MODULE,
259 .pm = &stmmac_pltfr_pm_ops,
6a228452 260 .of_match_table = of_match_ptr(stmmac_dt_ids),
bfab27a1
GC
261 },
262};
263
bfab27a1
GC
264MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
265MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
266MODULE_LICENSE("GPL");