@@ -400,26 +400,31 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data)
400
400
mutex_unlock (& priv -> lock );
401
401
}
402
402
403
- /*
404
- * Wait until the PHY operation is complete.
405
- */
406
- static int wait_phy_ready (struct enc28j60_net * priv )
403
+ static unsigned long msec20_to_jiffies ;
404
+
405
+ static int poll_ready (struct enc28j60_net * priv , u8 reg , u8 mask , u8 val )
407
406
{
408
- unsigned long timeout = jiffies + 20 * HZ / 1000 ;
409
- int ret = 1 ;
407
+ unsigned long timeout = jiffies + msec20_to_jiffies ;
410
408
411
409
/* 20 msec timeout read */
412
- while (nolock_regb_read (priv , MISTAT ) & MISTAT_BUSY ) {
410
+ while (( nolock_regb_read (priv , reg ) & mask ) != val ) {
413
411
if (time_after (jiffies , timeout )) {
414
412
if (netif_msg_drv (priv ))
415
- printk (KERN_DEBUG DRV_NAME
416
- ": PHY ready timeout!\n" );
417
- ret = 0 ;
418
- break ;
413
+ dev_dbg (& priv -> spi -> dev ,
414
+ "reg %02x ready timeout!\n" , reg );
415
+ return - ETIMEDOUT ;
419
416
}
420
417
cpu_relax ();
421
418
}
422
- return ret ;
419
+ return 0 ;
420
+ }
421
+
422
+ /*
423
+ * Wait until the PHY operation is complete.
424
+ */
425
+ static 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
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
+ */
607
+ static 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
+
597
628
static int enc28j60_hw_init (struct enc28j60_net * priv )
598
629
{
599
630
u8 reg ;
@@ -612,8 +643,8 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
612
643
priv -> tx_retry_count = 0 ;
613
644
priv -> max_pk_counter = 0 ;
614
645
priv -> rxfilter = RXFILTER_NORMAL ;
615
- /* enable address auto increment */
616
- nolock_regb_write (priv , ECON2 , ECON2_AUTOINC );
646
+ /* enable address auto increment and voltage regulator powersave */
647
+ nolock_regb_write (priv , ECON2 , ECON2_AUTOINC | ECON2_VRPS );
617
648
618
649
nolock_rxfifo_init (priv , RXSTART_INIT , RXEND_INIT );
619
650
nolock_txfifo_init (priv , TXSTART_INIT , TXEND_INIT );
@@ -690,7 +721,7 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
690
721
691
722
static void enc28j60_hw_enable (struct enc28j60_net * priv )
692
723
{
693
- /* enable interrutps */
724
+ /* enable interrupts */
694
725
if (netif_msg_hw (priv ))
695
726
printk (KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n" ,
696
727
__FUNCTION__ );
@@ -726,15 +757,12 @@ enc28j60_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex)
726
757
int ret = 0 ;
727
758
728
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
764
priv -> full_duplex = (duplex == DUPLEX_FULL );
731
- if (!enc28j60_hw_init (priv )) {
732
- if (netif_msg_drv (priv ))
733
- dev_err (& ndev -> dev ,
734
- "hw_reset() failed\n" );
735
- ret = - EINVAL ;
736
- }
737
- } else {
765
+ else {
738
766
if (netif_msg_link (priv ))
739
767
dev_warn (& ndev -> dev ,
740
768
"unsupported link setting\n" );
@@ -1307,7 +1335,8 @@ static int enc28j60_net_open(struct net_device *dev)
1307
1335
}
1308
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
1340
enc28j60_hw_disable (priv );
1312
1341
if (!enc28j60_hw_init (priv )) {
1313
1342
if (netif_msg_ifup (priv ))
@@ -1337,6 +1366,7 @@ static int enc28j60_net_close(struct net_device *dev)
1337
1366
printk (KERN_DEBUG DRV_NAME ": %s() enter\n" , __FUNCTION__ );
1338
1367
1339
1368
enc28j60_hw_disable (priv );
1369
+ enc28j60_lowpower (priv , true);
1340
1370
netif_stop_queue (dev );
1341
1371
1342
1372
return 0 ;
@@ -1537,6 +1567,8 @@ static int __devinit enc28j60_probe(struct spi_device *spi)
1537
1567
dev -> watchdog_timeo = TX_TIMEOUT ;
1538
1568
SET_ETHTOOL_OPS (dev , & enc28j60_ethtool_ops );
1539
1569
1570
+ enc28j60_lowpower (priv , true);
1571
+
1540
1572
ret = register_netdev (dev );
1541
1573
if (ret ) {
1542
1574
if (netif_msg_probe (priv ))
@@ -1556,7 +1588,7 @@ static int __devinit enc28j60_probe(struct spi_device *spi)
1556
1588
return ret ;
1557
1589
}
1558
1590
1559
- static int enc28j60_remove (struct spi_device * spi )
1591
+ static int __devexit enc28j60_remove (struct spi_device * spi )
1560
1592
{
1561
1593
struct enc28j60_net * priv = dev_get_drvdata (& spi -> dev );
1562
1594
@@ -1573,15 +1605,16 @@ static int enc28j60_remove(struct spi_device *spi)
1573
1605
static struct spi_driver enc28j60_driver = {
1574
1606
.driver = {
1575
1607
.name = DRV_NAME ,
1576
- .bus = & spi_bus_type ,
1577
1608
.owner = THIS_MODULE ,
1578
- },
1609
+ },
1579
1610
.probe = enc28j60_probe ,
1580
1611
.remove = __devexit_p (enc28j60_remove ),
1581
1612
};
1582
1613
1583
1614
static int __init enc28j60_init (void )
1584
1615
{
1616
+ msec20_to_jiffies = msecs_to_jiffies (20 );
1617
+
1585
1618
return spi_register_driver (& enc28j60_driver );
1586
1619
}
1587
1620
0 commit comments