Commit d9fe64e5 authored by Robert Foss's avatar Robert Foss Committed by David S. Miller

net: asix: Add in_pm parameter

From: Freddy Xin <freddy@asix.com.tw>

In order to R/W registers in suspend/resume functions, in_pm flags are
added to some functions to determine whether the nopm version of usb
functions is called.

Save BMCR and ANAR PHY registers in suspend function and restore them
in resume function.

Reset HW in resume function to ensure the PHY works correctly.
Signed-off-by: default avatarFreddy Xin <freddy@asix.com.tw>
Signed-off-by: default avatarRobert Foss <robert.foss@collabora.com>
Tested-by: default avatarRobert Foss <robert.foss@collabora.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c7735f1b
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define AX_CMD_SET_SW_MII 0x06 #define AX_CMD_SET_SW_MII 0x06
#define AX_CMD_READ_MII_REG 0x07 #define AX_CMD_READ_MII_REG 0x07
#define AX_CMD_WRITE_MII_REG 0x08 #define AX_CMD_WRITE_MII_REG 0x08
#define AX_CMD_STATMNGSTS_REG 0x09
#define AX_CMD_SET_HW_MII 0x0a #define AX_CMD_SET_HW_MII 0x0a
#define AX_CMD_READ_EEPROM 0x0b #define AX_CMD_READ_EEPROM 0x0b
#define AX_CMD_WRITE_EEPROM 0x0c #define AX_CMD_WRITE_EEPROM 0x0c
...@@ -71,6 +72,17 @@ ...@@ -71,6 +72,17 @@
#define AX_CMD_SW_RESET 0x20 #define AX_CMD_SW_RESET 0x20
#define AX_CMD_SW_PHY_STATUS 0x21 #define AX_CMD_SW_PHY_STATUS 0x21
#define AX_CMD_SW_PHY_SELECT 0x22 #define AX_CMD_SW_PHY_SELECT 0x22
#define AX_QCTCTRL 0x2A
#define AX_CHIPCODE_MASK 0x70
#define AX_AX88772_CHIPCODE 0x00
#define AX_AX88772A_CHIPCODE 0x10
#define AX_AX88772B_CHIPCODE 0x20
#define AX_HOST_EN 0x01
#define AX_PHYSEL_PSEL 0x01
#define AX_PHYSEL_SSMII 0
#define AX_PHYSEL_SSEN 0x10
#define AX_PHY_SELECT_MASK (BIT(3) | BIT(2)) #define AX_PHY_SELECT_MASK (BIT(3) | BIT(2))
#define AX_PHY_SELECT_INTERNAL 0 #define AX_PHY_SELECT_INTERNAL 0
...@@ -173,6 +185,10 @@ struct asix_rx_fixup_info { ...@@ -173,6 +185,10 @@ struct asix_rx_fixup_info {
}; };
struct asix_common_private { struct asix_common_private {
void (*resume)(struct usbnet *dev);
void (*suspend)(struct usbnet *dev);
u16 presvd_phy_advertise;
u16 presvd_phy_bmcr;
struct asix_rx_fixup_info rx_fixup_info; struct asix_rx_fixup_info rx_fixup_info;
}; };
...@@ -182,10 +198,10 @@ extern const struct driver_info ax88172a_info; ...@@ -182,10 +198,10 @@ extern const struct driver_info ax88172a_info;
#define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */ #define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */
int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data); u16 size, void *data, int in_pm);
int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data); u16 size, void *data, int in_pm);
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
u16 index, u16 size, void *data); u16 index, u16 size, void *data);
...@@ -197,27 +213,31 @@ int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb); ...@@ -197,27 +213,31 @@ int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb);
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
gfp_t flags); gfp_t flags);
int asix_set_sw_mii(struct usbnet *dev); int asix_set_sw_mii(struct usbnet *dev, int in_pm);
int asix_set_hw_mii(struct usbnet *dev); int asix_set_hw_mii(struct usbnet *dev, int in_pm);
int asix_read_phy_addr(struct usbnet *dev, int internal); int asix_read_phy_addr(struct usbnet *dev, int internal);
int asix_get_phy_addr(struct usbnet *dev); int asix_get_phy_addr(struct usbnet *dev);
int asix_sw_reset(struct usbnet *dev, u8 flags); int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm);
u16 asix_read_rx_ctl(struct usbnet *dev); u16 asix_read_rx_ctl(struct usbnet *dev, int in_pm);
int asix_write_rx_ctl(struct usbnet *dev, u16 mode); int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm);
u16 asix_read_medium_status(struct usbnet *dev); u16 asix_read_medium_status(struct usbnet *dev, int in_pm);
int asix_write_medium_mode(struct usbnet *dev, u16 mode); int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm);
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep); int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm);
void asix_set_multicast(struct net_device *net); void asix_set_multicast(struct net_device *net);
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc); int asix_mdio_read(struct net_device *netdev, int phy_id, int loc);
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val); void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val);
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc);
void asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc,
int val);
void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo);
int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo);
......
...@@ -22,24 +22,49 @@ ...@@ -22,24 +22,49 @@
#include "asix.h" #include "asix.h"
int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data) u16 size, void *data, int in_pm)
{ {
int ret; int ret;
ret = usbnet_read_cmd(dev, cmd, int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
BUG_ON(!dev);
if (!in_pm)
fn = usbnet_read_cmd;
else
fn = usbnet_read_cmd_nopm;
ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, data, size); value, index, data, size);
if (ret != size && ret >= 0) if (unlikely(ret < 0))
return -EINVAL; netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n",
index, ret);
return ret; return ret;
} }
int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data) u16 size, void *data, int in_pm)
{ {
return usbnet_write_cmd(dev, cmd, int ret;
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
BUG_ON(!dev);
if (!in_pm)
fn = usbnet_write_cmd;
else
fn = usbnet_write_cmd_nopm;
ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, data, size); value, index, data, size);
if (unlikely(ret < 0))
netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n",
index, ret);
return ret;
} }
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
...@@ -225,19 +250,20 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, ...@@ -225,19 +250,20 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
return skb; return skb;
} }
int asix_set_sw_mii(struct usbnet *dev) int asix_set_sw_mii(struct usbnet *dev, int in_pm)
{ {
int ret; int ret;
ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL, in_pm);
if (ret < 0) if (ret < 0)
netdev_err(dev->net, "Failed to enable software MII access\n"); netdev_err(dev->net, "Failed to enable software MII access\n");
return ret; return ret;
} }
int asix_set_hw_mii(struct usbnet *dev) int asix_set_hw_mii(struct usbnet *dev, int in_pm)
{ {
int ret; int ret;
ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL, in_pm);
if (ret < 0) if (ret < 0)
netdev_err(dev->net, "Failed to enable hardware MII access\n"); netdev_err(dev->net, "Failed to enable hardware MII access\n");
return ret; return ret;
...@@ -247,7 +273,7 @@ int asix_read_phy_addr(struct usbnet *dev, int internal) ...@@ -247,7 +273,7 @@ int asix_read_phy_addr(struct usbnet *dev, int internal)
{ {
int offset = (internal ? 1 : 0); int offset = (internal ? 1 : 0);
u8 buf[2]; u8 buf[2];
int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf, 0);
netdev_dbg(dev->net, "asix_get_phy_addr()\n"); netdev_dbg(dev->net, "asix_get_phy_addr()\n");
...@@ -270,21 +296,21 @@ int asix_get_phy_addr(struct usbnet *dev) ...@@ -270,21 +296,21 @@ int asix_get_phy_addr(struct usbnet *dev)
} }
int asix_sw_reset(struct usbnet *dev, u8 flags) int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm)
{ {
int ret; int ret;
ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL, in_pm);
if (ret < 0) if (ret < 0)
netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
return ret; return ret;
} }
u16 asix_read_rx_ctl(struct usbnet *dev) u16 asix_read_rx_ctl(struct usbnet *dev, int in_pm)
{ {
__le16 v; __le16 v;
int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v, in_pm);
if (ret < 0) { if (ret < 0) {
netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
...@@ -295,12 +321,12 @@ u16 asix_read_rx_ctl(struct usbnet *dev) ...@@ -295,12 +321,12 @@ u16 asix_read_rx_ctl(struct usbnet *dev)
return ret; return ret;
} }
int asix_write_rx_ctl(struct usbnet *dev, u16 mode) int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm)
{ {
int ret; int ret;
netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL, in_pm);
if (ret < 0) if (ret < 0)
netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
mode, ret); mode, ret);
...@@ -308,10 +334,11 @@ int asix_write_rx_ctl(struct usbnet *dev, u16 mode) ...@@ -308,10 +334,11 @@ int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
return ret; return ret;
} }
u16 asix_read_medium_status(struct usbnet *dev) u16 asix_read_medium_status(struct usbnet *dev, int in_pm)
{ {
__le16 v; __le16 v;
int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS,
0, 0, 2, &v, in_pm);
if (ret < 0) { if (ret < 0) {
netdev_err(dev->net, "Error reading Medium Status register: %02x\n", netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
...@@ -323,12 +350,13 @@ u16 asix_read_medium_status(struct usbnet *dev) ...@@ -323,12 +350,13 @@ u16 asix_read_medium_status(struct usbnet *dev)
} }
int asix_write_medium_mode(struct usbnet *dev, u16 mode) int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm)
{ {
int ret; int ret;
netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
mode, 0, 0, NULL, in_pm);
if (ret < 0) if (ret < 0)
netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
mode, ret); mode, ret);
...@@ -336,12 +364,12 @@ int asix_write_medium_mode(struct usbnet *dev, u16 mode) ...@@ -336,12 +364,12 @@ int asix_write_medium_mode(struct usbnet *dev, u16 mode)
return ret; return ret;
} }
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm)
{ {
int ret; int ret;
netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL, in_pm);
if (ret < 0) if (ret < 0)
netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
value, ret); value, ret);
...@@ -398,12 +426,19 @@ int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) ...@@ -398,12 +426,19 @@ int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
{ {
struct usbnet *dev = netdev_priv(netdev); struct usbnet *dev = netdev_priv(netdev);
__le16 res; __le16 res;
u8 smsr;
int i = 0;
mutex_lock(&dev->phy_mutex); mutex_lock(&dev->phy_mutex);
asix_set_sw_mii(dev); do {
asix_set_sw_mii(dev, 0);
usleep_range(1000, 1100);
asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 0);
} while (!(smsr & AX_HOST_EN) && (i++ < 30));
asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
(__u16)loc, 2, &res); (__u16)loc, 2, &res, 0);
asix_set_hw_mii(dev); asix_set_hw_mii(dev, 0);
mutex_unlock(&dev->phy_mutex); mutex_unlock(&dev->phy_mutex);
netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
...@@ -416,13 +451,71 @@ void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) ...@@ -416,13 +451,71 @@ void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
{ {
struct usbnet *dev = netdev_priv(netdev); struct usbnet *dev = netdev_priv(netdev);
__le16 res = cpu_to_le16(val); __le16 res = cpu_to_le16(val);
u8 smsr;
int i = 0;
netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
phy_id, loc, val); phy_id, loc, val);
mutex_lock(&dev->phy_mutex);
do {
asix_set_sw_mii(dev, 0);
usleep_range(1000, 1100);
asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 0);
} while (!(smsr & AX_HOST_EN) && (i++ < 30));
asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
(__u16)loc, 2, &res, 0);
asix_set_hw_mii(dev, 0);
mutex_unlock(&dev->phy_mutex);
}
int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc)
{
struct usbnet *dev = netdev_priv(netdev);
__le16 res;
u8 smsr;
int i = 0;
mutex_lock(&dev->phy_mutex);
do {
asix_set_sw_mii(dev, 1);
usleep_range(1000, 1100);
asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 1);
} while (!(smsr & AX_HOST_EN) && (i++ < 30));
asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
(__u16)loc, 2, &res, 1);
asix_set_hw_mii(dev, 1);
mutex_unlock(&dev->phy_mutex);
netdev_dbg(dev->net, "asix_mdio_read_nopm() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
phy_id, loc, le16_to_cpu(res));
return le16_to_cpu(res);
}
void
asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc, int val)
{
struct usbnet *dev = netdev_priv(netdev);
__le16 res = cpu_to_le16(val);
u8 smsr;
int i = 0;
netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
phy_id, loc, val);
mutex_lock(&dev->phy_mutex); mutex_lock(&dev->phy_mutex);
asix_set_sw_mii(dev); do {
asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); asix_set_sw_mii(dev, 1);
asix_set_hw_mii(dev); usleep_range(1000, 1100);
asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 1);
} while (!(smsr & AX_HOST_EN) && (i++ < 30));
asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
(__u16)loc, 2, &res, 1);
asix_set_hw_mii(dev, 1);
mutex_unlock(&dev->phy_mutex); mutex_unlock(&dev->phy_mutex);
} }
...@@ -431,7 +524,8 @@ void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) ...@@ -431,7 +524,8 @@ void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
struct usbnet *dev = netdev_priv(net); struct usbnet *dev = netdev_priv(net);
u8 opt; u8 opt;
if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE,
0, 0, 1, &opt, 0) < 0) {
wolinfo->supported = 0; wolinfo->supported = 0;
wolinfo->wolopts = 0; wolinfo->wolopts = 0;
return; return;
...@@ -455,7 +549,7 @@ int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) ...@@ -455,7 +549,7 @@ int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
opt |= AX_MONITOR_MAGIC; opt |= AX_MONITOR_MAGIC;
if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
opt, 0, 0, NULL) < 0) opt, 0, 0, NULL, 0) < 0)
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -490,7 +584,7 @@ int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, ...@@ -490,7 +584,7 @@ int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
/* ax8817x returns 2 bytes from eeprom on read */ /* ax8817x returns 2 bytes from eeprom on read */
for (i = first_word; i <= last_word; i++) { for (i = first_word; i <= last_word; i++) {
if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2, if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2,
&(eeprom_buff[i - first_word])) < 0) { &eeprom_buff[i - first_word], 0) < 0) {
kfree(eeprom_buff); kfree(eeprom_buff);
return -EIO; return -EIO;
} }
...@@ -531,7 +625,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, ...@@ -531,7 +625,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
the EEPROM */ the EEPROM */
if (eeprom->offset & 1) { if (eeprom->offset & 1) {
ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2, ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2,
&(eeprom_buff[0])); &eeprom_buff[0], 0);
if (ret < 0) { if (ret < 0) {
netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word); netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word);
goto free; goto free;
...@@ -540,7 +634,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, ...@@ -540,7 +634,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
if ((eeprom->offset + eeprom->len) & 1) { if ((eeprom->offset + eeprom->len) & 1) {
ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2, ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2,
&(eeprom_buff[last_word - first_word])); &eeprom_buff[last_word - first_word], 0);
if (ret < 0) { if (ret < 0) {
netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word); netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word);
goto free; goto free;
...@@ -550,7 +644,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, ...@@ -550,7 +644,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len); memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len);
/* write data to EEPROM */ /* write data to EEPROM */
ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(net, "Failed to enable EEPROM write\n"); netdev_err(net, "Failed to enable EEPROM write\n");
goto free; goto free;
...@@ -561,7 +655,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, ...@@ -561,7 +655,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n", netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n",
i, eeprom_buff[i - first_word]); i, eeprom_buff[i - first_word]);
ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i, ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i,
eeprom_buff[i - first_word], 0, NULL); eeprom_buff[i - first_word], 0, NULL, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n", netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n",
i); i);
...@@ -570,7 +664,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, ...@@ -570,7 +664,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
msleep(20); msleep(20);
} }
ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(net, "Failed to disable EEPROM write\n"); netdev_err(net, "Failed to disable EEPROM write\n");
goto free; goto free;
......
...@@ -184,7 +184,7 @@ static int ax88172_link_reset(struct usbnet *dev) ...@@ -184,7 +184,7 @@ static int ax88172_link_reset(struct usbnet *dev)
netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
asix_write_medium_mode(dev, mode); asix_write_medium_mode(dev, mode, 0);
return 0; return 0;
} }
...@@ -213,18 +213,19 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -213,18 +213,19 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
/* Toggle the GPIOs in a manufacturer/model specific way */ /* Toggle the GPIOs in a manufacturer/model specific way */
for (i = 2; i >= 0; i--) { for (i = 2; i >= 0; i--) {
ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
(gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
msleep(5); msleep(5);
} }
ret = asix_write_rx_ctl(dev, 0x80); ret = asix_write_rx_ctl(dev, 0x80, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
/* Get the MAC address */ /* Get the MAC address */
ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID,
0, 0, ETH_ALEN, buf, 0);
if (ret < 0) { if (ret < 0) {
netdev_dbg(dev->net, "read AX_CMD_READ_NODE_ID failed: %d\n", netdev_dbg(dev->net, "read AX_CMD_READ_NODE_ID failed: %d\n",
ret); ret);
...@@ -290,86 +291,200 @@ static int ax88772_link_reset(struct usbnet *dev) ...@@ -290,86 +291,200 @@ static int ax88772_link_reset(struct usbnet *dev)
netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
asix_write_medium_mode(dev, mode); asix_write_medium_mode(dev, mode, 0);
return 0; return 0;
} }
static int ax88772_reset(struct usbnet *dev) static int ax88772_reset(struct usbnet *dev)
{
struct asix_data *data = (struct asix_data *)&dev->data;
int ret;
/* Rewrite MAC address */
ether_addr_copy(data->mac_addr, dev->net->dev_addr);
ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0,
ETH_ALEN, data->mac_addr, 0);
if (ret < 0)
goto out;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, 0);
if (ret < 0)
goto out;
asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT, 0);
if (ret < 0)
goto out;
return 0;
out:
return ret;
}
static int ax88772_hw_reset(struct usbnet *dev, int in_pm)
{ {
struct asix_data *data = (struct asix_data *)&dev->data; struct asix_data *data = (struct asix_data *)&dev->data;
int ret, embd_phy; int ret, embd_phy;
u16 rx_ctl; u16 rx_ctl;
ret = asix_write_gpio(dev, ret = asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_2 |
AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); AX_GPIO_GPO2EN, 5, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0);
ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy,
0, 0, NULL, in_pm);
if (ret < 0) { if (ret < 0) {
netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
goto out; goto out;
} }
ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); if (embd_phy) {
ret = asix_sw_reset(dev, AX_SWRESET_IPPD, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
msleep(150); usleep_range(10000, 11000);
ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); ret = asix_sw_reset(dev, AX_SWRESET_CLEAR, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
msleep(150); msleep(60);
if (embd_phy) { ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL,
ret = asix_sw_reset(dev, AX_SWRESET_IPRL); in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
} else { } else {
ret = asix_sw_reset(dev, AX_SWRESET_PRTE); ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL,
in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
} }
msleep(150); msleep(150);
rx_ctl = asix_read_rx_ctl(dev);
netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); if (in_pm && (!asix_mdio_read_nopm(dev->net, dev->mii.phy_id,
ret = asix_write_rx_ctl(dev, 0x0000); MII_PHYSID1))){
ret = -EIO;
goto out;
}
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
rx_ctl = asix_read_rx_ctl(dev); ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT, in_pm);
netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); if (ret < 0)
goto out;
ret = asix_sw_reset(dev, AX_SWRESET_PRL); ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
AX88772_IPG2_DEFAULT, 0, NULL, in_pm);
if (ret < 0) {
netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
goto out;
}
/* Rewrite MAC address */
ether_addr_copy(data->mac_addr, dev->net->dev_addr);
ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0,
ETH_ALEN, data->mac_addr, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
msleep(150); /* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, in_pm);
if (ret < 0)
goto out;
rx_ctl = asix_read_rx_ctl(dev, in_pm);
netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
rx_ctl);
rx_ctl = asix_read_medium_status(dev, in_pm);
netdev_dbg(dev->net,
"Medium Status is 0x%04x after all initializations\n",
rx_ctl);
return 0;
out:
return ret;
}
ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); static int ax88772a_hw_reset(struct usbnet *dev, int in_pm)
{
struct asix_data *data = (struct asix_data *)&dev->data;
int ret, embd_phy;
u16 rx_ctl;
u8 chipcode = 0;
ret = asix_write_gpio(dev, AX_GPIO_RSE, 5, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
msleep(150); embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0);
asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy |
asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, AX_PHYSEL_SSEN, 0, 0, NULL, in_pm);
ADVERTISE_ALL | ADVERTISE_CSMA); if (ret < 0) {
mii_nway_restart(&dev->mii); netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
goto out;
}
usleep_range(10000, 11000);
ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_IPRL, in_pm);
if (ret < 0)
goto out;
usleep_range(10000, 11000);
ret = asix_sw_reset(dev, AX_SWRESET_IPRL, in_pm);
if (ret < 0)
goto out;
msleep(160);
ret = asix_sw_reset(dev, AX_SWRESET_CLEAR, in_pm);
if (ret < 0)
goto out;
ret = asix_sw_reset(dev, AX_SWRESET_IPRL, in_pm);
if (ret < 0)
goto out;
msleep(200);
ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); if (in_pm && (!asix_mdio_read_nopm(dev->net, dev->mii.phy_id,
MII_PHYSID1))) {
ret = -1;
goto out;
}
ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0,
0, 1, &chipcode, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
if ((chipcode & AX_CHIPCODE_MASK) == AX_AX88772B_CHIPCODE) {
ret = asix_write_cmd(dev, AX_QCTCTRL, 0x8000, 0x8001,
0, NULL, in_pm);
if (ret < 0) {
netdev_dbg(dev->net, "Write BQ setting failed: %d\n",
ret);
goto out;
}
}
ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
AX88772_IPG2_DEFAULT, 0, NULL); AX88772_IPG2_DEFAULT, 0, NULL, in_pm);
if (ret < 0) { if (ret < 0) {
netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
goto out; goto out;
...@@ -378,20 +493,29 @@ static int ax88772_reset(struct usbnet *dev) ...@@ -378,20 +493,29 @@ static int ax88772_reset(struct usbnet *dev)
/* Rewrite MAC address */ /* Rewrite MAC address */
memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
data->mac_addr); data->mac_addr, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, in_pm);
if (ret < 0) if (ret < 0)
goto out; goto out;
rx_ctl = asix_read_rx_ctl(dev); ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT, in_pm);
if (ret < 0)
return ret;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, in_pm);
if (ret < 0)
goto out;
rx_ctl = asix_read_rx_ctl(dev, in_pm);
netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
rx_ctl); rx_ctl);
rx_ctl = asix_read_medium_status(dev); rx_ctl = asix_read_medium_status(dev, in_pm);
netdev_dbg(dev->net, netdev_dbg(dev->net,
"Medium Status is 0x%04x after all initializations\n", "Medium Status is 0x%04x after all initializations\n",
rx_ctl); rx_ctl);
...@@ -400,7 +524,6 @@ static int ax88772_reset(struct usbnet *dev) ...@@ -400,7 +524,6 @@ static int ax88772_reset(struct usbnet *dev)
out: out:
return ret; return ret;
} }
static const struct net_device_ops ax88772_netdev_ops = { static const struct net_device_ops ax88772_netdev_ops = {
...@@ -415,11 +538,87 @@ static const struct net_device_ops ax88772_netdev_ops = { ...@@ -415,11 +538,87 @@ static const struct net_device_ops ax88772_netdev_ops = {
.ndo_set_rx_mode = asix_set_multicast, .ndo_set_rx_mode = asix_set_multicast,
}; };
static void ax88772_suspend(struct usbnet *dev)
{
struct asix_common_private *priv = dev->driver_priv;
/* Preserve BMCR for restoring */
priv->presvd_phy_bmcr =
asix_mdio_read_nopm(dev->net, dev->mii.phy_id, MII_BMCR);
/* Preserve ANAR for restoring */
priv->presvd_phy_advertise =
asix_mdio_read_nopm(dev->net, dev->mii.phy_id, MII_ADVERTISE);
}
static int asix_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbnet *dev = usb_get_intfdata(intf);
struct asix_common_private *priv = dev->driver_priv;
if (priv->suspend)
priv->suspend(dev);
return usbnet_suspend(intf, message);
}
static void ax88772_restore_phy(struct usbnet *dev)
{
struct asix_common_private *priv = dev->driver_priv;
if (priv->presvd_phy_advertise) {
/* Restore Advertisement control reg */
asix_mdio_write_nopm(dev->net, dev->mii.phy_id, MII_ADVERTISE,
priv->presvd_phy_advertise);
/* Restore BMCR */
asix_mdio_write_nopm(dev->net, dev->mii.phy_id, MII_BMCR,
priv->presvd_phy_bmcr);
priv->presvd_phy_advertise = 0;
priv->presvd_phy_bmcr = 0;
}
}
static void ax88772_resume(struct usbnet *dev)
{
int i;
for (i = 0; i < 3; i++)
if (!ax88772_hw_reset(dev, 1))
break;
ax88772_restore_phy(dev);
}
static void ax88772a_resume(struct usbnet *dev)
{
int i;
for (i = 0; i < 3; i++) {
if (!ax88772a_hw_reset(dev, 1))
break;
}
ax88772_restore_phy(dev);
}
static int asix_resume(struct usb_interface *intf)
{
struct usbnet *dev = usb_get_intfdata(intf);
struct asix_common_private *priv = dev->driver_priv;
if (priv->resume)
priv->resume(dev);
return usbnet_resume(intf);
}
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{ {
int ret, embd_phy, i; int ret, i;
u8 buf[ETH_ALEN]; u8 buf[ETH_ALEN], chipcode = 0;
u32 phyid; u32 phyid;
struct asix_common_private *priv;
usbnet_get_endpoints(dev,intf); usbnet_get_endpoints(dev,intf);
...@@ -427,13 +626,13 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -427,13 +626,13 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
if (dev->driver_info->data & FLAG_EEPROM_MAC) { if (dev->driver_info->data & FLAG_EEPROM_MAC) {
for (i = 0; i < (ETH_ALEN >> 1); i++) { for (i = 0; i < (ETH_ALEN >> 1); i++) {
ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x04 + i, ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x04 + i,
0, 2, buf + i * 2); 0, 2, buf + i * 2, 0);
if (ret < 0) if (ret < 0)
break; break;
} }
} else { } else {
ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
0, 0, ETH_ALEN, buf); 0, 0, ETH_ALEN, buf, 0);
} }
if (ret < 0) { if (ret < 0) {
...@@ -456,16 +655,11 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -456,16 +655,11 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */
dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */
embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &chipcode, 0);
chipcode &= AX_CHIPCODE_MASK;
/* Reset the PHY to normal operation mode */ (chipcode == AX_AX88772_CHIPCODE) ? ax88772_hw_reset(dev, 0) :
ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); ax88772a_hw_reset(dev, 0);
if (ret < 0) {
netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
return ret;
}
ax88772_reset(dev);
/* Read PHYID register *AFTER* the PHY was reset properly */ /* Read PHYID register *AFTER* the PHY was reset properly */
phyid = asix_get_phyid(dev); phyid = asix_get_phyid(dev);
...@@ -482,6 +676,18 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -482,6 +676,18 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
if (!dev->driver_priv) if (!dev->driver_priv)
return -ENOMEM; return -ENOMEM;
priv = dev->driver_priv;
priv->presvd_phy_bmcr = 0;
priv->presvd_phy_advertise = 0;
if (chipcode == AX_AX88772_CHIPCODE) {
priv->resume = ax88772_resume;
priv->suspend = ax88772_suspend;
} else {
priv->resume = ax88772a_resume;
priv->suspend = ax88772_suspend;
}
return 0; return 0;
} }
...@@ -593,12 +799,12 @@ static int ax88178_reset(struct usbnet *dev) ...@@ -593,12 +799,12 @@ static int ax88178_reset(struct usbnet *dev)
int gpio0 = 0; int gpio0 = 0;
u32 phyid; u32 phyid;
asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status, 0);
netdev_dbg(dev->net, "GPIO Status: 0x%04x\n", status); netdev_dbg(dev->net, "GPIO Status: 0x%04x\n", status);
asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL, 0);
asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom, 0);
asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL, 0);
netdev_dbg(dev->net, "EEPROM index 0x17 is 0x%04x\n", eeprom); netdev_dbg(dev->net, "EEPROM index 0x17 is 0x%04x\n", eeprom);
...@@ -614,15 +820,16 @@ static int ax88178_reset(struct usbnet *dev) ...@@ -614,15 +820,16 @@ static int ax88178_reset(struct usbnet *dev)
netdev_dbg(dev->net, "GPIO0: %d, PhyMode: %d\n", gpio0, data->phymode); netdev_dbg(dev->net, "GPIO0: %d, PhyMode: %d\n", gpio0, data->phymode);
/* Power up external GigaPHY through AX88178 GPIO pin */ /* Power up external GigaPHY through AX88178 GPIO pin */
asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 |
AX_GPIO_GPO1EN, 40, 0);
if ((le16_to_cpu(eeprom) >> 8) != 1) { if ((le16_to_cpu(eeprom) >> 8) != 1) {
asix_write_gpio(dev, 0x003c, 30); asix_write_gpio(dev, 0x003c, 30, 0);
asix_write_gpio(dev, 0x001c, 300); asix_write_gpio(dev, 0x001c, 300, 0);
asix_write_gpio(dev, 0x003c, 30); asix_write_gpio(dev, 0x003c, 30, 0);
} else { } else {
netdev_dbg(dev->net, "gpio phymode == 1 path\n"); netdev_dbg(dev->net, "gpio phymode == 1 path\n");
asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); asix_write_gpio(dev, AX_GPIO_GPO1EN, 30, 0);
asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30, 0);
} }
/* Read PHYID register *AFTER* powering up PHY */ /* Read PHYID register *AFTER* powering up PHY */
...@@ -630,15 +837,15 @@ static int ax88178_reset(struct usbnet *dev) ...@@ -630,15 +837,15 @@ static int ax88178_reset(struct usbnet *dev)
netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid);
/* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */
asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL, 0);
asix_sw_reset(dev, 0); asix_sw_reset(dev, 0, 0);
msleep(150); msleep(150);
asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD, 0);
msleep(150); msleep(150);
asix_write_rx_ctl(dev, 0); asix_write_rx_ctl(dev, 0, 0);
if (data->phymode == PHY_MODE_MARVELL) { if (data->phymode == PHY_MODE_MARVELL) {
marvell_phy_init(dev); marvell_phy_init(dev);
...@@ -655,18 +862,18 @@ static int ax88178_reset(struct usbnet *dev) ...@@ -655,18 +862,18 @@ static int ax88178_reset(struct usbnet *dev)
mii_nway_restart(&dev->mii); mii_nway_restart(&dev->mii);
ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Rewrite MAC address */ /* Rewrite MAC address */
memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
data->mac_addr); data->mac_addr, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -704,7 +911,7 @@ static int ax88178_link_reset(struct usbnet *dev) ...@@ -704,7 +911,7 @@ static int ax88178_link_reset(struct usbnet *dev)
netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
speed, ecmd.duplex, mode); speed, ecmd.duplex, mode);
asix_write_medium_mode(dev, mode); asix_write_medium_mode(dev, mode, 0);
if (data->phymode == PHY_MODE_MARVELL && data->ledmode) if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
marvell_led_status(dev, speed); marvell_led_status(dev, speed);
...@@ -733,15 +940,15 @@ static void ax88178_set_mfb(struct usbnet *dev) ...@@ -733,15 +940,15 @@ static void ax88178_set_mfb(struct usbnet *dev)
mfb = AX_RX_CTL_MFB_16384; mfb = AX_RX_CTL_MFB_16384;
} }
rxctl = asix_read_rx_ctl(dev); rxctl = asix_read_rx_ctl(dev, 0);
asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb, 0);
medium = asix_read_medium_status(dev); medium = asix_read_medium_status(dev, 0);
if (dev->net->mtu > 1500) if (dev->net->mtu > 1500)
medium |= AX_MEDIUM_JFE; medium |= AX_MEDIUM_JFE;
else else
medium &= ~AX_MEDIUM_JFE; medium &= ~AX_MEDIUM_JFE;
asix_write_medium_mode(dev, medium); asix_write_medium_mode(dev, medium, 0);
if (dev->rx_urb_size > old_rx_urb_size) if (dev->rx_urb_size > old_rx_urb_size)
usbnet_unlink_rx_urbs(dev); usbnet_unlink_rx_urbs(dev);
...@@ -790,7 +997,7 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -790,7 +997,7 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
usbnet_get_endpoints(dev,intf); usbnet_get_endpoints(dev,intf);
/* Get the MAC address */ /* Get the MAC address */
ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf, 0);
if (ret < 0) { if (ret < 0) {
netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret); netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
return ret; return ret;
...@@ -811,10 +1018,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -811,10 +1018,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->ethtool_ops = &ax88178_ethtool_ops; dev->net->ethtool_ops = &ax88178_ethtool_ops;
/* Blink LEDS so users know driver saw dongle */ /* Blink LEDS so users know driver saw dongle */
asix_sw_reset(dev, 0); asix_sw_reset(dev, 0, 0);
msleep(150); msleep(150);
asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD, 0);
msleep(150); msleep(150);
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
...@@ -877,7 +1084,7 @@ static const struct driver_info ax88772_info = { ...@@ -877,7 +1084,7 @@ static const struct driver_info ax88772_info = {
.unbind = ax88772_unbind, .unbind = ax88772_unbind,
.status = asix_status, .status = asix_status,
.link_reset = ax88772_link_reset, .link_reset = ax88772_link_reset,
.reset = ax88772_link_reset, .reset = ax88772_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
.rx_fixup = asix_rx_fixup_common, .rx_fixup = asix_rx_fixup_common,
.tx_fixup = asix_tx_fixup, .tx_fixup = asix_tx_fixup,
...@@ -1005,7 +1212,7 @@ static const struct usb_device_id products [] = { ...@@ -1005,7 +1212,7 @@ static const struct usb_device_id products [] = {
}, { }, {
// Lenovo U2L100P 10/100 // Lenovo U2L100P 10/100
USB_DEVICE (0x17ef, 0x7203), USB_DEVICE (0x17ef, 0x7203),
.driver_info = (unsigned long) &ax88772_info, .driver_info = (unsigned long)&ax88772b_info,
}, { }, {
// ASIX AX88772B 10/100 // ASIX AX88772B 10/100
USB_DEVICE (0x0b95, 0x772b), USB_DEVICE (0x0b95, 0x772b),
...@@ -1073,7 +1280,7 @@ static const struct usb_device_id products [] = { ...@@ -1073,7 +1280,7 @@ static const struct usb_device_id products [] = {
}, { }, {
// Asus USB Ethernet Adapter // Asus USB Ethernet Adapter
USB_DEVICE (0x0b95, 0x7e2b), USB_DEVICE (0x0b95, 0x7e2b),
.driver_info = (unsigned long) &ax88772_info, .driver_info = (unsigned long)&ax88772b_info,
}, { }, {
/* ASIX 88172a demo board */ /* ASIX 88172a demo board */
USB_DEVICE(0x0b95, 0x172a), USB_DEVICE(0x0b95, 0x172a),
...@@ -1095,8 +1302,8 @@ static struct usb_driver asix_driver = { ...@@ -1095,8 +1302,8 @@ static struct usb_driver asix_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = products, .id_table = products,
.probe = usbnet_probe, .probe = usbnet_probe,
.suspend = usbnet_suspend, .suspend = asix_suspend,
.resume = usbnet_resume, .resume = asix_resume,
.disconnect = usbnet_disconnect, .disconnect = usbnet_disconnect,
.supports_autosuspend = 1, .supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1, .disable_hub_initiated_lpm = 1,
......
...@@ -81,7 +81,7 @@ static void ax88172a_adjust_link(struct net_device *netdev) ...@@ -81,7 +81,7 @@ static void ax88172a_adjust_link(struct net_device *netdev)
} }
if (mode != priv->oldmode) { if (mode != priv->oldmode) {
asix_write_medium_mode(dev, mode); asix_write_medium_mode(dev, mode, 0);
priv->oldmode = mode; priv->oldmode = mode;
netdev_dbg(netdev, "speed %u duplex %d, setting mode to 0x%04x\n", netdev_dbg(netdev, "speed %u duplex %d, setting mode to 0x%04x\n",
phydev->speed, phydev->duplex, mode); phydev->speed, phydev->duplex, mode);
...@@ -176,18 +176,19 @@ static int ax88172a_reset_phy(struct usbnet *dev, int embd_phy) ...@@ -176,18 +176,19 @@ static int ax88172a_reset_phy(struct usbnet *dev, int embd_phy)
{ {
int ret; int ret;
ret = asix_sw_reset(dev, AX_SWRESET_IPPD); ret = asix_sw_reset(dev, AX_SWRESET_IPPD, 0);
if (ret < 0) if (ret < 0)
goto err; goto err;
msleep(150); msleep(150);
ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); ret = asix_sw_reset(dev, AX_SWRESET_CLEAR, 0);
if (ret < 0) if (ret < 0)
goto err; goto err;
msleep(150); msleep(150);
ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_IPPD); ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_IPPD,
0);
if (ret < 0) if (ret < 0)
goto err; goto err;
...@@ -213,7 +214,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -213,7 +214,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
dev->driver_priv = priv; dev->driver_priv = priv;
/* Get the MAC address */ /* Get the MAC address */
ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(dev->net, "Failed to read MAC address: %d\n", ret); netdev_err(dev->net, "Failed to read MAC address: %d\n", ret);
goto free; goto free;
...@@ -224,7 +225,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -224,7 +225,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->ethtool_ops = &ax88172a_ethtool_ops; dev->net->ethtool_ops = &ax88172a_ethtool_ops;
/* are we using the internal or the external phy? */ /* are we using the internal or the external phy? */
ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf); ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(dev->net, "Failed to read software interface selection register: %d\n", netdev_err(dev->net, "Failed to read software interface selection register: %d\n",
ret); ret);
...@@ -303,20 +304,20 @@ static int ax88172a_reset(struct usbnet *dev) ...@@ -303,20 +304,20 @@ static int ax88172a_reset(struct usbnet *dev)
ax88172a_reset_phy(dev, priv->use_embdphy); ax88172a_reset_phy(dev, priv->use_embdphy);
msleep(150); msleep(150);
rx_ctl = asix_read_rx_ctl(dev); rx_ctl = asix_read_rx_ctl(dev, 0);
netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
ret = asix_write_rx_ctl(dev, 0x0000); ret = asix_write_rx_ctl(dev, 0x0000, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
rx_ctl = asix_read_rx_ctl(dev); rx_ctl = asix_read_rx_ctl(dev, 0);
netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
msleep(150); msleep(150);
ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
AX88772_IPG2_DEFAULT, 0, NULL); AX88772_IPG2_DEFAULT, 0, NULL, 0);
if (ret < 0) { if (ret < 0) {
netdev_err(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); netdev_err(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
goto out; goto out;
...@@ -325,20 +326,20 @@ static int ax88172a_reset(struct usbnet *dev) ...@@ -325,20 +326,20 @@ static int ax88172a_reset(struct usbnet *dev)
/* Rewrite MAC address */ /* Rewrite MAC address */
memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
data->mac_addr); data->mac_addr, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
rx_ctl = asix_read_rx_ctl(dev); rx_ctl = asix_read_rx_ctl(dev, 0);
netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
rx_ctl); rx_ctl);
rx_ctl = asix_read_medium_status(dev); rx_ctl = asix_read_medium_status(dev, 0);
netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n", netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n",
rx_ctl); rx_ctl);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment