Patchwork [U-Boot] USB: Ethernet: asix.c: Added support for AX88178 based devices

login
register
mail settings
Submitter David Jander
Date May 31, 2011, 12:58 p.m.
Message ID <1306846706-16766-1-git-send-email-david@protonic.nl>
Download mbox | patch
Permalink /patch/98030/
State Changes Requested
Headers show

Comments

David Jander - May 31, 2011, 12:58 p.m.
Completed command definitions copied from linux driver source.
Implemented support for AX88178 by copying and rewriting bits and pieces
from the linux asix driver.

Signed-off-by: David Jander <david@protonic.nl>
---
 drivers/usb/eth/asix.c |  236 +++++++++++++++++++++++++++++++++++++++++++++---
 include/usb_ether.h    |    1 +
 2 files changed, 224 insertions(+), 13 deletions(-)
Simon Glass - June 24, 2011, 12:03 a.m.
Hi David,

Thanks for the patch - I have tried this and things still work, but I
don't think I have a Belkin F5D5055 Gig USB to test with. No matter.

Please see below form comments.

On Tue, May 31, 2011 at 5:58 AM, David Jander <david@protonic.nl> wrote:
> Completed command definitions copied from linux driver source.
> Implemented support for AX88178 by copying and rewriting bits and pieces
> from the linux asix driver.
>
> Signed-off-by: David Jander <david@protonic.nl>
> ---
>  drivers/usb/eth/asix.c |  236 +++++++++++++++++++++++++++++++++++++++++++++---
>  include/usb_ether.h    |    1 +
>  2 files changed, 224 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c
> index 9b012e4..cecbc76 100644
> --- a/drivers/usb/eth/asix.c
> +++ b/drivers/usb/eth/asix.c

> @@ -310,7 +331,7 @@ static int mii_nway_restart(struct ueth_data *dev)
>  /*
>  * Asix callbacks
>  */
> -static int asix_init(struct eth_device *eth, bd_t *bd)
> +static int asix_init_ax88772(struct eth_device *eth, bd_t *bd)
>  {
>        int embd_phy;
>        unsigned char buf[ETH_ALEN];
> @@ -419,6 +440,190 @@ out_err:
>        return -1;
>  }
>
> +/**
> + * mii_check_media - check the MII interface for a duplex change
> + * @mii: the MII interface
> + * @ok_to_print: OK to print link up/down messages
> + * @init_media: OK to save duplex mode in @mii
> + *
> + * Returns 1 if the duplex mode changed, 0 if not.
> + * If the media type is forced, always returns 0.
> + */
> +unsigned int mii_check_media (struct eth_device *eth,

Please remove space before (

> +                             unsigned int ok_to_print,
> +                             unsigned int init_media)
> +{
> +       int advertise, lpa, media, duplex;
> +       int lpa2 = 0;
> +       struct ueth_data *dev = (struct ueth_data *)eth->priv;
> +
> +       /* get MII advertise and LPA values */
> +       advertise = asix_mdio_read(dev, dev->phy_id, MII_ADVERTISE);
> +       lpa = asix_mdio_read(dev, dev->phy_id, MII_LPA);
> +       lpa2 = asix_mdio_read(dev, dev->phy_id, MII_STAT1000);
> +
> +       /* figure out media and duplex from advertise and LPA values */
> +       media = mii_nway_result(lpa & advertise);
> +       duplex = (media & ADVERTISE_FULL) ? 1 : 0;
> +       if (lpa2 & LPA_1000FULL)
> +               duplex = 1;
> +
> +       printf("link up, %uMbps, %s-duplex, lpa 0x%04X\n",
> +                           lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
> +                           media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
> +                           100 : 10,
> +                           duplex ? "full" : "half",
> +                           lpa);
> +
> +       return 0; /* duplex did not change */
> +}
> +
> +static int ax88178_link_reset(struct eth_device *eth)
> +{
> +       u16 mode;
> +       struct ueth_data        *dev = (struct ueth_data *)eth->priv;
> +
> +       debug("ax88178_link_reset()\n");
> +
> +       mii_check_media(eth, 1, 1);
> +       mode = AX88178_MEDIUM_DEFAULT;
> +
> +       /* All supported ax88178 dongles have GMII */
> +       mode |= AX_MEDIUM_GM;
> +       mode |= AX_MEDIUM_ENCK;
> +       mode |= AX_MEDIUM_FD;
> +
> +       asix_write_medium_mode(dev, mode);
> +
> +       return 0;
> +}
> +
> +static int asix_init_ax88178(struct eth_device *eth, bd_t *bd)
> +{
> +       unsigned char buf[ETH_ALEN];
> +       int phymode, ledmode;
> +       int gpio0 = 0;
> +       u8 status;
> +       __le16 eeprom;
> +       struct ueth_data        *dev = (struct ueth_data *)eth->priv;
> +       int timeout = 0;
> +#define TIMEOUT_RESOLUTION 50  /* ms */
> +       int link_detected;
> +
> +       debug("** %s()\n", __func__);
> +
> +       asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status);
> +       debug("GPIO Status: 0x%04x\n", status);
> +
> +       asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
> +       asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
> +       asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
> +
> +       debug("EEPROM index 0x17 is 0x%04x\n", eeprom);
> +       if (eeprom == cpu_to_le16(0xffff)) {
> +               printf("Error: Marvell phy not supported\n");
> +               return -1;
> +       } else {
> +               phymode = le16_to_cpu(eeprom) & 7;
> +               ledmode = le16_to_cpu(eeprom) >> 8;
> +               gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1;
> +       }
> +       debug("GPIO0: %d, PhyMode: %d\n", gpio0, phymode);
> +
> +       asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
> +       if ((le16_to_cpu(eeprom) >> 8) != 1) {
> +               asix_write_gpio(dev, 0x003c, 30);
> +               asix_write_gpio(dev, 0x001c, 300);
> +               asix_write_gpio(dev, 0x003c, 30);
> +       } else {
> +               debug("gpio phymode == 1 path\n");
> +               asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
> +               asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
> +       }
> +
> +       asix_sw_reset(dev, 0);
> +       udelay(150000);
> +
> +       asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
> +       udelay(150000);
> +
> +       asix_write_rx_ctl(dev, 0);
> +
> +       /* Get the MAC address */
> +       if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
> +                               0, 0, ETH_ALEN, buf) < 0) {
> +               debug("Failed to read MAC address.\n");
> +               goto out_err;
> +       }
> +       memcpy(eth->enetaddr, buf, ETH_ALEN);
> +       debug("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
> +               eth->enetaddr[0], eth->enetaddr[1],
> +               eth->enetaddr[2], eth->enetaddr[3],
> +               eth->enetaddr[4], eth->enetaddr[5]);
> +
> +       dev->phy_id = asix_get_phy_addr(dev);
> +       if (dev->phy_id < 0)
> +               debug("Failed to read phy id\n");
> +
> +       asix_mdio_write(dev, dev->phy_id, MII_BMCR,
> +                       BMCR_RESET | BMCR_ANENABLE);
> +       asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
> +                       ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
> +       asix_mdio_write(dev, dev->phy_id, MII_CTRL1000,
> +                       ADVERTISE_1000FULL);
> +
> +       mii_nway_restart(dev);
> +
> +       if (asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT) < 0)
> +               goto out_err;
> +
> +       if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0)
> +               goto out_err;
> +
> +       do {
> +               link_detected = asix_mdio_read(dev, dev->phy_id, MII_BMSR) &
> +                       BMSR_LSTATUS;
> +               if (!link_detected) {
> +                       if (timeout == 0)
> +                               printf("Waiting for Ethernet connection... ");
> +                       udelay(TIMEOUT_RESOLUTION * 1000);
> +                       timeout += TIMEOUT_RESOLUTION;
> +               }
> +       } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
> +       if (link_detected) {
> +               if (timeout != 0)
> +                       printf("done.\n");
> +       } else {
> +               printf("unable to connect.\n");
> +               goto out_err;
> +       }
> +
> +       udelay(50000);
> +       ax88178_link_reset(eth);
> +       udelay(50000);
> +
> +       return 0;
> +out_err:
> +       return -1;
> +}
> +
> +static int asix_init(struct eth_device *eth, bd_t *bd)
> +{
> +       struct ueth_data *dev = (struct ueth_data *)eth->priv;
> +
> +       switch (dev->asix_model) {
> +       case ASIX_MODEL_AX88772 :

I don't think you should have space before : here

> +               return asix_init_ax88772(eth, bd);
> +               break;
> +       case ASIX_MODEL_AX88178 :

and here

> +               return asix_init_ax88178(eth, bd);
> +               break;
> +       default:
> +               printf("Unsupported asix model!\n");
> +               return -1;
> +       }
> +}
> +
>  static int asix_send(struct eth_device *eth, volatile void *packet, int length)
>  {
>        struct ueth_data *dev = (struct ueth_data *)eth->priv;
> @@ -530,19 +735,21 @@ void asix_eth_before_probe(void)
>  struct asix_dongle {
>        unsigned short vendor;
>        unsigned short product;
> +       unsigned int asix_model;
>  };
>
>  static struct asix_dongle asix_dongles[] = {
> -       { 0x05ac, 0x1402 },     /* Apple USB Ethernet Adapter */
> -       { 0x07d1, 0x3c05 },     /* D-Link DUB-E100 H/W Ver B1 */
> -       { 0x0b95, 0x772a },     /* Cables-to-Go USB Ethernet Adapter */
> -       { 0x0b95, 0x7720 },     /* Trendnet TU2-ET100 V3.0R */
> -       { 0x0b95, 0x1720 },     /* SMC */
> -       { 0x0db0, 0xa877 },     /* MSI - ASIX 88772a */
> -       { 0x13b1, 0x0018 },     /* Linksys 200M v2.1 */
> -       { 0x1557, 0x7720 },     /* 0Q0 cable ethernet */
> -       { 0x2001, 0x3c05 },     /* DLink DUB-E100 H/W Ver B1 Alternate */
> -       { 0x0000, 0x0000 }      /* END - Do not remove */
> +       { 0x05ac, 0x1402, ASIX_MODEL_AX88772 }, /* Apple USB Ethernet Adapter */
> +       { 0x07d1, 0x3c05, ASIX_MODEL_AX88772 }, /* D-Link DUB-E100 H/W Ver B1 */
> +       { 0x0b95, 0x772a, ASIX_MODEL_AX88772 }, /* Cables-to-Go USB Ethernet Adapter */

A few lines over 80cols here - can you reduce? Maybe ASIX_MODEL_AX...
to MODEL_AX...?

> +       { 0x0b95, 0x7720, ASIX_MODEL_AX88772 }, /* Trendnet TU2-ET100 V3.0R */
> +       { 0x0b95, 0x1720, ASIX_MODEL_AX88772 }, /* SMC FIXME: isn't this AX88178? */
> +       { 0x0db0, 0xa877, ASIX_MODEL_AX88772 }, /* MSI - ASIX 88772a */
> +       { 0x13b1, 0x0018, ASIX_MODEL_AX88772 }, /* Linksys 200M v2.1 */
> +       { 0x1557, 0x7720, ASIX_MODEL_AX88772 }, /* 0Q0 cable ethernet */
> +       { 0x2001, 0x3c05, ASIX_MODEL_AX88772 }, /* DLink DUB-E100 H/W Ver B1 Alternate */
> +       { 0x050d, 0x5055, ASIX_MODEL_AX88178 }, /* Belkin F5D5055 Gig USB */
> +       { 0x0000, 0x0000, 0 }   /* END - Do not remove */
>  };
>
>  /* Probe to see if a new device is actually an asix device */
> @@ -569,9 +776,12 @@ int asix_eth_probe(struct usb_device *dev, unsigned int ifnum,
>
>        memset(ss, 0, sizeof(struct ueth_data));
>
> +       ss->asix_model = asix_dongles[i].asix_model;
> +
>        /* At this point, we know we've got a live one */
> -       debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
> -             dev->descriptor.idVendor, dev->descriptor.idProduct);
> +       debug("\n\nUSB Ethernet device detected: %#04x:%#04x model AX88%s\n",
> +             dev->descriptor.idVendor, dev->descriptor.idProduct,
> +             ss->asix_model? "772" : "178");

Space before ?

...

Regards,
Simon
Simon Glass - July 14, 2011, 5:37 a.m.
Hi David,

On Thu, Jun 23, 2011 at 5:03 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi David,
>
> Thanks for the patch - I have tried this and things still work, but I
> don't think I have a Belkin F5D5055 Gig USB to test with. No matter.
>
> Please see below form comments.
>
> On Tue, May 31, 2011 at 5:58 AM, David Jander <david@protonic.nl> wrote:
>> Completed command definitions copied from linux driver source.
>> Implemented support for AX88178 by copying and rewriting bits and pieces
>> from the linux asix driver.
>>
>> Signed-off-by: David Jander <david@protonic.nl>

[snip]

Are you going to update resend this? We should get it merged I think.

Regards,
Simon

Patch

diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c
index 9b012e4..cecbc76 100644
--- a/drivers/usb/eth/asix.c
+++ b/drivers/usb/eth/asix.c
@@ -24,6 +24,8 @@ 
 #include <linux/mii.h>
 #include "usb_ether.h"
 
+#define ASIX_MODEL_AX88772 0
+#define ASIX_MODEL_AX88178 1
 
 /* ASIX AX8817X based USB 2.0 Ethernet Devices */
 
@@ -31,14 +33,29 @@ 
 #define AX_CMD_READ_MII_REG		0x07
 #define AX_CMD_WRITE_MII_REG		0x08
 #define AX_CMD_SET_HW_MII		0x0a
+#define AX_CMD_READ_EEPROM		0x0b
+#define AX_CMD_WRITE_EEPROM		0x0c
+#define AX_CMD_WRITE_ENABLE		0x0d
+#define AX_CMD_WRITE_DISABLE		0x0e
 #define AX_CMD_READ_RX_CTL		0x0f
 #define AX_CMD_WRITE_RX_CTL		0x10
+#define AX_CMD_READ_IPG012		0x11
 #define AX_CMD_WRITE_IPG0		0x12
+#define AX_CMD_WRITE_IPG1		0x13
 #define AX_CMD_READ_NODE_ID		0x13
+#define AX_CMD_WRITE_NODE_ID		0x14
+#define AX_CMD_WRITE_IPG2		0x14
+#define AX_CMD_WRITE_MULTI_FILTER	0x16
+#define AX88172_CMD_READ_NODE_ID	0x17
 #define AX_CMD_READ_PHY_ID		0x19
+#define AX_CMD_READ_MEDIUM_STATUS	0x1a
 #define AX_CMD_WRITE_MEDIUM_MODE	0x1b
+#define AX_CMD_READ_MONITOR_MODE	0x1c
+#define AX_CMD_WRITE_MONITOR_MODE	0x1d
+#define AX_CMD_READ_GPIOS		0x1e
 #define AX_CMD_WRITE_GPIOS		0x1f
 #define AX_CMD_SW_RESET			0x20
+#define AX_CMD_SW_PHY_STATUS		0x21
 #define AX_CMD_SW_PHY_SELECT		0x22
 
 #define AX_SWRESET_CLEAR		0x00
@@ -83,6 +100,10 @@ 
 	(AX_RX_CTL_SO | AX_RX_CTL_AB)
 
 /* GPIO 2 toggles */
+#define AX_GPIO_GPO0EN		0x01	/* GPIO0 Output enable */
+#define AX_GPIO_GPO_0		0x02	/* GPIO0 Output value */
+#define AX_GPIO_GPO1EN		0x04	/* GPIO1 Output enable */
+#define AX_GPIO_GPO_1		0x08	/* GPIO1 Output value */
 #define AX_GPIO_GPO2EN		0x10	/* GPIO2 Output enable */
 #define AX_GPIO_GPO_2		0x20	/* GPIO2 Output value */
 #define AX_GPIO_RSE		0x80	/* Reload serial EEPROM */
@@ -310,7 +331,7 @@  static int mii_nway_restart(struct ueth_data *dev)
 /*
  * Asix callbacks
  */
-static int asix_init(struct eth_device *eth, bd_t *bd)
+static int asix_init_ax88772(struct eth_device *eth, bd_t *bd)
 {
 	int embd_phy;
 	unsigned char buf[ETH_ALEN];
@@ -419,6 +440,190 @@  out_err:
 	return -1;
 }
 
+/**
+ * mii_check_media - check the MII interface for a duplex change
+ * @mii: the MII interface
+ * @ok_to_print: OK to print link up/down messages
+ * @init_media: OK to save duplex mode in @mii
+ *
+ * Returns 1 if the duplex mode changed, 0 if not.
+ * If the media type is forced, always returns 0.
+ */
+unsigned int mii_check_media (struct eth_device *eth,
+			      unsigned int ok_to_print,
+			      unsigned int init_media)
+{
+	int advertise, lpa, media, duplex;
+	int lpa2 = 0;
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	/* get MII advertise and LPA values */
+	advertise = asix_mdio_read(dev, dev->phy_id, MII_ADVERTISE);
+	lpa = asix_mdio_read(dev, dev->phy_id, MII_LPA);
+	lpa2 = asix_mdio_read(dev, dev->phy_id, MII_STAT1000);
+
+	/* figure out media and duplex from advertise and LPA values */
+	media = mii_nway_result(lpa & advertise);
+	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+	if (lpa2 & LPA_1000FULL)
+		duplex = 1;
+
+	printf("link up, %uMbps, %s-duplex, lpa 0x%04X\n",
+			    lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
+			    media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
+			    100 : 10,
+			    duplex ? "full" : "half",
+			    lpa);
+
+	return 0; /* duplex did not change */
+}
+
+static int ax88178_link_reset(struct eth_device *eth)
+{
+	u16 mode;
+	struct ueth_data	*dev = (struct ueth_data *)eth->priv;
+
+	debug("ax88178_link_reset()\n");
+
+	mii_check_media(eth, 1, 1);
+	mode = AX88178_MEDIUM_DEFAULT;
+
+	/* All supported ax88178 dongles have GMII */
+	mode |= AX_MEDIUM_GM;
+	mode |= AX_MEDIUM_ENCK;
+	mode |= AX_MEDIUM_FD;
+
+	asix_write_medium_mode(dev, mode);
+
+	return 0;
+}
+
+static int asix_init_ax88178(struct eth_device *eth, bd_t *bd)
+{
+	unsigned char buf[ETH_ALEN];
+	int phymode, ledmode;
+	int gpio0 = 0;
+	u8 status;
+	__le16 eeprom;
+	struct ueth_data	*dev = (struct ueth_data *)eth->priv;
+	int timeout = 0;
+#define TIMEOUT_RESOLUTION 50	/* ms */
+	int link_detected;
+
+	debug("** %s()\n", __func__);
+
+	asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status);
+	debug("GPIO Status: 0x%04x\n", status);
+
+	asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
+	asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
+	asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
+
+	debug("EEPROM index 0x17 is 0x%04x\n", eeprom);
+	if (eeprom == cpu_to_le16(0xffff)) {
+		printf("Error: Marvell phy not supported\n");
+		return -1;
+	} else {
+		phymode = le16_to_cpu(eeprom) & 7;
+		ledmode = le16_to_cpu(eeprom) >> 8;
+		gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1;
+	}
+	debug("GPIO0: %d, PhyMode: %d\n", gpio0, phymode);
+
+	asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
+	if ((le16_to_cpu(eeprom) >> 8) != 1) {
+		asix_write_gpio(dev, 0x003c, 30);
+		asix_write_gpio(dev, 0x001c, 300);
+		asix_write_gpio(dev, 0x003c, 30);
+	} else {
+		debug("gpio phymode == 1 path\n");
+		asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
+		asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
+	}
+
+	asix_sw_reset(dev, 0);
+	udelay(150000);
+
+	asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
+	udelay(150000);
+
+	asix_write_rx_ctl(dev, 0);
+
+	/* Get the MAC address */
+	if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+				0, 0, ETH_ALEN, buf) < 0) {
+		debug("Failed to read MAC address.\n");
+		goto out_err;
+	}
+	memcpy(eth->enetaddr, buf, ETH_ALEN);
+	debug("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+		eth->enetaddr[0], eth->enetaddr[1],
+		eth->enetaddr[2], eth->enetaddr[3],
+		eth->enetaddr[4], eth->enetaddr[5]);
+
+	dev->phy_id = asix_get_phy_addr(dev);
+	if (dev->phy_id < 0)
+		debug("Failed to read phy id\n");
+
+	asix_mdio_write(dev, dev->phy_id, MII_BMCR,
+			BMCR_RESET | BMCR_ANENABLE);
+	asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
+			ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	asix_mdio_write(dev, dev->phy_id, MII_CTRL1000,
+			ADVERTISE_1000FULL);
+
+	mii_nway_restart(dev);
+
+	if (asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT) < 0)
+		goto out_err;
+
+	if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0)
+		goto out_err;
+
+	do {
+		link_detected = asix_mdio_read(dev, dev->phy_id, MII_BMSR) &
+			BMSR_LSTATUS;
+		if (!link_detected) {
+			if (timeout == 0)
+				printf("Waiting for Ethernet connection... ");
+			udelay(TIMEOUT_RESOLUTION * 1000);
+			timeout += TIMEOUT_RESOLUTION;
+		}
+	} while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
+	if (link_detected) {
+		if (timeout != 0)
+			printf("done.\n");
+	} else {
+		printf("unable to connect.\n");
+		goto out_err;
+	}
+
+	udelay(50000);
+	ax88178_link_reset(eth);
+	udelay(50000);
+
+	return 0;
+out_err:
+	return -1;
+}
+
+static int asix_init(struct eth_device *eth, bd_t *bd)
+{
+	struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+	switch (dev->asix_model) {
+	case ASIX_MODEL_AX88772 :
+		return asix_init_ax88772(eth, bd);
+		break;
+	case ASIX_MODEL_AX88178 :
+		return asix_init_ax88178(eth, bd);
+		break;
+	default:
+		printf("Unsupported asix model!\n");
+		return -1;
+	}
+}
+
 static int asix_send(struct eth_device *eth, volatile void *packet, int length)
 {
 	struct ueth_data *dev = (struct ueth_data *)eth->priv;
@@ -530,19 +735,21 @@  void asix_eth_before_probe(void)
 struct asix_dongle {
 	unsigned short vendor;
 	unsigned short product;
+	unsigned int asix_model;
 };
 
 static struct asix_dongle asix_dongles[] = {
-	{ 0x05ac, 0x1402 },	/* Apple USB Ethernet Adapter */
-	{ 0x07d1, 0x3c05 },	/* D-Link DUB-E100 H/W Ver B1 */
-	{ 0x0b95, 0x772a },	/* Cables-to-Go USB Ethernet Adapter */
-	{ 0x0b95, 0x7720 },	/* Trendnet TU2-ET100 V3.0R */
-	{ 0x0b95, 0x1720 },	/* SMC */
-	{ 0x0db0, 0xa877 },	/* MSI - ASIX 88772a */
-	{ 0x13b1, 0x0018 },	/* Linksys 200M v2.1 */
-	{ 0x1557, 0x7720 },	/* 0Q0 cable ethernet */
-	{ 0x2001, 0x3c05 },	/* DLink DUB-E100 H/W Ver B1 Alternate */
-	{ 0x0000, 0x0000 }	/* END - Do not remove */
+	{ 0x05ac, 0x1402, ASIX_MODEL_AX88772 },	/* Apple USB Ethernet Adapter */
+	{ 0x07d1, 0x3c05, ASIX_MODEL_AX88772 },	/* D-Link DUB-E100 H/W Ver B1 */
+	{ 0x0b95, 0x772a, ASIX_MODEL_AX88772 },	/* Cables-to-Go USB Ethernet Adapter */
+	{ 0x0b95, 0x7720, ASIX_MODEL_AX88772 },	/* Trendnet TU2-ET100 V3.0R */
+	{ 0x0b95, 0x1720, ASIX_MODEL_AX88772 },	/* SMC FIXME: isn't this AX88178? */
+	{ 0x0db0, 0xa877, ASIX_MODEL_AX88772 },	/* MSI - ASIX 88772a */
+	{ 0x13b1, 0x0018, ASIX_MODEL_AX88772 },	/* Linksys 200M v2.1 */
+	{ 0x1557, 0x7720, ASIX_MODEL_AX88772 },	/* 0Q0 cable ethernet */
+	{ 0x2001, 0x3c05, ASIX_MODEL_AX88772 },	/* DLink DUB-E100 H/W Ver B1 Alternate */
+	{ 0x050d, 0x5055, ASIX_MODEL_AX88178 },	/* Belkin F5D5055 Gig USB */
+	{ 0x0000, 0x0000, 0 }	/* END - Do not remove */
 };
 
 /* Probe to see if a new device is actually an asix device */
@@ -569,9 +776,12 @@  int asix_eth_probe(struct usb_device *dev, unsigned int ifnum,
 
 	memset(ss, 0, sizeof(struct ueth_data));
 
+	ss->asix_model = asix_dongles[i].asix_model;
+
 	/* At this point, we know we've got a live one */
-	debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
-	      dev->descriptor.idVendor, dev->descriptor.idProduct);
+	debug("\n\nUSB Ethernet device detected: %#04x:%#04x model AX88%s\n",
+	      dev->descriptor.idVendor, dev->descriptor.idProduct,
+	      ss->asix_model? "772" : "178");
 
 	/* Initialize the ueth_data structure with some useful info */
 	ss->ifnum = ifnum;
diff --git a/include/usb_ether.h b/include/usb_ether.h
index 825c275..28144f1 100644
--- a/include/usb_ether.h
+++ b/include/usb_ether.h
@@ -51,6 +51,7 @@  struct ueth_data {
 	unsigned char	irqinterval;	/* Intervall for IRQ Pipe */
 
 	/* private fields for each driver can go here if needed */
+	unsigned int	asix_model;
 };
 
 /*