Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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>
 27#include <linux/of.h>
 28#include <linux/of_net.h>
 29#include "stmmac.h"
 30
 31#ifdef CONFIG_OF
 32static int __devinit stmmac_probe_config_dt(struct platform_device *pdev,
 33					    struct plat_stmmacenet_data *plat,
 34					    const char **mac)
 35{
 36	struct device_node *np = pdev->dev.of_node;
 37
 38	if (!np)
 39		return -ENODEV;
 40
 41	*mac = of_get_mac_address(np);
 42	plat->interface = of_get_phy_mode(np);
 43	plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
 44					   sizeof(struct stmmac_mdio_bus_data),
 45					   GFP_KERNEL);
 46
 47	/*
 48	 * Currently only the properties needed on SPEAr600
 49	 * are provided. All other properties should be added
 50	 * once needed on other platforms.
 51	 */
 52	if (of_device_is_compatible(np, "st,spear600-gmac")) {
 53		plat->has_gmac = 1;
 54		plat->pmt = 1;
 55	}
 56
 57	return 0;
 58}
 59#else
 60static int __devinit stmmac_probe_config_dt(struct platform_device *pdev,
 61					    struct plat_stmmacenet_data *plat,
 62					    const char **mac)
 63{
 64	return -ENOSYS;
 65}
 66#endif /* CONFIG_OF */
 67
 68/**
 69 * stmmac_pltfr_probe
 70 * @pdev: platform device pointer
 71 * Description: platform_device probe function. It allocates
 72 * the necessary resources and invokes the main to init
 73 * the net device, register the mdio bus etc.
 74 */
 75static int stmmac_pltfr_probe(struct platform_device *pdev)
 76{
 77	int ret = 0;
 78	struct resource *res;
 79	void __iomem *addr = NULL;
 80	struct stmmac_priv *priv = NULL;
 81	struct plat_stmmacenet_data *plat_dat = NULL;
 82	const char *mac = NULL;
 83
 84	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 85	if (!res)
 86		return -ENODEV;
 87
 88	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
 89		pr_err("%s: ERROR: memory allocation failed"
 90		       "cannot get the I/O addr 0x%x\n",
 91		       __func__, (unsigned int)res->start);
 92		return -EBUSY;
 93	}
 94
 95	addr = ioremap(res->start, resource_size(res));
 96	if (!addr) {
 97		pr_err("%s: ERROR: memory mapping failed", __func__);
 98		ret = -ENOMEM;
 99		goto out_release_region;
100	}
101
102	if (pdev->dev.of_node) {
103		plat_dat = devm_kzalloc(&pdev->dev,
104					sizeof(struct plat_stmmacenet_data),
105					GFP_KERNEL);
106		if (!plat_dat) {
107			pr_err("%s: ERROR: no memory", __func__);
108			ret = -ENOMEM;
109			goto out_unmap;
110		}
111
112		ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
113		if (ret) {
114			pr_err("%s: main dt probe failed", __func__);
115			goto out_unmap;
116		}
117	} else {
118		plat_dat = pdev->dev.platform_data;
119	}
120
121	/* Custom initialisation (if needed)*/
122	if (plat_dat->init) {
123		ret = plat_dat->init(pdev);
124		if (unlikely(ret))
125			goto out_unmap;
126	}
127
128	priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
129	if (!priv) {
130		pr_err("%s: main driver probe failed", __func__);
131		goto out_unmap;
132	}
133
134	/* Get MAC address if available (DT) */
135	if (mac)
136		memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
137
138	/* Get the MAC information */
139	priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
140	if (priv->dev->irq == -ENXIO) {
141		pr_err("%s: ERROR: MAC IRQ configuration "
142		       "information not found\n", __func__);
143		ret = -ENXIO;
144		goto out_unmap;
145	}
146
147	/*
148	 * On some platforms e.g. SPEAr the wake up irq differs from the mac irq
149	 * The external wake up irq can be passed through the platform code
150	 * named as "eth_wake_irq"
151	 *
152	 * In case the wake up interrupt is not passed from the platform
153	 * so the driver will continue to use the mac irq (ndev->irq)
154	 */
155	priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
156	if (priv->wol_irq == -ENXIO)
157		priv->wol_irq = priv->dev->irq;
158
159	platform_set_drvdata(pdev, priv->dev);
160
161	pr_debug("STMMAC platform driver registration completed");
162
163	return 0;
164
165out_unmap:
166	iounmap(addr);
167	platform_set_drvdata(pdev, NULL);
168
169out_release_region:
170	release_mem_region(res->start, resource_size(res));
171
172	return ret;
173}
174
175/**
176 * stmmac_pltfr_remove
177 * @pdev: platform device pointer
178 * Description: this function calls the main to free the net resources
179 * and calls the platforms hook and release the resources (e.g. mem).
180 */
181static int stmmac_pltfr_remove(struct platform_device *pdev)
182{
183	struct net_device *ndev = platform_get_drvdata(pdev);
184	struct stmmac_priv *priv = netdev_priv(ndev);
185	struct resource *res;
186	int ret = stmmac_dvr_remove(ndev);
187
188	if (priv->plat->exit)
189		priv->plat->exit(pdev);
190
191	platform_set_drvdata(pdev, NULL);
192
193	iounmap((void *)priv->ioaddr);
194	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
195	release_mem_region(res->start, resource_size(res));
196
197	return ret;
198}
199
200#ifdef CONFIG_PM
201static int stmmac_pltfr_suspend(struct device *dev)
202{
203	struct net_device *ndev = dev_get_drvdata(dev);
204
205	return stmmac_suspend(ndev);
206}
207
208static int stmmac_pltfr_resume(struct device *dev)
209{
210	struct net_device *ndev = dev_get_drvdata(dev);
211
212	return stmmac_resume(ndev);
213}
214
215int stmmac_pltfr_freeze(struct device *dev)
216{
217	int ret;
218	struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev);
219	struct net_device *ndev = dev_get_drvdata(dev);
220	struct platform_device *pdev = to_platform_device(dev);
221
222	ret = stmmac_freeze(ndev);
223	if (plat_dat->exit)
224		plat_dat->exit(pdev);
225
226	return ret;
227}
228
229int stmmac_pltfr_restore(struct device *dev)
230{
231	struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev);
232	struct net_device *ndev = dev_get_drvdata(dev);
233	struct platform_device *pdev = to_platform_device(dev);
234
235	if (plat_dat->init)
236		plat_dat->init(pdev);
237
238	return stmmac_restore(ndev);
239}
240
241static const struct dev_pm_ops stmmac_pltfr_pm_ops = {
242	.suspend = stmmac_pltfr_suspend,
243	.resume = stmmac_pltfr_resume,
244	.freeze = stmmac_pltfr_freeze,
245	.thaw = stmmac_pltfr_restore,
246	.restore = stmmac_pltfr_restore,
247};
248#else
249static const struct dev_pm_ops stmmac_pltfr_pm_ops;
250#endif /* CONFIG_PM */
251
252static const struct of_device_id stmmac_dt_ids[] = {
253	{ .compatible = "st,spear600-gmac", },
254	{ /* sentinel */ }
255};
256MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
257
258struct platform_driver stmmac_pltfr_driver = {
259	.probe = stmmac_pltfr_probe,
260	.remove = stmmac_pltfr_remove,
261	.driver = {
262		   .name = STMMAC_RESOURCE_NAME,
263		   .owner = THIS_MODULE,
264		   .pm = &stmmac_pltfr_pm_ops,
265		   .of_match_table = of_match_ptr(stmmac_dt_ids),
266		   },
267};
268
269MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
270MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
271MODULE_LICENSE("GPL");