]>
Commit | Line | Data |
---|---|---|
1edb9ca6 SR |
1 | /* 10G controller driver for Samsung SoCs |
2 | * | |
3 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. | |
4 | * http://www.samsung.com | |
5 | * | |
6 | * Author: Siva Reddy Kallam <siva.kallam@samsung.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
14 | ||
15 | #include <linux/etherdevice.h> | |
16 | #include <linux/io.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/netdevice.h> | |
19 | #include <linux/of.h> | |
20 | #include <linux/of_irq.h> | |
21 | #include <linux/of_net.h> | |
22 | #include <linux/phy.h> | |
23 | #include <linux/platform_device.h> | |
24 | #include <linux/sxgbe_platform.h> | |
25 | ||
26 | #include "sxgbe_common.h" | |
27 | #include "sxgbe_reg.h" | |
28 | ||
29 | #ifdef CONFIG_OF | |
30 | static int sxgbe_probe_config_dt(struct platform_device *pdev, | |
31 | struct sxgbe_plat_data *plat, | |
32 | const char **mac) | |
33 | { | |
34 | struct device_node *np = pdev->dev.of_node; | |
35 | struct sxgbe_dma_cfg *dma_cfg; | |
36 | ||
37 | if (!np) | |
38 | return -ENODEV; | |
39 | ||
40 | *mac = of_get_mac_address(np); | |
41 | plat->interface = of_get_phy_mode(np); | |
42 | ||
43 | plat->bus_id = of_alias_get_id(np, "ethernet"); | |
44 | if (plat->bus_id < 0) | |
45 | plat->bus_id = 0; | |
46 | ||
47 | plat->mdio_bus_data = devm_kzalloc(&pdev->dev, | |
48 | sizeof(*plat->mdio_bus_data), | |
49 | GFP_KERNEL); | |
50 | ||
51 | dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), GFP_KERNEL); | |
52 | if (!dma_cfg) | |
53 | return -ENOMEM; | |
54 | ||
55 | plat->dma_cfg = dma_cfg; | |
56 | of_property_read_u32(np, "samsung,pbl", &dma_cfg->pbl); | |
57 | if (of_property_read_u32(np, "samsung,burst-map", &dma_cfg->burst_map) == 0) | |
58 | dma_cfg->fixed_burst = true; | |
59 | ||
60 | return 0; | |
61 | } | |
62 | #else | |
63 | static int sxgbe_probe_config_dt(struct platform_device *pdev, | |
64 | struct sxgbe_plat_data *plat, | |
65 | const char **mac) | |
66 | { | |
67 | return -ENOSYS; | |
68 | } | |
69 | #endif /* CONFIG_OF */ | |
70 | ||
71 | /** | |
72 | * sxgbe_platform_probe | |
73 | * @pdev: platform device pointer | |
74 | * Description: platform_device probe function. It allocates | |
75 | * the necessary resources and invokes the main to init | |
76 | * the net device, register the mdio bus etc. | |
77 | */ | |
78 | static int sxgbe_platform_probe(struct platform_device *pdev) | |
79 | { | |
80 | int ret; | |
81 | int i, chan; | |
82 | struct resource *res; | |
83 | struct device *dev = &pdev->dev; | |
84 | void __iomem *addr; | |
85 | struct sxgbe_priv_data *priv = NULL; | |
86 | struct sxgbe_plat_data *plat_dat = NULL; | |
87 | const char *mac = NULL; | |
88 | struct net_device *ndev = platform_get_drvdata(pdev); | |
89 | struct device_node *node = dev->of_node; | |
90 | ||
91 | /* Get memory resource */ | |
92 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
1edb9ca6 SR |
93 | addr = devm_ioremap_resource(dev, res); |
94 | if (IS_ERR(addr)) | |
95 | return PTR_ERR(addr); | |
96 | ||
97 | if (pdev->dev.of_node) { | |
98 | plat_dat = devm_kzalloc(&pdev->dev, | |
99 | sizeof(struct sxgbe_plat_data), | |
100 | GFP_KERNEL); | |
101 | if (!plat_dat) | |
102 | return -ENOMEM; | |
103 | ||
104 | ret = sxgbe_probe_config_dt(pdev, plat_dat, &mac); | |
105 | if (ret) { | |
106 | pr_err("%s: main dt probe failed\n", __func__); | |
107 | return ret; | |
108 | } | |
109 | } | |
110 | ||
1edb9ca6 SR |
111 | priv = sxgbe_drv_probe(&(pdev->dev), plat_dat, addr); |
112 | if (!priv) { | |
113 | pr_err("%s: main driver probe failed\n", __func__); | |
114 | goto err_out; | |
115 | } | |
116 | ||
117 | /* Get the SXGBE common INT information */ | |
118 | priv->irq = irq_of_parse_and_map(node, 0); | |
119 | if (priv->irq <= 0) { | |
120 | dev_err(dev, "sxgbe common irq parsing failed\n"); | |
121 | goto err_drv_remove; | |
122 | } | |
123 | ||
1c1832c7 G |
124 | /* Get MAC address if available (DT) */ |
125 | if (mac) | |
126 | ether_addr_copy(priv->dev->dev_addr, mac); | |
127 | ||
1edb9ca6 SR |
128 | /* Get the TX/RX IRQ numbers */ |
129 | for (i = 0, chan = 1; i < SXGBE_TX_QUEUES; i++) { | |
130 | priv->txq[i]->irq_no = irq_of_parse_and_map(node, chan++); | |
131 | if (priv->txq[i]->irq_no <= 0) { | |
132 | dev_err(dev, "sxgbe tx irq parsing failed\n"); | |
133 | goto err_tx_irq_unmap; | |
134 | } | |
135 | } | |
136 | ||
137 | for (i = 0; i < SXGBE_RX_QUEUES; i++) { | |
138 | priv->rxq[i]->irq_no = irq_of_parse_and_map(node, chan++); | |
139 | if (priv->rxq[i]->irq_no <= 0) { | |
140 | dev_err(dev, "sxgbe rx irq parsing failed\n"); | |
141 | goto err_rx_irq_unmap; | |
142 | } | |
143 | } | |
144 | ||
acc18c14 G |
145 | priv->lpi_irq = irq_of_parse_and_map(node, chan); |
146 | if (priv->lpi_irq <= 0) { | |
147 | dev_err(dev, "sxgbe lpi irq parsing failed\n"); | |
148 | goto err_rx_irq_unmap; | |
149 | } | |
150 | ||
1edb9ca6 SR |
151 | platform_set_drvdata(pdev, priv->dev); |
152 | ||
153 | pr_debug("platform driver registration completed\n"); | |
154 | ||
155 | return 0; | |
156 | ||
157 | err_rx_irq_unmap: | |
79c13423 | 158 | while (i--) |
1edb9ca6 SR |
159 | irq_dispose_mapping(priv->rxq[i]->irq_no); |
160 | i = SXGBE_TX_QUEUES; | |
161 | err_tx_irq_unmap: | |
79c13423 | 162 | while (i--) |
1edb9ca6 SR |
163 | irq_dispose_mapping(priv->txq[i]->irq_no); |
164 | irq_dispose_mapping(priv->irq); | |
165 | err_drv_remove: | |
166 | sxgbe_drv_remove(ndev); | |
167 | err_out: | |
168 | return -ENODEV; | |
169 | } | |
170 | ||
171 | /** | |
172 | * sxgbe_platform_remove | |
173 | * @pdev: platform device pointer | |
174 | * Description: this function calls the main to free the net resources | |
175 | * and calls the platforms hook and release the resources (e.g. mem). | |
176 | */ | |
177 | static int sxgbe_platform_remove(struct platform_device *pdev) | |
178 | { | |
179 | struct net_device *ndev = platform_get_drvdata(pdev); | |
180 | int ret = sxgbe_drv_remove(ndev); | |
181 | ||
182 | return ret; | |
183 | } | |
184 | ||
185 | #ifdef CONFIG_PM | |
186 | static int sxgbe_platform_suspend(struct device *dev) | |
187 | { | |
188 | struct net_device *ndev = dev_get_drvdata(dev); | |
189 | ||
190 | return sxgbe_suspend(ndev); | |
191 | } | |
192 | ||
193 | static int sxgbe_platform_resume(struct device *dev) | |
194 | { | |
195 | struct net_device *ndev = dev_get_drvdata(dev); | |
196 | ||
197 | return sxgbe_resume(ndev); | |
198 | } | |
199 | ||
40b92cad | 200 | static int sxgbe_platform_freeze(struct device *dev) |
1edb9ca6 SR |
201 | { |
202 | struct net_device *ndev = dev_get_drvdata(dev); | |
203 | ||
204 | return sxgbe_freeze(ndev); | |
205 | } | |
206 | ||
40b92cad | 207 | static int sxgbe_platform_restore(struct device *dev) |
1edb9ca6 SR |
208 | { |
209 | struct net_device *ndev = dev_get_drvdata(dev); | |
210 | ||
211 | return sxgbe_restore(ndev); | |
212 | } | |
213 | ||
214 | static const struct dev_pm_ops sxgbe_platform_pm_ops = { | |
215 | .suspend = sxgbe_platform_suspend, | |
216 | .resume = sxgbe_platform_resume, | |
217 | .freeze = sxgbe_platform_freeze, | |
218 | .thaw = sxgbe_platform_restore, | |
219 | .restore = sxgbe_platform_restore, | |
220 | }; | |
221 | #else | |
222 | static const struct dev_pm_ops sxgbe_platform_pm_ops; | |
223 | #endif /* CONFIG_PM */ | |
224 | ||
225 | static const struct of_device_id sxgbe_dt_ids[] = { | |
226 | { .compatible = "samsung,sxgbe-v2.0a"}, | |
227 | { /* sentinel */ } | |
228 | }; | |
229 | MODULE_DEVICE_TABLE(of, sxgbe_dt_ids); | |
230 | ||
40b92cad | 231 | static struct platform_driver sxgbe_platform_driver = { |
1edb9ca6 SR |
232 | .probe = sxgbe_platform_probe, |
233 | .remove = sxgbe_platform_remove, | |
234 | .driver = { | |
235 | .name = SXGBE_RESOURCE_NAME, | |
1edb9ca6 SR |
236 | .pm = &sxgbe_platform_pm_ops, |
237 | .of_match_table = of_match_ptr(sxgbe_dt_ids), | |
238 | }, | |
239 | }; | |
240 | ||
241 | int sxgbe_register_platform(void) | |
242 | { | |
243 | int err; | |
244 | ||
245 | err = platform_driver_register(&sxgbe_platform_driver); | |
246 | if (err) | |
247 | pr_err("failed to register the platform driver\n"); | |
248 | ||
249 | return err; | |
250 | } | |
251 | ||
252 | void sxgbe_unregister_platform(void) | |
253 | { | |
254 | platform_driver_unregister(&sxgbe_platform_driver); | |
255 | } |