xref: /openbmc/linux/drivers/net/phy/at803x.c (revision e15bb4c6)
10ca7111aSMatus Ujhelyi /*
20ca7111aSMatus Ujhelyi  * drivers/net/phy/at803x.c
30ca7111aSMatus Ujhelyi  *
40ca7111aSMatus Ujhelyi  * Driver for Atheros 803x PHY
50ca7111aSMatus Ujhelyi  *
60ca7111aSMatus Ujhelyi  * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
70ca7111aSMatus Ujhelyi  *
80ca7111aSMatus Ujhelyi  * This program is free software; you can redistribute  it and/or modify it
90ca7111aSMatus Ujhelyi  * under  the terms of  the GNU General  Public License as published by the
100ca7111aSMatus Ujhelyi  * Free Software Foundation;  either version 2 of the  License, or (at your
110ca7111aSMatus Ujhelyi  * option) any later version.
120ca7111aSMatus Ujhelyi  */
130ca7111aSMatus Ujhelyi 
140ca7111aSMatus Ujhelyi #include <linux/phy.h>
150ca7111aSMatus Ujhelyi #include <linux/module.h>
160ca7111aSMatus Ujhelyi #include <linux/string.h>
170ca7111aSMatus Ujhelyi #include <linux/netdevice.h>
180ca7111aSMatus Ujhelyi #include <linux/etherdevice.h>
1913a56b44SDaniel Mack #include <linux/of_gpio.h>
2013a56b44SDaniel Mack #include <linux/gpio/consumer.h>
210ca7111aSMatus Ujhelyi 
220ca7111aSMatus Ujhelyi #define AT803X_INTR_ENABLE			0x12
230ca7111aSMatus Ujhelyi #define AT803X_INTR_STATUS			0x13
2413a56b44SDaniel Mack #define AT803X_SMART_SPEED			0x14
2513a56b44SDaniel Mack #define AT803X_LED_CONTROL			0x18
260ca7111aSMatus Ujhelyi #define AT803X_WOL_ENABLE			0x01
270ca7111aSMatus Ujhelyi #define AT803X_DEVICE_ADDR			0x03
280ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_0_15_OFFSET		0x804C
290ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_16_31_OFFSET	0x804B
300ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_32_47_OFFSET	0x804A
310ca7111aSMatus Ujhelyi #define AT803X_MMD_ACCESS_CONTROL		0x0D
320ca7111aSMatus Ujhelyi #define AT803X_MMD_ACCESS_CONTROL_DATA		0x0E
330ca7111aSMatus Ujhelyi #define AT803X_FUNC_DATA			0x4003
3477a99394SZhao Qiang #define AT803X_INER				0x0012
3577a99394SZhao Qiang #define AT803X_INER_INIT			0xec00
3677a99394SZhao Qiang #define AT803X_INSR				0x0013
371ca6d1b1SMugunthan V N #define AT803X_DEBUG_ADDR			0x1D
381ca6d1b1SMugunthan V N #define AT803X_DEBUG_DATA			0x1E
391ca6d1b1SMugunthan V N #define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
401ca6d1b1SMugunthan V N #define AT803X_DEBUG_RGMII_TX_CLK_DLY		BIT(8)
410ca7111aSMatus Ujhelyi 
42bd8ca17fSDaniel Mack #define ATH8030_PHY_ID 0x004dd076
43bd8ca17fSDaniel Mack #define ATH8031_PHY_ID 0x004dd074
44bd8ca17fSDaniel Mack #define ATH8035_PHY_ID 0x004dd072
45bd8ca17fSDaniel Mack 
460ca7111aSMatus Ujhelyi MODULE_DESCRIPTION("Atheros 803x PHY driver");
470ca7111aSMatus Ujhelyi MODULE_AUTHOR("Matus Ujhelyi");
480ca7111aSMatus Ujhelyi MODULE_LICENSE("GPL");
490ca7111aSMatus Ujhelyi 
5013a56b44SDaniel Mack struct at803x_priv {
5113a56b44SDaniel Mack 	bool phy_reset:1;
5213a56b44SDaniel Mack 	struct gpio_desc *gpiod_reset;
5313a56b44SDaniel Mack };
5413a56b44SDaniel Mack 
5513a56b44SDaniel Mack struct at803x_context {
5613a56b44SDaniel Mack 	u16 bmcr;
5713a56b44SDaniel Mack 	u16 advertise;
5813a56b44SDaniel Mack 	u16 control1000;
5913a56b44SDaniel Mack 	u16 int_enable;
6013a56b44SDaniel Mack 	u16 smart_speed;
6113a56b44SDaniel Mack 	u16 led_control;
6213a56b44SDaniel Mack };
6313a56b44SDaniel Mack 
6413a56b44SDaniel Mack /* save relevant PHY registers to private copy */
6513a56b44SDaniel Mack static void at803x_context_save(struct phy_device *phydev,
6613a56b44SDaniel Mack 				struct at803x_context *context)
6713a56b44SDaniel Mack {
6813a56b44SDaniel Mack 	context->bmcr = phy_read(phydev, MII_BMCR);
6913a56b44SDaniel Mack 	context->advertise = phy_read(phydev, MII_ADVERTISE);
7013a56b44SDaniel Mack 	context->control1000 = phy_read(phydev, MII_CTRL1000);
7113a56b44SDaniel Mack 	context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
7213a56b44SDaniel Mack 	context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
7313a56b44SDaniel Mack 	context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
7413a56b44SDaniel Mack }
7513a56b44SDaniel Mack 
7613a56b44SDaniel Mack /* restore relevant PHY registers from private copy */
7713a56b44SDaniel Mack static void at803x_context_restore(struct phy_device *phydev,
7813a56b44SDaniel Mack 				   const struct at803x_context *context)
7913a56b44SDaniel Mack {
8013a56b44SDaniel Mack 	phy_write(phydev, MII_BMCR, context->bmcr);
8113a56b44SDaniel Mack 	phy_write(phydev, MII_ADVERTISE, context->advertise);
8213a56b44SDaniel Mack 	phy_write(phydev, MII_CTRL1000, context->control1000);
8313a56b44SDaniel Mack 	phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
8413a56b44SDaniel Mack 	phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
8513a56b44SDaniel Mack 	phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
8613a56b44SDaniel Mack }
8713a56b44SDaniel Mack 
88ea13c9eeSMugunthan V N static int at803x_set_wol(struct phy_device *phydev,
89ea13c9eeSMugunthan V N 			  struct ethtool_wolinfo *wol)
900ca7111aSMatus Ujhelyi {
910ca7111aSMatus Ujhelyi 	struct net_device *ndev = phydev->attached_dev;
920ca7111aSMatus Ujhelyi 	const u8 *mac;
93ea13c9eeSMugunthan V N 	int ret;
94ea13c9eeSMugunthan V N 	u32 value;
950ca7111aSMatus Ujhelyi 	unsigned int i, offsets[] = {
960ca7111aSMatus Ujhelyi 		AT803X_LOC_MAC_ADDR_32_47_OFFSET,
970ca7111aSMatus Ujhelyi 		AT803X_LOC_MAC_ADDR_16_31_OFFSET,
980ca7111aSMatus Ujhelyi 		AT803X_LOC_MAC_ADDR_0_15_OFFSET,
990ca7111aSMatus Ujhelyi 	};
1000ca7111aSMatus Ujhelyi 
1010ca7111aSMatus Ujhelyi 	if (!ndev)
102ea13c9eeSMugunthan V N 		return -ENODEV;
1030ca7111aSMatus Ujhelyi 
104ea13c9eeSMugunthan V N 	if (wol->wolopts & WAKE_MAGIC) {
1050ca7111aSMatus Ujhelyi 		mac = (const u8 *) ndev->dev_addr;
1060ca7111aSMatus Ujhelyi 
1070ca7111aSMatus Ujhelyi 		if (!is_valid_ether_addr(mac))
108ea13c9eeSMugunthan V N 			return -EFAULT;
1090ca7111aSMatus Ujhelyi 
1100ca7111aSMatus Ujhelyi 		for (i = 0; i < 3; i++) {
1110ca7111aSMatus Ujhelyi 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
1120ca7111aSMatus Ujhelyi 				  AT803X_DEVICE_ADDR);
1130ca7111aSMatus Ujhelyi 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
1140ca7111aSMatus Ujhelyi 				  offsets[i]);
1150ca7111aSMatus Ujhelyi 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
1160ca7111aSMatus Ujhelyi 				  AT803X_FUNC_DATA);
1170ca7111aSMatus Ujhelyi 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
1180ca7111aSMatus Ujhelyi 				  mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
1190ca7111aSMatus Ujhelyi 		}
120ea13c9eeSMugunthan V N 
121ea13c9eeSMugunthan V N 		value = phy_read(phydev, AT803X_INTR_ENABLE);
122ea13c9eeSMugunthan V N 		value |= AT803X_WOL_ENABLE;
123ea13c9eeSMugunthan V N 		ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
124ea13c9eeSMugunthan V N 		if (ret)
125ea13c9eeSMugunthan V N 			return ret;
126ea13c9eeSMugunthan V N 		value = phy_read(phydev, AT803X_INTR_STATUS);
127ea13c9eeSMugunthan V N 	} else {
128ea13c9eeSMugunthan V N 		value = phy_read(phydev, AT803X_INTR_ENABLE);
129ea13c9eeSMugunthan V N 		value &= (~AT803X_WOL_ENABLE);
130ea13c9eeSMugunthan V N 		ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
131ea13c9eeSMugunthan V N 		if (ret)
132ea13c9eeSMugunthan V N 			return ret;
133ea13c9eeSMugunthan V N 		value = phy_read(phydev, AT803X_INTR_STATUS);
134ea13c9eeSMugunthan V N 	}
135ea13c9eeSMugunthan V N 
136ea13c9eeSMugunthan V N 	return ret;
137ea13c9eeSMugunthan V N }
138ea13c9eeSMugunthan V N 
139ea13c9eeSMugunthan V N static void at803x_get_wol(struct phy_device *phydev,
140ea13c9eeSMugunthan V N 			   struct ethtool_wolinfo *wol)
141ea13c9eeSMugunthan V N {
142ea13c9eeSMugunthan V N 	u32 value;
143ea13c9eeSMugunthan V N 
144ea13c9eeSMugunthan V N 	wol->supported = WAKE_MAGIC;
145ea13c9eeSMugunthan V N 	wol->wolopts = 0;
146ea13c9eeSMugunthan V N 
147ea13c9eeSMugunthan V N 	value = phy_read(phydev, AT803X_INTR_ENABLE);
148ea13c9eeSMugunthan V N 	if (value & AT803X_WOL_ENABLE)
149ea13c9eeSMugunthan V N 		wol->wolopts |= WAKE_MAGIC;
1500ca7111aSMatus Ujhelyi }
1510ca7111aSMatus Ujhelyi 
1526229ed1fSDaniel Mack static int at803x_suspend(struct phy_device *phydev)
1536229ed1fSDaniel Mack {
1546229ed1fSDaniel Mack 	int value;
1556229ed1fSDaniel Mack 	int wol_enabled;
1566229ed1fSDaniel Mack 
1576229ed1fSDaniel Mack 	mutex_lock(&phydev->lock);
1586229ed1fSDaniel Mack 
1596229ed1fSDaniel Mack 	value = phy_read(phydev, AT803X_INTR_ENABLE);
1606229ed1fSDaniel Mack 	wol_enabled = value & AT803X_WOL_ENABLE;
1616229ed1fSDaniel Mack 
1626229ed1fSDaniel Mack 	value = phy_read(phydev, MII_BMCR);
1636229ed1fSDaniel Mack 
1646229ed1fSDaniel Mack 	if (wol_enabled)
1656229ed1fSDaniel Mack 		value |= BMCR_ISOLATE;
1666229ed1fSDaniel Mack 	else
1676229ed1fSDaniel Mack 		value |= BMCR_PDOWN;
1686229ed1fSDaniel Mack 
1696229ed1fSDaniel Mack 	phy_write(phydev, MII_BMCR, value);
1706229ed1fSDaniel Mack 
1716229ed1fSDaniel Mack 	mutex_unlock(&phydev->lock);
1726229ed1fSDaniel Mack 
1736229ed1fSDaniel Mack 	return 0;
1746229ed1fSDaniel Mack }
1756229ed1fSDaniel Mack 
1766229ed1fSDaniel Mack static int at803x_resume(struct phy_device *phydev)
1776229ed1fSDaniel Mack {
1786229ed1fSDaniel Mack 	int value;
1796229ed1fSDaniel Mack 
1806229ed1fSDaniel Mack 	mutex_lock(&phydev->lock);
1816229ed1fSDaniel Mack 
1826229ed1fSDaniel Mack 	value = phy_read(phydev, MII_BMCR);
1836229ed1fSDaniel Mack 	value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
1846229ed1fSDaniel Mack 	phy_write(phydev, MII_BMCR, value);
1856229ed1fSDaniel Mack 
1866229ed1fSDaniel Mack 	mutex_unlock(&phydev->lock);
1876229ed1fSDaniel Mack 
1886229ed1fSDaniel Mack 	return 0;
1896229ed1fSDaniel Mack }
1906229ed1fSDaniel Mack 
19113a56b44SDaniel Mack static int at803x_probe(struct phy_device *phydev)
19213a56b44SDaniel Mack {
193e5a03bfdSAndrew Lunn 	struct device *dev = &phydev->mdio.dev;
19413a56b44SDaniel Mack 	struct at803x_priv *priv;
195687908c2SUwe Kleine-König 	struct gpio_desc *gpiod_reset;
19613a56b44SDaniel Mack 
1978f2877caSFengguang Wu 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
19813a56b44SDaniel Mack 	if (!priv)
19913a56b44SDaniel Mack 		return -ENOMEM;
20013a56b44SDaniel Mack 
201687908c2SUwe Kleine-König 	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
202687908c2SUwe Kleine-König 	if (IS_ERR(gpiod_reset))
203687908c2SUwe Kleine-König 		return PTR_ERR(gpiod_reset);
204687908c2SUwe Kleine-König 
205687908c2SUwe Kleine-König 	priv->gpiod_reset = gpiod_reset;
20613a56b44SDaniel Mack 
20713a56b44SDaniel Mack 	phydev->priv = priv;
20813a56b44SDaniel Mack 
20913a56b44SDaniel Mack 	return 0;
21013a56b44SDaniel Mack }
21113a56b44SDaniel Mack 
2120ca7111aSMatus Ujhelyi static int at803x_config_init(struct phy_device *phydev)
2130ca7111aSMatus Ujhelyi {
2141ca6d1b1SMugunthan V N 	int ret;
2150ca7111aSMatus Ujhelyi 
2166ff01dbbSDaniel Mack 	ret = genphy_config_init(phydev);
2176ff01dbbSDaniel Mack 	if (ret < 0)
2186ff01dbbSDaniel Mack 		return ret;
2190ca7111aSMatus Ujhelyi 
2201ca6d1b1SMugunthan V N 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
2211ca6d1b1SMugunthan V N 		ret = phy_write(phydev, AT803X_DEBUG_ADDR,
2221ca6d1b1SMugunthan V N 				AT803X_DEBUG_SYSTEM_MODE_CTRL);
2231ca6d1b1SMugunthan V N 		if (ret)
2241ca6d1b1SMugunthan V N 			return ret;
2251ca6d1b1SMugunthan V N 		ret = phy_write(phydev, AT803X_DEBUG_DATA,
2261ca6d1b1SMugunthan V N 				AT803X_DEBUG_RGMII_TX_CLK_DLY);
2271ca6d1b1SMugunthan V N 		if (ret)
2281ca6d1b1SMugunthan V N 			return ret;
2291ca6d1b1SMugunthan V N 	}
2301ca6d1b1SMugunthan V N 
2310ca7111aSMatus Ujhelyi 	return 0;
2320ca7111aSMatus Ujhelyi }
2330ca7111aSMatus Ujhelyi 
23477a99394SZhao Qiang static int at803x_ack_interrupt(struct phy_device *phydev)
23577a99394SZhao Qiang {
23677a99394SZhao Qiang 	int err;
23777a99394SZhao Qiang 
23877a99394SZhao Qiang 	err = phy_read(phydev, AT803X_INSR);
23977a99394SZhao Qiang 
24077a99394SZhao Qiang 	return (err < 0) ? err : 0;
24177a99394SZhao Qiang }
24277a99394SZhao Qiang 
24377a99394SZhao Qiang static int at803x_config_intr(struct phy_device *phydev)
24477a99394SZhao Qiang {
24577a99394SZhao Qiang 	int err;
24677a99394SZhao Qiang 	int value;
24777a99394SZhao Qiang 
24877a99394SZhao Qiang 	value = phy_read(phydev, AT803X_INER);
24977a99394SZhao Qiang 
25077a99394SZhao Qiang 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
25177a99394SZhao Qiang 		err = phy_write(phydev, AT803X_INER,
25277a99394SZhao Qiang 				value | AT803X_INER_INIT);
25377a99394SZhao Qiang 	else
25477a99394SZhao Qiang 		err = phy_write(phydev, AT803X_INER, 0);
25577a99394SZhao Qiang 
25677a99394SZhao Qiang 	return err;
25777a99394SZhao Qiang }
25877a99394SZhao Qiang 
25913a56b44SDaniel Mack static void at803x_link_change_notify(struct phy_device *phydev)
26013a56b44SDaniel Mack {
26113a56b44SDaniel Mack 	struct at803x_priv *priv = phydev->priv;
26213a56b44SDaniel Mack 
26313a56b44SDaniel Mack 	/*
26413a56b44SDaniel Mack 	 * Conduct a hardware reset for AT8030 every time a link loss is
26513a56b44SDaniel Mack 	 * signalled. This is necessary to circumvent a hardware bug that
26613a56b44SDaniel Mack 	 * occurs when the cable is unplugged while TX packets are pending
26713a56b44SDaniel Mack 	 * in the FIFO. In such cases, the FIFO enters an error mode it
26813a56b44SDaniel Mack 	 * cannot recover from by software.
26913a56b44SDaniel Mack 	 */
27013a56b44SDaniel Mack 	if (phydev->drv->phy_id == ATH8030_PHY_ID) {
27113a56b44SDaniel Mack 		if (phydev->state == PHY_NOLINK) {
27213a56b44SDaniel Mack 			if (priv->gpiod_reset && !priv->phy_reset) {
27313a56b44SDaniel Mack 				struct at803x_context context;
27413a56b44SDaniel Mack 
27513a56b44SDaniel Mack 				at803x_context_save(phydev, &context);
27613a56b44SDaniel Mack 
27713a56b44SDaniel Mack 				gpiod_set_value(priv->gpiod_reset, 0);
27813a56b44SDaniel Mack 				msleep(1);
27913a56b44SDaniel Mack 				gpiod_set_value(priv->gpiod_reset, 1);
28013a56b44SDaniel Mack 				msleep(1);
28113a56b44SDaniel Mack 
28213a56b44SDaniel Mack 				at803x_context_restore(phydev, &context);
28313a56b44SDaniel Mack 
28472ba48beSAndrew Lunn 				phydev_dbg(phydev, "%s(): phy was reset\n",
28513a56b44SDaniel Mack 					   __func__);
28613a56b44SDaniel Mack 				priv->phy_reset = true;
28713a56b44SDaniel Mack 			}
28813a56b44SDaniel Mack 		} else {
28913a56b44SDaniel Mack 			priv->phy_reset = false;
29013a56b44SDaniel Mack 		}
29113a56b44SDaniel Mack 	}
29213a56b44SDaniel Mack }
29313a56b44SDaniel Mack 
294317420abSMugunthan V N static struct phy_driver at803x_driver[] = {
295317420abSMugunthan V N {
2960ca7111aSMatus Ujhelyi 	/* ATHEROS 8035 */
297bd8ca17fSDaniel Mack 	.phy_id			= ATH8035_PHY_ID,
2980ca7111aSMatus Ujhelyi 	.name			= "Atheros 8035 ethernet",
2990ca7111aSMatus Ujhelyi 	.phy_id_mask		= 0xffffffef,
30013a56b44SDaniel Mack 	.probe			= at803x_probe,
3010ca7111aSMatus Ujhelyi 	.config_init		= at803x_config_init,
30213a56b44SDaniel Mack 	.link_change_notify	= at803x_link_change_notify,
303ea13c9eeSMugunthan V N 	.set_wol		= at803x_set_wol,
304ea13c9eeSMugunthan V N 	.get_wol		= at803x_get_wol,
3056229ed1fSDaniel Mack 	.suspend		= at803x_suspend,
3066229ed1fSDaniel Mack 	.resume			= at803x_resume,
3070ca7111aSMatus Ujhelyi 	.features		= PHY_GBIT_FEATURES,
3080ca7111aSMatus Ujhelyi 	.flags			= PHY_HAS_INTERRUPT,
3090197ffedSDaniel Mack 	.config_aneg		= genphy_config_aneg,
3100197ffedSDaniel Mack 	.read_status		= genphy_read_status,
3110eae5982SMåns Rullgård 	.ack_interrupt		= at803x_ack_interrupt,
3120eae5982SMåns Rullgård 	.config_intr		= at803x_config_intr,
313317420abSMugunthan V N }, {
3140ca7111aSMatus Ujhelyi 	/* ATHEROS 8030 */
315bd8ca17fSDaniel Mack 	.phy_id			= ATH8030_PHY_ID,
3160ca7111aSMatus Ujhelyi 	.name			= "Atheros 8030 ethernet",
3170ca7111aSMatus Ujhelyi 	.phy_id_mask		= 0xffffffef,
31813a56b44SDaniel Mack 	.probe			= at803x_probe,
3190ca7111aSMatus Ujhelyi 	.config_init		= at803x_config_init,
32013a56b44SDaniel Mack 	.link_change_notify	= at803x_link_change_notify,
321ea13c9eeSMugunthan V N 	.set_wol		= at803x_set_wol,
322ea13c9eeSMugunthan V N 	.get_wol		= at803x_get_wol,
3236229ed1fSDaniel Mack 	.suspend		= at803x_suspend,
3246229ed1fSDaniel Mack 	.resume			= at803x_resume,
325e15bb4c6SMartin Blumenstingl 	.features		= PHY_BASIC_FEATURES,
3260ca7111aSMatus Ujhelyi 	.flags			= PHY_HAS_INTERRUPT,
3270197ffedSDaniel Mack 	.config_aneg		= genphy_config_aneg,
3280197ffedSDaniel Mack 	.read_status		= genphy_read_status,
3290eae5982SMåns Rullgård 	.ack_interrupt		= at803x_ack_interrupt,
3300eae5982SMåns Rullgård 	.config_intr		= at803x_config_intr,
33105d7cce8SMugunthan V N }, {
33205d7cce8SMugunthan V N 	/* ATHEROS 8031 */
333bd8ca17fSDaniel Mack 	.phy_id			= ATH8031_PHY_ID,
33405d7cce8SMugunthan V N 	.name			= "Atheros 8031 ethernet",
33505d7cce8SMugunthan V N 	.phy_id_mask		= 0xffffffef,
33613a56b44SDaniel Mack 	.probe			= at803x_probe,
33705d7cce8SMugunthan V N 	.config_init		= at803x_config_init,
33813a56b44SDaniel Mack 	.link_change_notify	= at803x_link_change_notify,
33905d7cce8SMugunthan V N 	.set_wol		= at803x_set_wol,
34005d7cce8SMugunthan V N 	.get_wol		= at803x_get_wol,
3416229ed1fSDaniel Mack 	.suspend		= at803x_suspend,
3426229ed1fSDaniel Mack 	.resume			= at803x_resume,
34305d7cce8SMugunthan V N 	.features		= PHY_GBIT_FEATURES,
34405d7cce8SMugunthan V N 	.flags			= PHY_HAS_INTERRUPT,
3450197ffedSDaniel Mack 	.config_aneg		= genphy_config_aneg,
3460197ffedSDaniel Mack 	.read_status		= genphy_read_status,
34777a99394SZhao Qiang 	.ack_interrupt		= &at803x_ack_interrupt,
34877a99394SZhao Qiang 	.config_intr		= &at803x_config_intr,
349317420abSMugunthan V N } };
3500ca7111aSMatus Ujhelyi 
35150fd7150SJohan Hovold module_phy_driver(at803x_driver);
3520ca7111aSMatus Ujhelyi 
3530ca7111aSMatus Ujhelyi static struct mdio_device_id __maybe_unused atheros_tbl[] = {
354bd8ca17fSDaniel Mack 	{ ATH8030_PHY_ID, 0xffffffef },
355bd8ca17fSDaniel Mack 	{ ATH8031_PHY_ID, 0xffffffef },
356bd8ca17fSDaniel Mack 	{ ATH8035_PHY_ID, 0xffffffef },
3570ca7111aSMatus Ujhelyi 	{ }
3580ca7111aSMatus Ujhelyi };
3590ca7111aSMatus Ujhelyi 
3600ca7111aSMatus Ujhelyi MODULE_DEVICE_TABLE(mdio, atheros_tbl);
361