2007-09-11 08:16:37 +00:00
|
|
|
/*
|
|
|
|
* SMSC LAN9[12]1[567] Network driver
|
|
|
|
*
|
|
|
|
* (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
|
|
|
|
*
|
|
|
|
* See file CREDITS for list of people who contributed to this
|
|
|
|
* project.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2007-10-18 19:02:02 +00:00
|
|
|
#ifdef CONFIG_ENABLE_DEVICE_NOISE
|
|
|
|
# define DEBUG
|
|
|
|
#endif
|
|
|
|
|
2007-09-11 08:16:37 +00:00
|
|
|
#include <common.h>
|
|
|
|
|
|
|
|
#include <command.h>
|
|
|
|
#include <net.h>
|
2010-08-26 16:33:28 +00:00
|
|
|
#include <miidev.h>
|
2007-09-11 08:16:37 +00:00
|
|
|
#include <malloc.h>
|
|
|
|
#include <init.h>
|
|
|
|
#include <xfuncs.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <clock.h>
|
2011-09-22 17:02:57 +00:00
|
|
|
#include <io.h>
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
|
2012-09-01 08:52:38 +00:00
|
|
|
#define AS CONFIG_DRIVER_NET_SMC911X_ADDRESS_SHIFT
|
|
|
|
#include "smc911x.h"
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
struct smc911x_priv {
|
2011-07-28 13:37:37 +00:00
|
|
|
struct eth_device edev;
|
2010-08-26 16:33:28 +00:00
|
|
|
struct mii_device miidev;
|
2011-07-28 13:35:56 +00:00
|
|
|
void __iomem *base;
|
2007-09-11 08:16:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct chip_id {
|
|
|
|
u16 id;
|
|
|
|
char *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct chip_id chip_ids[] = {
|
|
|
|
{ CHIP_9115, "LAN9115" },
|
|
|
|
{ CHIP_9116, "LAN9116" },
|
|
|
|
{ CHIP_9117, "LAN9117" },
|
|
|
|
{ CHIP_9118, "LAN9118" },
|
|
|
|
{ CHIP_9215, "LAN9215" },
|
|
|
|
{ CHIP_9216, "LAN9216" },
|
|
|
|
{ CHIP_9217, "LAN9217" },
|
|
|
|
{ CHIP_9218, "LAN9218" },
|
2011-03-24 17:55:19 +00:00
|
|
|
{ CHIP_9221, "LAN9221" },
|
2007-09-11 08:16:37 +00:00
|
|
|
{ 0, NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DRIVERNAME "smc911x"
|
|
|
|
|
|
|
|
static int smc911x_mac_wait_busy(struct smc911x_priv *priv)
|
|
|
|
{
|
|
|
|
uint64_t start = get_time_ns();
|
|
|
|
|
|
|
|
while (!is_timeout(start, MSECOND)) {
|
|
|
|
if (!(readl(priv->base + MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("%s: mac timeout\n", __FUNCTION__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 smc911x_get_mac_csr(struct eth_device *edev, u8 reg)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = edev->priv;
|
|
|
|
ulong val;
|
|
|
|
|
|
|
|
smc911x_mac_wait_busy(priv);
|
|
|
|
|
2007-09-12 14:57:01 +00:00
|
|
|
writel(MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg,
|
|
|
|
priv->base + MAC_CSR_CMD);
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
smc911x_mac_wait_busy(priv);
|
|
|
|
|
|
|
|
val = readl(priv->base + MAC_CSR_DATA);
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void smc911x_set_mac_csr(struct eth_device *edev, u8 reg, u32 data)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = edev->priv;
|
|
|
|
|
|
|
|
smc911x_mac_wait_busy(priv);
|
|
|
|
|
|
|
|
writel(data, priv->base + MAC_CSR_DATA);
|
|
|
|
writel(MAC_CSR_CMD_CSR_BUSY | reg, priv->base + MAC_CSR_CMD);
|
|
|
|
|
|
|
|
smc911x_mac_wait_busy(priv);
|
|
|
|
}
|
|
|
|
|
2007-10-18 09:17:16 +00:00
|
|
|
static int smc911x_get_ethaddr(struct eth_device *edev, unsigned char *m)
|
2007-09-11 08:16:37 +00:00
|
|
|
{
|
|
|
|
unsigned long addrh, addrl;
|
|
|
|
|
|
|
|
addrh = smc911x_get_mac_csr(edev, ADDRH);
|
|
|
|
addrl = smc911x_get_mac_csr(edev, ADDRL);
|
|
|
|
|
|
|
|
m[0] = (addrl ) & 0xff;
|
|
|
|
m[1] = (addrl >> 8 ) & 0xff;
|
|
|
|
m[2] = (addrl >> 16 ) & 0xff;
|
|
|
|
m[3] = (addrl >> 24 ) & 0xff;
|
|
|
|
m[4] = (addrh ) & 0xff;
|
|
|
|
m[5] = (addrh >> 8 ) & 0xff;
|
|
|
|
|
|
|
|
/* we get 0xff when there is no eeprom connected */
|
2007-09-12 14:57:01 +00:00
|
|
|
if ((m[0] & m[1] & m[2] & m[3] & m[4] & m[5]) == 0xff)
|
2007-09-11 08:16:37 +00:00
|
|
|
return -1;
|
2007-09-12 14:57:01 +00:00
|
|
|
|
2007-09-11 08:16:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-18 09:17:16 +00:00
|
|
|
static int smc911x_set_ethaddr(struct eth_device *edev, unsigned char *m)
|
2007-09-11 08:16:37 +00:00
|
|
|
{
|
|
|
|
unsigned long addrh, addrl;
|
|
|
|
|
|
|
|
addrl = m[0] | m[1] << 8 | m[2] << 16 | m[3] << 24;
|
|
|
|
addrh = m[4] | m[5] << 8;
|
|
|
|
smc911x_set_mac_csr(edev, ADDRH, addrh);
|
|
|
|
smc911x_set_mac_csr(edev, ADDRL, addrl);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-26 16:33:28 +00:00
|
|
|
static int smc911x_phy_read(struct mii_device *mdev, int phy_addr, int reg)
|
2007-09-11 08:16:37 +00:00
|
|
|
{
|
|
|
|
struct eth_device *edev = mdev->edev;
|
|
|
|
|
|
|
|
while (smc911x_get_mac_csr(edev, MII_ACC) & MII_ACC_MII_BUSY);
|
|
|
|
|
2007-09-12 14:57:01 +00:00
|
|
|
smc911x_set_mac_csr(edev, MII_ACC, phy_addr << 11 | reg << 6 |
|
|
|
|
MII_ACC_MII_BUSY);
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
while (smc911x_get_mac_csr(edev, MII_ACC) & MII_ACC_MII_BUSY);
|
|
|
|
|
2010-08-26 16:33:28 +00:00
|
|
|
return smc911x_get_mac_csr(edev, MII_DATA);
|
2007-09-11 08:16:37 +00:00
|
|
|
}
|
|
|
|
|
2010-08-26 16:33:28 +00:00
|
|
|
static int smc911x_phy_write(struct mii_device *mdev, int phy_addr,
|
|
|
|
int reg, int val)
|
2007-09-11 08:16:37 +00:00
|
|
|
{
|
|
|
|
struct eth_device *edev = mdev->edev;
|
|
|
|
|
|
|
|
while (smc911x_get_mac_csr(edev, MII_ACC) & MII_ACC_MII_BUSY);
|
|
|
|
|
|
|
|
smc911x_set_mac_csr(edev, MII_DATA, val);
|
|
|
|
smc911x_set_mac_csr(edev, MII_ACC,
|
2007-09-12 14:57:01 +00:00
|
|
|
phy_addr << 11 | reg << 6 | MII_ACC_MII_BUSY |
|
|
|
|
MII_ACC_MII_WRITE);
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
while (smc911x_get_mac_csr(edev, MII_ACC) & MII_ACC_MII_BUSY);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int smc911x_phy_reset(struct eth_device *edev)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = edev->priv;
|
|
|
|
u32 reg;
|
|
|
|
|
|
|
|
reg = readl(priv->base + PMT_CTRL);
|
2007-09-12 14:57:01 +00:00
|
|
|
reg &= 0xfcf;
|
2007-09-11 08:16:37 +00:00
|
|
|
reg |= PMT_CTRL_PHY_RST;
|
|
|
|
writel(reg, priv->base + PMT_CTRL);
|
|
|
|
|
|
|
|
mdelay(100);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void smc911x_reset(struct eth_device *edev)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = edev->priv;
|
|
|
|
uint64_t start;
|
|
|
|
|
|
|
|
/* Take out of PM setting first */
|
|
|
|
if (readl(priv->base + PMT_CTRL) & PMT_CTRL_READY) {
|
|
|
|
/* Write to the bytetest will take out of powerdown */
|
|
|
|
writel(0, priv->base + BYTE_TEST);
|
|
|
|
|
|
|
|
start = get_time_ns();
|
|
|
|
while(1) {
|
|
|
|
if ((readl(priv->base + PMT_CTRL) & PMT_CTRL_READY))
|
|
|
|
break;
|
|
|
|
if (is_timeout(start, 100 * USECOND)) {
|
2011-07-28 13:31:57 +00:00
|
|
|
dev_err(&edev->dev,
|
|
|
|
"timeout waiting for PM restore\n");
|
2007-09-11 08:16:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable interrupts */
|
|
|
|
writel(0, priv->base + INT_EN);
|
|
|
|
|
|
|
|
writel(HW_CFG_SRST, priv->base + HW_CFG);
|
|
|
|
|
|
|
|
start = get_time_ns();
|
|
|
|
while(1) {
|
|
|
|
if (!(readl(priv->base + E2P_CMD) & E2P_CMD_EPC_BUSY))
|
|
|
|
break;
|
|
|
|
if (is_timeout(start, 10 * MSECOND)) {
|
2011-07-28 13:31:57 +00:00
|
|
|
dev_err(&edev->dev, "reset timeout\n");
|
2007-09-11 08:16:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset the FIFO level and flow control settings */
|
|
|
|
smc911x_set_mac_csr(edev, FLOW, FLOW_FCPT | FLOW_FCEN);
|
|
|
|
|
|
|
|
writel(0x0050287F, priv->base + AFC_CFG);
|
|
|
|
|
|
|
|
/* Set to LED outputs */
|
|
|
|
writel(0x70070000, priv->base + GPIO_CFG);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void smc911x_enable(struct eth_device *edev)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = edev->priv;
|
|
|
|
|
|
|
|
/* Enable TX */
|
|
|
|
writel(8 << 16 | HW_CFG_SF, priv->base + HW_CFG);
|
|
|
|
|
|
|
|
writel(GPT_CFG_TIMER_EN | 10000, priv->base + GPT_CFG);
|
|
|
|
|
|
|
|
writel(TX_CFG_TX_ON, priv->base + TX_CFG);
|
|
|
|
|
|
|
|
/* no padding to start of packets */
|
2007-09-12 14:57:01 +00:00
|
|
|
writel(RX_CFG_RX_DUMP, priv->base + RX_CFG);
|
2007-09-11 08:16:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int smc911x_eth_open(struct eth_device *edev)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
|
|
|
|
|
2010-08-26 16:33:28 +00:00
|
|
|
miidev_wait_aneg(&priv->miidev);
|
|
|
|
miidev_print_status(&priv->miidev);
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
/* Turn on Tx + Rx */
|
|
|
|
smc911x_enable(edev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int smc911x_eth_send(struct eth_device *edev, void *packet, int length)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
|
|
|
|
u32 *data = (u32*)packet;
|
|
|
|
u32 tmplen;
|
|
|
|
u32 status;
|
2007-09-12 14:57:01 +00:00
|
|
|
uint64_t start;
|
2007-09-11 08:16:37 +00:00
|
|
|
|
2007-09-12 14:57:01 +00:00
|
|
|
writel(TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length,
|
|
|
|
priv->base + TX_DATA_FIFO);
|
2007-09-11 08:16:37 +00:00
|
|
|
writel(length, priv->base + TX_DATA_FIFO);
|
|
|
|
|
|
|
|
tmplen = (length + 3) / 4;
|
|
|
|
|
|
|
|
while(tmplen--)
|
|
|
|
writel(*data++, priv->base + TX_DATA_FIFO);
|
|
|
|
|
|
|
|
/* wait for transmission */
|
2007-09-12 14:57:01 +00:00
|
|
|
start = get_time_ns();
|
|
|
|
while (1) {
|
|
|
|
if ((readl(priv->base + TX_FIFO_INF) &
|
|
|
|
TX_FIFO_INF_TSUSED) >> 16)
|
|
|
|
break;
|
|
|
|
if (is_timeout(start, 100 * MSECOND)) {
|
2011-07-28 13:31:57 +00:00
|
|
|
dev_err(&edev->dev, "TX timeout\n");
|
2007-09-12 14:57:01 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
/* get status. Ignore 'no carrier' error, it has no meaning for
|
|
|
|
* full duplex operation
|
|
|
|
*/
|
2007-09-12 14:57:01 +00:00
|
|
|
status = readl(priv->base + TX_STATUS_FIFO) & (TX_STS_LOC |
|
|
|
|
TX_STS_LATE_COLL | TX_STS_MANY_COLL | TX_STS_MANY_DEFER |
|
|
|
|
TX_STS_UNDERRUN);
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
if(!status)
|
|
|
|
return 0;
|
|
|
|
|
2011-07-28 13:31:57 +00:00
|
|
|
dev_err(&edev->dev, "failed to send packet: %s%s%s%s%s\n",
|
2007-09-11 08:16:37 +00:00
|
|
|
status & TX_STS_LOC ? "TX_STS_LOC " : "",
|
|
|
|
status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "",
|
|
|
|
status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "",
|
|
|
|
status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "",
|
|
|
|
status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : "");
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void smc911x_eth_halt(struct eth_device *edev)
|
|
|
|
{
|
2007-09-12 14:57:01 +00:00
|
|
|
struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
|
|
|
|
|
|
|
|
/* Disable TX */
|
|
|
|
writel(TX_CFG_STOP_TX, priv->base + TX_CFG);
|
|
|
|
|
|
|
|
// smc911x_reset(edev);
|
2007-09-11 08:16:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int smc911x_eth_rx(struct eth_device *edev)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
|
|
|
|
u32 *data = (u32 *)NetRxPackets[0];
|
|
|
|
u32 pktlen, tmplen;
|
|
|
|
u32 status;
|
|
|
|
|
|
|
|
if((readl(priv->base + RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
|
|
|
|
status = readl(priv->base + RX_STATUS_FIFO);
|
|
|
|
pktlen = (status & RX_STS_PKT_LEN) >> 16;
|
|
|
|
|
|
|
|
writel(0, priv->base + RX_CFG);
|
|
|
|
|
2007-09-12 14:57:01 +00:00
|
|
|
tmplen = (pktlen + 2 + 3) / 4;
|
2007-09-11 08:16:37 +00:00
|
|
|
while(tmplen--)
|
|
|
|
*data++ = readl(priv->base + RX_DATA_FIFO);
|
|
|
|
|
|
|
|
if(status & RX_STS_ES)
|
2011-07-28 13:31:57 +00:00
|
|
|
dev_err(&edev->dev, "dropped bad packet. Status: 0x%08x\n",
|
2007-09-11 08:16:37 +00:00
|
|
|
status);
|
|
|
|
else
|
2010-06-02 13:59:16 +00:00
|
|
|
net_receive(NetRxPackets[0], pktlen);
|
2007-09-11 08:16:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int smc911x_init_dev(struct eth_device *edev)
|
|
|
|
{
|
|
|
|
struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
|
|
|
|
|
2007-09-12 14:57:01 +00:00
|
|
|
smc911x_set_mac_csr(edev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
|
|
|
|
MAC_CR_HBDIS);
|
|
|
|
|
2010-08-26 16:33:28 +00:00
|
|
|
miidev_restart_aneg(&priv->miidev);
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int smc911x_probe(struct device_d *dev)
|
|
|
|
{
|
|
|
|
struct eth_device *edev;
|
|
|
|
struct smc911x_priv *priv;
|
2011-01-07 10:36:20 +00:00
|
|
|
uint32_t val;
|
2007-09-11 08:16:37 +00:00
|
|
|
int i;
|
2012-06-22 10:58:11 +00:00
|
|
|
void __iomem *base;
|
2007-09-11 08:16:37 +00:00
|
|
|
|
2011-07-28 13:35:56 +00:00
|
|
|
base = dev_request_mem_region(dev, 0);
|
|
|
|
|
|
|
|
val = readl(base + BYTE_TEST);
|
2007-09-11 08:16:37 +00:00
|
|
|
if(val != 0x87654321) {
|
2011-07-28 13:35:56 +00:00
|
|
|
dev_err(dev, "no smc911x found on 0x%p (byte_test=0x%08x)\n",
|
|
|
|
base, val);
|
2007-09-11 08:16:37 +00:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2011-07-28 13:35:56 +00:00
|
|
|
val = readl(base + ID_REV) >> 16;
|
2007-09-11 08:16:37 +00:00
|
|
|
for(i = 0; chip_ids[i].id != 0; i++) {
|
|
|
|
if (chip_ids[i].id == val) break;
|
|
|
|
}
|
|
|
|
if (!chip_ids[i].id) {
|
2011-07-28 13:31:57 +00:00
|
|
|
dev_err(dev, "Unknown chip ID %04x\n", val);
|
2007-09-11 08:16:37 +00:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2011-07-28 13:31:57 +00:00
|
|
|
dev_info(dev, "detected %s controller\n", chip_ids[i].name);
|
2007-09-11 08:16:37 +00:00
|
|
|
|
2011-07-28 13:37:37 +00:00
|
|
|
priv = xzalloc(sizeof(*priv));
|
|
|
|
edev = &priv->edev;
|
|
|
|
edev->priv = priv;
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
edev->init = smc911x_init_dev;
|
|
|
|
edev->open = smc911x_eth_open;
|
|
|
|
edev->send = smc911x_eth_send;
|
|
|
|
edev->recv = smc911x_eth_rx;
|
|
|
|
edev->halt = smc911x_eth_halt;
|
2007-10-18 09:17:16 +00:00
|
|
|
edev->get_ethaddr = smc911x_get_ethaddr;
|
|
|
|
edev->set_ethaddr = smc911x_set_ethaddr;
|
2011-08-15 07:12:32 +00:00
|
|
|
edev->parent = dev;
|
2007-09-11 08:16:37 +00:00
|
|
|
|
2010-08-26 16:33:28 +00:00
|
|
|
priv->miidev.read = smc911x_phy_read;
|
|
|
|
priv->miidev.write = smc911x_phy_write;
|
|
|
|
priv->miidev.address = 1;
|
|
|
|
priv->miidev.flags = 0;
|
|
|
|
priv->miidev.edev = edev;
|
2011-08-15 07:30:46 +00:00
|
|
|
priv->miidev.parent = dev;
|
2011-07-28 13:35:56 +00:00
|
|
|
priv->base = base;
|
2007-09-11 08:16:37 +00:00
|
|
|
|
|
|
|
smc911x_reset(edev);
|
|
|
|
smc911x_phy_reset(edev);
|
|
|
|
|
2010-08-26 16:33:28 +00:00
|
|
|
mii_register(&priv->miidev);
|
2007-09-11 08:16:37 +00:00
|
|
|
eth_register(edev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct driver_d smc911x_driver = {
|
|
|
|
.name = "smc911x",
|
|
|
|
.probe = smc911x_probe,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int smc911x_init(void)
|
|
|
|
{
|
|
|
|
register_driver(&smc911x_driver);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
device_initcall(smc911x_init);
|
|
|
|
|