aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/enc28j60.c
diff options
context:
space:
mode:
authorJonathan Corbet <corbet@lwn.net>2008-07-14 17:29:34 -0400
committerJonathan Corbet <corbet@lwn.net>2008-07-14 17:29:34 -0400
commit2fceef397f9880b212a74c418290ce69e7ac00eb (patch)
treed9cc09ab992825ef7fede4a688103503e3caf655 /drivers/net/enc28j60.c
parentfeae1ef116ed381625d3731c5ae4f4ebcb3fa302 (diff)
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
Merge commit 'v2.6.26' into bkl-removal
Diffstat (limited to 'drivers/net/enc28j60.c')
-rw-r--r--drivers/net/enc28j60.c87
1 files changed, 60 insertions, 27 deletions
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 46a90e9ec563..c05cb159c772 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -400,26 +400,31 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data)
400 mutex_unlock(&priv->lock); 400 mutex_unlock(&priv->lock);
401} 401}
402 402
403/* 403static unsigned long msec20_to_jiffies;
404 * Wait until the PHY operation is complete. 404
405 */ 405static int poll_ready(struct enc28j60_net *priv, u8 reg, u8 mask, u8 val)
406static int wait_phy_ready(struct enc28j60_net *priv)
407{ 406{
408 unsigned long timeout = jiffies + 20 * HZ / 1000; 407 unsigned long timeout = jiffies + msec20_to_jiffies;
409 int ret = 1;
410 408
411 /* 20 msec timeout read */ 409 /* 20 msec timeout read */
412 while (nolock_regb_read(priv, MISTAT) & MISTAT_BUSY) { 410 while ((nolock_regb_read(priv, reg) & mask) != val) {
413 if (time_after(jiffies, timeout)) { 411 if (time_after(jiffies, timeout)) {
414 if (netif_msg_drv(priv)) 412 if (netif_msg_drv(priv))
415 printk(KERN_DEBUG DRV_NAME 413 dev_dbg(&priv->spi->dev,
416 ": PHY ready timeout!\n"); 414 "reg %02x ready timeout!\n", reg);
417 ret = 0; 415 return -ETIMEDOUT;
418 break;
419 } 416 }
420 cpu_relax(); 417 cpu_relax();
421 } 418 }
422 return ret; 419 return 0;
420}
421
422/*
423 * Wait until the PHY operation is complete.
424 */
425static int wait_phy_ready(struct enc28j60_net *priv)
426{
427 return poll_ready(priv, MISTAT, MISTAT_BUSY, 0) ? 0 : 1;
423} 428}
424 429
425/* 430/*
@@ -594,6 +599,32 @@ static void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
594 nolock_regw_write(priv, ETXNDL, end); 599 nolock_regw_write(priv, ETXNDL, end);
595} 600}
596 601
602/*
603 * Low power mode shrinks power consumption about 100x, so we'd like
604 * the chip to be in that mode whenever it's inactive. (However, we
605 * can't stay in lowpower mode during suspend with WOL active.)
606 */
607static void enc28j60_lowpower(struct enc28j60_net *priv, bool is_low)
608{
609 if (netif_msg_drv(priv))
610 dev_dbg(&priv->spi->dev, "%s power...\n",
611 is_low ? "low" : "high");
612
613 mutex_lock(&priv->lock);
614 if (is_low) {
615 nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
616 poll_ready(priv, ESTAT, ESTAT_RXBUSY, 0);
617 poll_ready(priv, ECON1, ECON1_TXRTS, 0);
618 /* ECON2_VRPS was set during initialization */
619 nolock_reg_bfset(priv, ECON2, ECON2_PWRSV);
620 } else {
621 nolock_reg_bfclr(priv, ECON2, ECON2_PWRSV);
622 poll_ready(priv, ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY);
623 /* caller sets ECON1_RXEN */
624 }
625 mutex_unlock(&priv->lock);
626}
627
597static int enc28j60_hw_init(struct enc28j60_net *priv) 628static int enc28j60_hw_init(struct enc28j60_net *priv)
598{ 629{
599 u8 reg; 630 u8 reg;
@@ -612,8 +643,8 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
612 priv->tx_retry_count = 0; 643 priv->tx_retry_count = 0;
613 priv->max_pk_counter = 0; 644 priv->max_pk_counter = 0;
614 priv->rxfilter = RXFILTER_NORMAL; 645 priv->rxfilter = RXFILTER_NORMAL;
615 /* enable address auto increment */ 646 /* enable address auto increment and voltage regulator powersave */
616 nolock_regb_write(priv, ECON2, ECON2_AUTOINC); 647 nolock_regb_write(priv, ECON2, ECON2_AUTOINC | ECON2_VRPS);
617 648
618 nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT); 649 nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT);
619 nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT); 650 nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT);
@@ -690,7 +721,7 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
690 721
691static void enc28j60_hw_enable(struct enc28j60_net *priv) 722static void enc28j60_hw_enable(struct enc28j60_net *priv)
692{ 723{
693 /* enable interrutps */ 724 /* enable interrupts */
694 if (netif_msg_hw(priv)) 725 if (netif_msg_hw(priv))
695 printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n", 726 printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n",
696 __FUNCTION__); 727 __FUNCTION__);
@@ -726,15 +757,12 @@ enc28j60_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex)
726 int ret = 0; 757 int ret = 0;
727 758
728 if (!priv->hw_enable) { 759 if (!priv->hw_enable) {
729 if (autoneg == AUTONEG_DISABLE && speed == SPEED_10) { 760 /* link is in low power mode now; duplex setting
761 * will take effect on next enc28j60_hw_init().
762 */
763 if (autoneg == AUTONEG_DISABLE && speed == SPEED_10)
730 priv->full_duplex = (duplex == DUPLEX_FULL); 764 priv->full_duplex = (duplex == DUPLEX_FULL);
731 if (!enc28j60_hw_init(priv)) { 765 else {
732 if (netif_msg_drv(priv))
733 dev_err(&ndev->dev,
734 "hw_reset() failed\n");
735 ret = -EINVAL;
736 }
737 } else {
738 if (netif_msg_link(priv)) 766 if (netif_msg_link(priv))
739 dev_warn(&ndev->dev, 767 dev_warn(&ndev->dev,
740 "unsupported link setting\n"); 768 "unsupported link setting\n");
@@ -1307,7 +1335,8 @@ static int enc28j60_net_open(struct net_device *dev)
1307 } 1335 }
1308 return -EADDRNOTAVAIL; 1336 return -EADDRNOTAVAIL;
1309 } 1337 }
1310 /* Reset the hardware here */ 1338 /* Reset the hardware here (and take it out of low power mode) */
1339 enc28j60_lowpower(priv, false);
1311 enc28j60_hw_disable(priv); 1340 enc28j60_hw_disable(priv);
1312 if (!enc28j60_hw_init(priv)) { 1341 if (!enc28j60_hw_init(priv)) {
1313 if (netif_msg_ifup(priv)) 1342 if (netif_msg_ifup(priv))
@@ -1337,6 +1366,7 @@ static int enc28j60_net_close(struct net_device *dev)
1337 printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); 1366 printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
1338 1367
1339 enc28j60_hw_disable(priv); 1368 enc28j60_hw_disable(priv);
1369 enc28j60_lowpower(priv, true);
1340 netif_stop_queue(dev); 1370 netif_stop_queue(dev);
1341 1371
1342 return 0; 1372 return 0;
@@ -1537,6 +1567,8 @@ static int __devinit enc28j60_probe(struct spi_device *spi)
1537 dev->watchdog_timeo = TX_TIMEOUT; 1567 dev->watchdog_timeo = TX_TIMEOUT;
1538 SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops); 1568 SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops);
1539 1569
1570 enc28j60_lowpower(priv, true);
1571
1540 ret = register_netdev(dev); 1572 ret = register_netdev(dev);
1541 if (ret) { 1573 if (ret) {
1542 if (netif_msg_probe(priv)) 1574 if (netif_msg_probe(priv))
@@ -1556,7 +1588,7 @@ error_alloc:
1556 return ret; 1588 return ret;
1557} 1589}
1558 1590
1559static int enc28j60_remove(struct spi_device *spi) 1591static int __devexit enc28j60_remove(struct spi_device *spi)
1560{ 1592{
1561 struct enc28j60_net *priv = dev_get_drvdata(&spi->dev); 1593 struct enc28j60_net *priv = dev_get_drvdata(&spi->dev);
1562 1594
@@ -1573,15 +1605,16 @@ static int enc28j60_remove(struct spi_device *spi)
1573static struct spi_driver enc28j60_driver = { 1605static struct spi_driver enc28j60_driver = {
1574 .driver = { 1606 .driver = {
1575 .name = DRV_NAME, 1607 .name = DRV_NAME,
1576 .bus = &spi_bus_type,
1577 .owner = THIS_MODULE, 1608 .owner = THIS_MODULE,
1578 }, 1609 },
1579 .probe = enc28j60_probe, 1610 .probe = enc28j60_probe,
1580 .remove = __devexit_p(enc28j60_remove), 1611 .remove = __devexit_p(enc28j60_remove),
1581}; 1612};
1582 1613
1583static int __init enc28j60_init(void) 1614static int __init enc28j60_init(void)
1584{ 1615{
1616 msec20_to_jiffies = msecs_to_jiffies(20);
1617
1585 return spi_register_driver(&enc28j60_driver); 1618 return spi_register_driver(&enc28j60_driver);
1586} 1619}
1587 1620