diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/smsc/smsc911x.c | 111 |
1 files changed, 100 insertions, 11 deletions
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 8843071fe987..06d0df61bee6 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/module.h> | 44 | #include <linux/module.h> |
45 | #include <linux/netdevice.h> | 45 | #include <linux/netdevice.h> |
46 | #include <linux/platform_device.h> | 46 | #include <linux/platform_device.h> |
47 | #include <linux/regulator/consumer.h> | ||
47 | #include <linux/sched.h> | 48 | #include <linux/sched.h> |
48 | #include <linux/timer.h> | 49 | #include <linux/timer.h> |
49 | #include <linux/bug.h> | 50 | #include <linux/bug.h> |
@@ -88,6 +89,8 @@ struct smsc911x_ops { | |||
88 | unsigned int *buf, unsigned int wordcount); | 89 | unsigned int *buf, unsigned int wordcount); |
89 | }; | 90 | }; |
90 | 91 | ||
92 | #define SMSC911X_NUM_SUPPLIES 2 | ||
93 | |||
91 | struct smsc911x_data { | 94 | struct smsc911x_data { |
92 | void __iomem *ioaddr; | 95 | void __iomem *ioaddr; |
93 | 96 | ||
@@ -138,6 +141,9 @@ struct smsc911x_data { | |||
138 | 141 | ||
139 | /* register access functions */ | 142 | /* register access functions */ |
140 | const struct smsc911x_ops *ops; | 143 | const struct smsc911x_ops *ops; |
144 | |||
145 | /* regulators */ | ||
146 | struct regulator_bulk_data supplies[SMSC911X_NUM_SUPPLIES]; | ||
141 | }; | 147 | }; |
142 | 148 | ||
143 | /* Easy access to information */ | 149 | /* Easy access to information */ |
@@ -362,6 +368,76 @@ out: | |||
362 | spin_unlock_irqrestore(&pdata->dev_lock, flags); | 368 | spin_unlock_irqrestore(&pdata->dev_lock, flags); |
363 | } | 369 | } |
364 | 370 | ||
371 | /* | ||
372 | * enable resources, currently just regulators. | ||
373 | */ | ||
374 | static int smsc911x_enable_resources(struct platform_device *pdev) | ||
375 | { | ||
376 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
377 | struct smsc911x_data *pdata = netdev_priv(ndev); | ||
378 | int ret = 0; | ||
379 | |||
380 | ret = regulator_bulk_enable(ARRAY_SIZE(pdata->supplies), | ||
381 | pdata->supplies); | ||
382 | if (ret) | ||
383 | netdev_err(ndev, "failed to enable regulators %d\n", | ||
384 | ret); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * disable resources, currently just regulators. | ||
390 | */ | ||
391 | static int smsc911x_disable_resources(struct platform_device *pdev) | ||
392 | { | ||
393 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
394 | struct smsc911x_data *pdata = netdev_priv(ndev); | ||
395 | int ret = 0; | ||
396 | |||
397 | ret = regulator_bulk_disable(ARRAY_SIZE(pdata->supplies), | ||
398 | pdata->supplies); | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Request resources, currently just regulators. | ||
404 | * | ||
405 | * The SMSC911x has two power pins: vddvario and vdd33a, in designs where | ||
406 | * these are not always-on we need to request regulators to be turned on | ||
407 | * before we can try to access the device registers. | ||
408 | */ | ||
409 | static int smsc911x_request_resources(struct platform_device *pdev) | ||
410 | { | ||
411 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
412 | struct smsc911x_data *pdata = netdev_priv(ndev); | ||
413 | int ret = 0; | ||
414 | |||
415 | /* Request regulators */ | ||
416 | pdata->supplies[0].supply = "vdd33a"; | ||
417 | pdata->supplies[1].supply = "vddvario"; | ||
418 | ret = regulator_bulk_get(&pdev->dev, | ||
419 | ARRAY_SIZE(pdata->supplies), | ||
420 | pdata->supplies); | ||
421 | if (ret) | ||
422 | netdev_err(ndev, "couldn't get regulators %d\n", | ||
423 | ret); | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * Free resources, currently just regulators. | ||
429 | * | ||
430 | */ | ||
431 | static void smsc911x_free_resources(struct platform_device *pdev) | ||
432 | { | ||
433 | struct net_device *ndev = platform_get_drvdata(pdev); | ||
434 | struct smsc911x_data *pdata = netdev_priv(ndev); | ||
435 | |||
436 | /* Free regulators */ | ||
437 | regulator_bulk_free(ARRAY_SIZE(pdata->supplies), | ||
438 | pdata->supplies); | ||
439 | } | ||
440 | |||
365 | /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read | 441 | /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read |
366 | * and smsc911x_mac_write, so assumes mac_lock is held */ | 442 | * and smsc911x_mac_write, so assumes mac_lock is held */ |
367 | static int smsc911x_mac_complete(struct smsc911x_data *pdata) | 443 | static int smsc911x_mac_complete(struct smsc911x_data *pdata) |
@@ -2092,6 +2168,9 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) | |||
2092 | 2168 | ||
2093 | iounmap(pdata->ioaddr); | 2169 | iounmap(pdata->ioaddr); |
2094 | 2170 | ||
2171 | (void)smsc911x_disable_resources(pdev); | ||
2172 | smsc911x_free_resources(pdev); | ||
2173 | |||
2095 | free_netdev(dev); | 2174 | free_netdev(dev); |
2096 | 2175 | ||
2097 | return 0; | 2176 | return 0; |
@@ -2218,10 +2297,20 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
2218 | pdata->dev = dev; | 2297 | pdata->dev = dev; |
2219 | pdata->msg_enable = ((1 << debug) - 1); | 2298 | pdata->msg_enable = ((1 << debug) - 1); |
2220 | 2299 | ||
2300 | platform_set_drvdata(pdev, dev); | ||
2301 | |||
2302 | retval = smsc911x_request_resources(pdev); | ||
2303 | if (retval) | ||
2304 | goto out_return_resources; | ||
2305 | |||
2306 | retval = smsc911x_enable_resources(pdev); | ||
2307 | if (retval) | ||
2308 | goto out_disable_resources; | ||
2309 | |||
2221 | if (pdata->ioaddr == NULL) { | 2310 | if (pdata->ioaddr == NULL) { |
2222 | SMSC_WARN(pdata, probe, "Error smsc911x base address invalid"); | 2311 | SMSC_WARN(pdata, probe, "Error smsc911x base address invalid"); |
2223 | retval = -ENOMEM; | 2312 | retval = -ENOMEM; |
2224 | goto out_free_netdev_2; | 2313 | goto out_disable_resources; |
2225 | } | 2314 | } |
2226 | 2315 | ||
2227 | retval = smsc911x_probe_config_dt(&pdata->config, np); | 2316 | retval = smsc911x_probe_config_dt(&pdata->config, np); |
@@ -2233,7 +2322,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
2233 | 2322 | ||
2234 | if (retval) { | 2323 | if (retval) { |
2235 | SMSC_WARN(pdata, probe, "Error smsc911x config not found"); | 2324 | SMSC_WARN(pdata, probe, "Error smsc911x config not found"); |
2236 | goto out_unmap_io_3; | 2325 | goto out_disable_resources; |
2237 | } | 2326 | } |
2238 | 2327 | ||
2239 | /* assume standard, non-shifted, access to HW registers */ | 2328 | /* assume standard, non-shifted, access to HW registers */ |
@@ -2244,7 +2333,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
2244 | 2333 | ||
2245 | retval = smsc911x_init(dev); | 2334 | retval = smsc911x_init(dev); |
2246 | if (retval < 0) | 2335 | if (retval < 0) |
2247 | goto out_unmap_io_3; | 2336 | goto out_disable_resources; |
2248 | 2337 | ||
2249 | /* configure irq polarity and type before connecting isr */ | 2338 | /* configure irq polarity and type before connecting isr */ |
2250 | if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH) | 2339 | if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH) |
@@ -2264,15 +2353,13 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
2264 | if (retval) { | 2353 | if (retval) { |
2265 | SMSC_WARN(pdata, probe, | 2354 | SMSC_WARN(pdata, probe, |
2266 | "Unable to claim requested irq: %d", dev->irq); | 2355 | "Unable to claim requested irq: %d", dev->irq); |
2267 | goto out_unmap_io_3; | 2356 | goto out_free_irq; |
2268 | } | 2357 | } |
2269 | 2358 | ||
2270 | platform_set_drvdata(pdev, dev); | ||
2271 | |||
2272 | retval = register_netdev(dev); | 2359 | retval = register_netdev(dev); |
2273 | if (retval) { | 2360 | if (retval) { |
2274 | SMSC_WARN(pdata, probe, "Error %i registering device", retval); | 2361 | SMSC_WARN(pdata, probe, "Error %i registering device", retval); |
2275 | goto out_unset_drvdata_4; | 2362 | goto out_free_irq; |
2276 | } else { | 2363 | } else { |
2277 | SMSC_TRACE(pdata, probe, | 2364 | SMSC_TRACE(pdata, probe, |
2278 | "Network interface: \"%s\"", dev->name); | 2365 | "Network interface: \"%s\"", dev->name); |
@@ -2321,12 +2408,14 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) | |||
2321 | 2408 | ||
2322 | out_unregister_netdev_5: | 2409 | out_unregister_netdev_5: |
2323 | unregister_netdev(dev); | 2410 | unregister_netdev(dev); |
2324 | out_unset_drvdata_4: | 2411 | out_free_irq: |
2325 | platform_set_drvdata(pdev, NULL); | ||
2326 | free_irq(dev->irq, dev); | 2412 | free_irq(dev->irq, dev); |
2327 | out_unmap_io_3: | 2413 | out_disable_resources: |
2414 | (void)smsc911x_disable_resources(pdev); | ||
2415 | out_return_resources: | ||
2416 | smsc911x_free_resources(pdev); | ||
2417 | platform_set_drvdata(pdev, NULL); | ||
2328 | iounmap(pdata->ioaddr); | 2418 | iounmap(pdata->ioaddr); |
2329 | out_free_netdev_2: | ||
2330 | free_netdev(dev); | 2419 | free_netdev(dev); |
2331 | out_release_io_1: | 2420 | out_release_io_1: |
2332 | release_mem_region(res->start, resource_size(res)); | 2421 | release_mem_region(res->start, resource_size(res)); |