1d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi/*
2d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi * drivers/net/phy/micrel.c
3d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi *
4d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi * Driver for Micrel PHYs
5d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi *
6d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi * Author: David J. Choi
7d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi *
8d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi * Copyright (c) 2010 Micrel, Inc.
9d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi *
10d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi * This program is free software; you can redistribute  it and/or modify it
11d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi * under  the terms of  the GNU General  Public License as published by the
12d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi * Free Software Foundation;  either version 2 of the  License, or (at your
13d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi * option) any later version.
14d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi *
1551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David * Support : ksz9021 1000/100/10 phy from Micrel
1651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David *		ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
17d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi */
18d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
19d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi#include <linux/kernel.h>
20d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi#include <linux/module.h>
21d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi#include <linux/phy.h>
22d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach#include <linux/micrel_phy.h>
23d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
2451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David/* general Interrupt control/status reg in vendor specific block. */
2551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define MII_KSZPHY_INTCS			0x1B
2651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_JABBER			(1 << 15)
2751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_RECEIVE_ERR		(1 << 14)
2851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_PAGE_RECEIVE		(1 << 13)
2951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_PARELLEL			(1 << 12)
3051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_LINK_PARTNER_ACK		(1 << 11)
3151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_LINK_DOWN			(1 << 10)
3251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_REMOTE_FAULT		(1 << 9)
3351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_LINK_UP			(1 << 8)
3451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	KSZPHY_INTCS_ALL			(KSZPHY_INTCS_LINK_UP |\
3551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David						KSZPHY_INTCS_LINK_DOWN)
3651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
3751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David/* general PHY control reg in vendor specific block. */
3851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define	MII_KSZPHY_CTRL			0x1F
3951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David/* bitmap of PHY register to set interrupt mode */
4051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define KSZPHY_CTRL_INT_ACTIVE_HIGH		(1 << 9)
4151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define KSZ9021_CTRL_INT_ACTIVE_HIGH		(1 << 14)
4251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David#define KS8737_CTRL_INT_ACTIVE_HIGH		(1 << 14)
43d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach#define KSZ8051_RMII_50MHZ_CLK			(1 << 7)
4451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
4551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic int kszphy_ack_interrupt(struct phy_device *phydev)
4651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David{
4751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	/* bit[7..0] int status, which is a read and clear register. */
4851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	int rc;
4951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
5051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	rc = phy_read(phydev, MII_KSZPHY_INTCS);
5151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
5251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	return (rc < 0) ? rc : 0;
5351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David}
5451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
5551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic int kszphy_set_interrupt(struct phy_device *phydev)
5651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David{
5751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	int temp;
5851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ?
5951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David		KSZPHY_INTCS_ALL : 0;
6051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	return phy_write(phydev, MII_KSZPHY_INTCS, temp);
6151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David}
6251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
6351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic int kszphy_config_intr(struct phy_device *phydev)
6451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David{
6551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	int temp, rc;
6651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
6751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	/* set the interrupt pin active low */
6851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	temp = phy_read(phydev, MII_KSZPHY_CTRL);
6951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
7051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_write(phydev, MII_KSZPHY_CTRL, temp);
7151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	rc = kszphy_set_interrupt(phydev);
7251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	return rc < 0 ? rc : 0;
7351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David}
7451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
7551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic int ksz9021_config_intr(struct phy_device *phydev)
7651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David{
7751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	int temp, rc;
7851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
7951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	/* set the interrupt pin active low */
8051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	temp = phy_read(phydev, MII_KSZPHY_CTRL);
8151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
8251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_write(phydev, MII_KSZPHY_CTRL, temp);
8351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	rc = kszphy_set_interrupt(phydev);
8451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	return rc < 0 ? rc : 0;
8551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David}
8651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
8751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic int ks8737_config_intr(struct phy_device *phydev)
8851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David{
8951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	int temp, rc;
9051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
9151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	/* set the interrupt pin active low */
9251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	temp = phy_read(phydev, MII_KSZPHY_CTRL);
9351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
9451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_write(phydev, MII_KSZPHY_CTRL, temp);
9551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	rc = kszphy_set_interrupt(phydev);
9651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	return rc < 0 ? rc : 0;
9751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David}
98d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
99d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choistatic int kszphy_config_init(struct phy_device *phydev)
100d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi{
101d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	return 0;
102d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi}
103d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
104d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siachstatic int ks8051_config_init(struct phy_device *phydev)
105d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach{
106d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach	int regval;
107d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach
108d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach	if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
109d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach		regval = phy_read(phydev, MII_KSZPHY_CTRL);
110d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach		regval |= KSZ8051_RMII_50MHZ_CLK;
111d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach		phy_write(phydev, MII_KSZPHY_CTRL, regval);
112d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach	}
113d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach
114d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach	return 0;
115d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach}
116d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach
11751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic struct phy_driver ks8737_driver = {
11851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.phy_id		= PHY_ID_KS8737,
11951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.phy_id_mask	= 0x00fffff0,
12051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.name		= "Micrel KS8737",
12151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
12251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
12351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_init	= kszphy_config_init,
12451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_aneg	= genphy_config_aneg,
12551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.read_status	= genphy_read_status,
12651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.ack_interrupt	= kszphy_ack_interrupt,
12751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_intr	= ks8737_config_intr,
12851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.driver		= { .owner = THIS_MODULE,},
12951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David};
13051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
13151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic struct phy_driver ks8041_driver = {
13251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.phy_id		= PHY_ID_KS8041,
13351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.phy_id_mask	= 0x00fffff0,
13451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.name		= "Micrel KS8041",
13551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
13651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David				| SUPPORTED_Asym_Pause),
13751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
13851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_init	= kszphy_config_init,
13951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_aneg	= genphy_config_aneg,
14051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.read_status	= genphy_read_status,
14151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.ack_interrupt	= kszphy_ack_interrupt,
14251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_intr	= kszphy_config_intr,
14351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.driver		= { .owner = THIS_MODULE,},
14451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David};
145d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
14651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic struct phy_driver ks8051_driver = {
14751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.phy_id		= PHY_ID_KS8051,
148d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.phy_id_mask	= 0x00fffff0,
14951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.name		= "Micrel KS8051",
15051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
15151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David				| SUPPORTED_Asym_Pause),
15251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
153d606ef3fe0c57504b8e534c58498f73a6abc049aBaruch Siach	.config_init	= ks8051_config_init,
154d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.config_aneg	= genphy_config_aneg,
155d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.read_status	= genphy_read_status,
15651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.ack_interrupt	= kszphy_ack_interrupt,
15751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_intr	= kszphy_config_intr,
158d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.driver		= { .owner = THIS_MODULE,},
159d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi};
160d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
16151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Davidstatic struct phy_driver ks8001_driver = {
16251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.phy_id		= PHY_ID_KS8001,
16351f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.name		= "Micrel KS8001 or KS8721",
164d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.phy_id_mask	= 0x00fffff0,
16551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
16651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
167d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.config_init	= kszphy_config_init,
168d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.config_aneg	= genphy_config_aneg,
169d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.read_status	= genphy_read_status,
17051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.ack_interrupt	= kszphy_ack_interrupt,
17151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_intr	= kszphy_config_intr,
172d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.driver		= { .owner = THIS_MODULE,},
173d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi};
174d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
175d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choistatic struct phy_driver ksz9021_driver = {
176d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.phy_id		= PHY_ID_KSZ9021,
177d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.phy_id_mask	= 0x000fff10,
178d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.name		= "Micrel KSZ9021 Gigabit PHY",
17951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause
18051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David				| SUPPORTED_Asym_Pause),
18151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
182d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.config_init	= kszphy_config_init,
183d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.config_aneg	= genphy_config_aneg,
184d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.read_status	= genphy_read_status,
18551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.ack_interrupt	= kszphy_ack_interrupt,
18651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	.config_intr	= ksz9021_config_intr,
187d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	.driver		= { .owner = THIS_MODULE, },
188d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi};
189d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
190d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choistatic int __init ksphy_init(void)
191d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi{
192d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	int ret;
193d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
194d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	ret = phy_driver_register(&ks8001_driver);
195d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	if (ret)
196d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi		goto err1;
19751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
19851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	ret = phy_driver_register(&ksz9021_driver);
199d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	if (ret)
200d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi		goto err2;
201d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
20251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	ret = phy_driver_register(&ks8737_driver);
203d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	if (ret)
204d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi		goto err3;
20551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	ret = phy_driver_register(&ks8041_driver);
20651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	if (ret)
20751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David		goto err4;
20851f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	ret = phy_driver_register(&ks8051_driver);
20951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	if (ret)
21051f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David		goto err5;
21151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David
212d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	return 0;
213d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
21451f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Daviderr5:
21551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_driver_unregister(&ks8041_driver);
21651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, Daviderr4:
21751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_driver_unregister(&ks8737_driver);
218d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choierr3:
21951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_driver_unregister(&ksz9021_driver);
220d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choierr2:
221d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	phy_driver_unregister(&ks8001_driver);
222d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choierr1:
223d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	return ret;
224d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi}
225d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
226d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choistatic void __exit ksphy_exit(void)
227d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi{
228d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	phy_driver_unregister(&ks8001_driver);
22951f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_driver_unregister(&ks8737_driver);
230d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi	phy_driver_unregister(&ksz9021_driver);
23151f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_driver_unregister(&ks8041_driver);
23251f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	phy_driver_unregister(&ks8051_driver);
233d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi}
234d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
235d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choimodule_init(ksphy_init);
236d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choimodule_exit(ksphy_exit);
237d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. Choi
238d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. ChoiMODULE_DESCRIPTION("Micrel PHY driver");
239d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. ChoiMODULE_AUTHOR("David J. Choi");
240d05070091849015f8c5b7d55cd75b86ebb61b3ecDavid J. ChoiMODULE_LICENSE("GPL");
24152a60ed2da716105de5f906a3630c475264b87d5David S. Miller
242cf93c94581bab447a5634c6d737c1cf38c080261Uwe Kleine-Königstatic struct mdio_device_id __maybe_unused micrel_tbl[] = {
24352a60ed2da716105de5f906a3630c475264b87d5David S. Miller	{ PHY_ID_KSZ9021, 0x000fff10 },
24452a60ed2da716105de5f906a3630c475264b87d5David S. Miller	{ PHY_ID_KS8001, 0x00fffff0 },
24551f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	{ PHY_ID_KS8737, 0x00fffff0 },
24651f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	{ PHY_ID_KS8041, 0x00fffff0 },
24751f932c4870f785d73d5fd5fed33306e63cf4efcChoi, David	{ PHY_ID_KS8051, 0x00fffff0 },
24852a60ed2da716105de5f906a3630c475264b87d5David S. Miller	{ }
24952a60ed2da716105de5f906a3630c475264b87d5David S. Miller};
25052a60ed2da716105de5f906a3630c475264b87d5David S. Miller
25152a60ed2da716105de5f906a3630c475264b87d5David S. MillerMODULE_DEVICE_TABLE(mdio, micrel_tbl);
252