diff options
Diffstat (limited to 'drivers/net/ethernet/smsc/smsc911x.c')
| -rw-r--r-- | drivers/net/ethernet/smsc/smsc911x.c | 127 |
1 files changed, 81 insertions, 46 deletions
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 1466e5d2af4..5e13fa5524a 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -14,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see <http://www.gnu.org/licenses/>. * *************************************************************************** * Rewritten, heavily based on smsc911x simple driver by SMSC. @@ -33,6 +32,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/crc32.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/etherdevice.h> @@ -144,6 +144,9 @@ struct smsc911x_data { /* regulators */ struct regulator_bulk_data supplies[SMSC911X_NUM_SUPPLIES]; + + /* clock */ + struct clk *clk; }; /* Easy access to information */ @@ -253,7 +256,7 @@ smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, } if (pdata->config.flags & SMSC911X_USE_32BIT) { - writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); + iowrite32_rep(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); goto out; } @@ -285,7 +288,7 @@ smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf, } if (pdata->config.flags & SMSC911X_USE_32BIT) { - writesl(pdata->ioaddr + __smsc_shift(pdata, + iowrite32_rep(pdata->ioaddr + __smsc_shift(pdata, TX_DATA_FIFO), buf, wordcount); goto out; } @@ -319,7 +322,7 @@ smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, } if (pdata->config.flags & SMSC911X_USE_32BIT) { - readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); + ioread32_rep(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); goto out; } @@ -351,7 +354,7 @@ smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf, } if (pdata->config.flags & SMSC911X_USE_32BIT) { - readsl(pdata->ioaddr + __smsc_shift(pdata, + ioread32_rep(pdata->ioaddr + __smsc_shift(pdata, RX_DATA_FIFO), buf, wordcount); goto out; } @@ -369,7 +372,7 @@ out: } /* - * enable resources, currently just regulators. + * enable regulator and clock resources. */ static int smsc911x_enable_resources(struct platform_device *pdev) { @@ -382,6 +385,13 @@ static int smsc911x_enable_resources(struct platform_device *pdev) if (ret) netdev_err(ndev, "failed to enable regulators %d\n", ret); + + if (!IS_ERR(pdata->clk)) { + ret = clk_prepare_enable(pdata->clk); + if (ret < 0) + netdev_err(ndev, "failed to enable clock %d\n", ret); + } + return ret; } @@ -396,6 +406,10 @@ static int smsc911x_disable_resources(struct platform_device *pdev) ret = regulator_bulk_disable(ARRAY_SIZE(pdata->supplies), pdata->supplies); + + if (!IS_ERR(pdata->clk)) + clk_disable_unprepare(pdata->clk); + return ret; } @@ -421,6 +435,13 @@ static int smsc911x_request_resources(struct platform_device *pdev) if (ret) netdev_err(ndev, "couldn't get regulators %d\n", ret); + + /* Request clock */ + pdata->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(pdata->clk)) + dev_dbg(&pdev->dev, "couldn't get clock %li\n", + PTR_ERR(pdata->clk)); + return ret; } @@ -436,6 +457,12 @@ static void smsc911x_free_resources(struct platform_device *pdev) /* Free regulators */ regulator_bulk_free(ARRAY_SIZE(pdata->supplies), pdata->supplies); + + /* Free clock */ + if (!IS_ERR(pdata->clk)) { + clk_put(pdata->clk); + pdata->clk = NULL; + } } /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read @@ -997,9 +1024,8 @@ static int smsc911x_mii_probe(struct net_device *dev) SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X", phydev->addr, phydev->phy_id); - ret = phy_connect_direct(dev, phydev, - &smsc911x_phy_adjust_link, 0, - pdata->config.phy_interface); + ret = phy_connect_direct(dev, phydev, &smsc911x_phy_adjust_link, + pdata->config.phy_interface); if (ret) { netdev_err(dev, "Could not attach to PHY\n"); @@ -1031,8 +1057,8 @@ static int smsc911x_mii_probe(struct net_device *dev) return 0; } -static int __devinit smsc911x_mii_init(struct platform_device *pdev, - struct net_device *dev) +static int smsc911x_mii_init(struct platform_device *pdev, + struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); int err = -ENXIO, i; @@ -1442,6 +1468,14 @@ smsc911x_set_hw_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6]) smsc911x_mac_write(pdata, ADDRL, mac_low32); } +static void smsc911x_disable_irq_chip(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + smsc911x_reg_write(pdata, INT_EN, 0); + smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); +} + static int smsc911x_open(struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); @@ -1455,11 +1489,6 @@ static int smsc911x_open(struct net_device *dev) return -EAGAIN; } - if (!is_valid_ether_addr(dev->dev_addr)) { - SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address"); - return -EADDRNOTAVAIL; - } - /* Reset the LAN911x */ if (smsc911x_soft_reset(pdata)) { SMSC_WARN(pdata, hw, "soft reset failed"); @@ -1494,8 +1523,7 @@ static int smsc911x_open(struct net_device *dev) spin_unlock_irq(&pdata->mac_lock); /* Initialise irqs, but leave all sources disabled */ - smsc911x_reg_write(pdata, INT_EN, 0); - smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); + smsc911x_disable_irq_chip(dev); /* Set interrupt deassertion to 100uS */ intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); @@ -1645,7 +1673,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); freespace -= (skb->len + 32); skb_tx_timestamp(skb); - dev_kfree_skb(skb); + dev_consume_skb_any(skb); if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30)) smsc911x_tx_update_txcounters(dev); @@ -1829,7 +1857,6 @@ static int smsc911x_set_mac_address(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - dev->addr_assign_type &= ~NET_ADDR_RANDOM; memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); spin_lock_irq(&pdata->mac_lock); @@ -2085,7 +2112,7 @@ static const struct net_device_ops smsc911x_netdev_ops = { }; /* copies the current mac address from hardware to dev->dev_addr */ -static void __devinit smsc911x_read_mac_address(struct net_device *dev) +static void smsc911x_read_mac_address(struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH); @@ -2100,10 +2127,10 @@ static void __devinit smsc911x_read_mac_address(struct net_device *dev) } /* Initializing private device structures, only called from probe */ -static int __devinit smsc911x_init(struct net_device *dev) +static int smsc911x_init(struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int byte_test; + unsigned int byte_test, mask; unsigned int to = 100; SMSC_TRACE(pdata, probe, "Driver Parameters:"); @@ -2115,7 +2142,7 @@ static int __devinit smsc911x_init(struct net_device *dev) spin_lock_init(&pdata->dev_lock); spin_lock_init(&pdata->mac_lock); - if (pdata->ioaddr == 0) { + if (pdata->ioaddr == NULL) { SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000"); return -ENODEV; } @@ -2123,11 +2150,24 @@ static int __devinit smsc911x_init(struct net_device *dev) /* * poll the READY bit in PMT_CTRL. Any other access to the device is * forbidden while this bit isn't set. Try for 100ms + * + * Note that this test is done before the WORD_SWAP register is + * programmed. So in some configurations the READY bit is at 16 before + * WORD_SWAP is written to. This issue is worked around by waiting + * until either bit 0 or bit 16 gets set in PMT_CTRL. + * + * SMSC has confirmed that checking bit 16 (marked as reserved in + * the datasheet) is fine since these bits "will either never be set + * or can only go high after READY does (so also indicate the device + * is ready)". */ - while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) + + mask = PMT_CTRL_READY_ | swahw32(PMT_CTRL_READY_); + while (!(smsc911x_reg_read(pdata, PMT_CTRL) & mask) && --to) udelay(1000); + if (to == 0) { - pr_err("Device not READY in 100ms aborting\n"); + netdev_err(dev, "Device not READY in 100ms aborting\n"); return -ENODEV; } @@ -2215,9 +2255,6 @@ static int __devinit smsc911x_init(struct net_device *dev) if (smsc911x_soft_reset(pdata)) return -ENODEV; - /* Disable all interrupt sources until we bring the device up */ - smsc911x_reg_write(pdata, INT_EN, 0); - ether_setup(dev); dev->flags |= IFF_MULTICAST; netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT); @@ -2227,7 +2264,7 @@ static int __devinit smsc911x_init(struct net_device *dev) return 0; } -static int __devexit smsc911x_drv_remove(struct platform_device *pdev) +static int smsc911x_drv_remove(struct platform_device *pdev) { struct net_device *dev; struct smsc911x_data *pdata; @@ -2247,7 +2284,6 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) mdiobus_unregister(pdata->mii_bus); mdiobus_free(pdata->mii_bus); - platform_set_drvdata(pdev, NULL); unregister_netdev(dev); free_irq(dev->irq, dev); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -2284,9 +2320,8 @@ static const struct smsc911x_ops shifted_smsc911x_ops = { }; #ifdef CONFIG_OF -static int __devinit smsc911x_probe_config_dt( - struct smsc911x_platform_config *config, - struct device_node *np) +static int smsc911x_probe_config_dt(struct smsc911x_platform_config *config, + struct device_node *np) { const char *mac; u32 width = 0; @@ -2334,19 +2369,17 @@ static inline int smsc911x_probe_config_dt( } #endif /* CONFIG_OF */ -static int __devinit smsc911x_drv_probe(struct platform_device *pdev) +static int smsc911x_drv_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct net_device *dev; struct smsc911x_data *pdata; - struct smsc911x_platform_config *config = pdev->dev.platform_data; + struct smsc911x_platform_config *config = dev_get_platdata(&pdev->dev); struct resource *res, *irq_res; unsigned int intcfg = 0; int res_size, irq_flags; int retval; - pr_info("Driver version %s\n", SMSC_DRV_VERSION); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smsc911x-memory"); if (!res) @@ -2434,8 +2467,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) smsc911x_reg_write(pdata, INT_CFG, intcfg); /* Ensure interrupts are globally disabled before connecting ISR */ - smsc911x_reg_write(pdata, INT_EN, 0); - smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); + smsc911x_disable_irq_chip(dev); retval = request_irq(dev->irq, smsc911x_irqhandler, irq_flags | IRQF_SHARED, dev->name, dev); @@ -2445,6 +2477,8 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) goto out_disable_resources; } + netif_carrier_off(dev); + retval = register_netdev(dev); if (retval) { SMSC_WARN(pdata, probe, "Error %i registering device", retval); @@ -2468,7 +2502,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) SMSC_TRACE(pdata, probe, "MAC Address is specified by configuration"); } else if (is_valid_ether_addr(pdata->config.mac)) { - memcpy(dev->dev_addr, pdata->config.mac, 6); + memcpy(dev->dev_addr, pdata->config.mac, ETH_ALEN); SMSC_TRACE(pdata, probe, "MAC Address specified by platform data"); } else { @@ -2485,7 +2519,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) eth_hw_addr_random(dev); smsc911x_set_hw_mac_address(pdata, dev->dev_addr); SMSC_TRACE(pdata, probe, - "MAC Address is set to random_ether_addr"); + "MAC Address is set to eth_random_addr"); } } @@ -2504,7 +2538,6 @@ out_disable_resources: out_enable_resources_fail: smsc911x_free_resources(pdev); out_request_resources_fail: - platform_set_drvdata(pdev, NULL); iounmap(pdata->ioaddr); free_netdev(dev); out_release_io_1: @@ -2565,20 +2598,22 @@ static const struct dev_pm_ops smsc911x_pm_ops = { #define SMSC911X_PM_OPS NULL #endif +#ifdef CONFIG_OF static const struct of_device_id smsc911x_dt_ids[] = { { .compatible = "smsc,lan9115", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, smsc911x_dt_ids); +#endif static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, - .remove = __devexit_p(smsc911x_drv_remove), + .remove = smsc911x_drv_remove, .driver = { .name = SMSC_CHIPNAME, .owner = THIS_MODULE, .pm = SMSC911X_PM_OPS, - .of_match_table = smsc911x_dt_ids, + .of_match_table = of_match_ptr(smsc911x_dt_ids), }, }; |
