xref: /openbmc/linux/drivers/net/phy/at803x.c (revision a46bd63b)
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
23a46bd63bSMartin Blumenstingl #define AT803X_INTR_ENABLE_INIT			0xec00
240ca7111aSMatus Ujhelyi #define AT803X_INTR_STATUS			0x13
25a46bd63bSMartin Blumenstingl 
2613a56b44SDaniel Mack #define AT803X_SMART_SPEED			0x14
2713a56b44SDaniel Mack #define AT803X_LED_CONTROL			0x18
28a46bd63bSMartin Blumenstingl 
290ca7111aSMatus Ujhelyi #define AT803X_WOL_ENABLE			0x01
300ca7111aSMatus Ujhelyi #define AT803X_DEVICE_ADDR			0x03
310ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_0_15_OFFSET		0x804C
320ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_16_31_OFFSET	0x804B
330ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_32_47_OFFSET	0x804A
340ca7111aSMatus Ujhelyi #define AT803X_MMD_ACCESS_CONTROL		0x0D
350ca7111aSMatus Ujhelyi #define AT803X_MMD_ACCESS_CONTROL_DATA		0x0E
360ca7111aSMatus Ujhelyi #define AT803X_FUNC_DATA			0x4003
37a46bd63bSMartin Blumenstingl 
381ca6d1b1SMugunthan V N #define AT803X_DEBUG_ADDR			0x1D
391ca6d1b1SMugunthan V N #define AT803X_DEBUG_DATA			0x1E
40a46bd63bSMartin Blumenstingl 
412e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_REG_0			0x00
422e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_RX_CLK_DLY_EN		BIT(15)
43a46bd63bSMartin Blumenstingl 
442e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_REG_5			0x05
452e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_TX_CLK_DLY_EN		BIT(8)
460ca7111aSMatus Ujhelyi 
47bd8ca17fSDaniel Mack #define ATH8030_PHY_ID 0x004dd076
48bd8ca17fSDaniel Mack #define ATH8031_PHY_ID 0x004dd074
49bd8ca17fSDaniel Mack #define ATH8035_PHY_ID 0x004dd072
50bd8ca17fSDaniel Mack 
510ca7111aSMatus Ujhelyi MODULE_DESCRIPTION("Atheros 803x PHY driver");
520ca7111aSMatus Ujhelyi MODULE_AUTHOR("Matus Ujhelyi");
530ca7111aSMatus Ujhelyi MODULE_LICENSE("GPL");
540ca7111aSMatus Ujhelyi 
5513a56b44SDaniel Mack struct at803x_priv {
5613a56b44SDaniel Mack 	bool phy_reset:1;
5713a56b44SDaniel Mack 	struct gpio_desc *gpiod_reset;
5813a56b44SDaniel Mack };
5913a56b44SDaniel Mack 
6013a56b44SDaniel Mack struct at803x_context {
6113a56b44SDaniel Mack 	u16 bmcr;
6213a56b44SDaniel Mack 	u16 advertise;
6313a56b44SDaniel Mack 	u16 control1000;
6413a56b44SDaniel Mack 	u16 int_enable;
6513a56b44SDaniel Mack 	u16 smart_speed;
6613a56b44SDaniel Mack 	u16 led_control;
6713a56b44SDaniel Mack };
6813a56b44SDaniel Mack 
692e5f9f28SMartin Blumenstingl static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
702e5f9f28SMartin Blumenstingl {
712e5f9f28SMartin Blumenstingl 	int ret;
722e5f9f28SMartin Blumenstingl 
732e5f9f28SMartin Blumenstingl 	ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
742e5f9f28SMartin Blumenstingl 	if (ret < 0)
752e5f9f28SMartin Blumenstingl 		return ret;
762e5f9f28SMartin Blumenstingl 
772e5f9f28SMartin Blumenstingl 	return phy_read(phydev, AT803X_DEBUG_DATA);
782e5f9f28SMartin Blumenstingl }
792e5f9f28SMartin Blumenstingl 
802e5f9f28SMartin Blumenstingl static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
812e5f9f28SMartin Blumenstingl 				 u16 clear, u16 set)
822e5f9f28SMartin Blumenstingl {
832e5f9f28SMartin Blumenstingl 	u16 val;
842e5f9f28SMartin Blumenstingl 	int ret;
852e5f9f28SMartin Blumenstingl 
862e5f9f28SMartin Blumenstingl 	ret = at803x_debug_reg_read(phydev, reg);
872e5f9f28SMartin Blumenstingl 	if (ret < 0)
882e5f9f28SMartin Blumenstingl 		return ret;
892e5f9f28SMartin Blumenstingl 
902e5f9f28SMartin Blumenstingl 	val = ret & 0xffff;
912e5f9f28SMartin Blumenstingl 	val &= ~clear;
922e5f9f28SMartin Blumenstingl 	val |= set;
932e5f9f28SMartin Blumenstingl 
942e5f9f28SMartin Blumenstingl 	return phy_write(phydev, AT803X_DEBUG_DATA, val);
952e5f9f28SMartin Blumenstingl }
962e5f9f28SMartin Blumenstingl 
972e5f9f28SMartin Blumenstingl static inline int at803x_enable_rx_delay(struct phy_device *phydev)
982e5f9f28SMartin Blumenstingl {
992e5f9f28SMartin Blumenstingl 	return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
1002e5f9f28SMartin Blumenstingl 					AT803X_DEBUG_RX_CLK_DLY_EN);
1012e5f9f28SMartin Blumenstingl }
1022e5f9f28SMartin Blumenstingl 
1032e5f9f28SMartin Blumenstingl static inline int at803x_enable_tx_delay(struct phy_device *phydev)
1042e5f9f28SMartin Blumenstingl {
1052e5f9f28SMartin Blumenstingl 	return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
1062e5f9f28SMartin Blumenstingl 					AT803X_DEBUG_TX_CLK_DLY_EN);
1072e5f9f28SMartin Blumenstingl }
1082e5f9f28SMartin Blumenstingl 
10913a56b44SDaniel Mack /* save relevant PHY registers to private copy */
11013a56b44SDaniel Mack static void at803x_context_save(struct phy_device *phydev,
11113a56b44SDaniel Mack 				struct at803x_context *context)
11213a56b44SDaniel Mack {
11313a56b44SDaniel Mack 	context->bmcr = phy_read(phydev, MII_BMCR);
11413a56b44SDaniel Mack 	context->advertise = phy_read(phydev, MII_ADVERTISE);
11513a56b44SDaniel Mack 	context->control1000 = phy_read(phydev, MII_CTRL1000);
11613a56b44SDaniel Mack 	context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
11713a56b44SDaniel Mack 	context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
11813a56b44SDaniel Mack 	context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
11913a56b44SDaniel Mack }
12013a56b44SDaniel Mack 
12113a56b44SDaniel Mack /* restore relevant PHY registers from private copy */
12213a56b44SDaniel Mack static void at803x_context_restore(struct phy_device *phydev,
12313a56b44SDaniel Mack 				   const struct at803x_context *context)
12413a56b44SDaniel Mack {
12513a56b44SDaniel Mack 	phy_write(phydev, MII_BMCR, context->bmcr);
12613a56b44SDaniel Mack 	phy_write(phydev, MII_ADVERTISE, context->advertise);
12713a56b44SDaniel Mack 	phy_write(phydev, MII_CTRL1000, context->control1000);
12813a56b44SDaniel Mack 	phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
12913a56b44SDaniel Mack 	phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
13013a56b44SDaniel Mack 	phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
13113a56b44SDaniel Mack }
13213a56b44SDaniel Mack 
133ea13c9eeSMugunthan V N static int at803x_set_wol(struct phy_device *phydev,
134ea13c9eeSMugunthan V N 			  struct ethtool_wolinfo *wol)
1350ca7111aSMatus Ujhelyi {
1360ca7111aSMatus Ujhelyi 	struct net_device *ndev = phydev->attached_dev;
1370ca7111aSMatus Ujhelyi 	const u8 *mac;
138ea13c9eeSMugunthan V N 	int ret;
139ea13c9eeSMugunthan V N 	u32 value;
1400ca7111aSMatus Ujhelyi 	unsigned int i, offsets[] = {
1410ca7111aSMatus Ujhelyi 		AT803X_LOC_MAC_ADDR_32_47_OFFSET,
1420ca7111aSMatus Ujhelyi 		AT803X_LOC_MAC_ADDR_16_31_OFFSET,
1430ca7111aSMatus Ujhelyi 		AT803X_LOC_MAC_ADDR_0_15_OFFSET,
1440ca7111aSMatus Ujhelyi 	};
1450ca7111aSMatus Ujhelyi 
1460ca7111aSMatus Ujhelyi 	if (!ndev)
147ea13c9eeSMugunthan V N 		return -ENODEV;
1480ca7111aSMatus Ujhelyi 
149ea13c9eeSMugunthan V N 	if (wol->wolopts & WAKE_MAGIC) {
1500ca7111aSMatus Ujhelyi 		mac = (const u8 *) ndev->dev_addr;
1510ca7111aSMatus Ujhelyi 
1520ca7111aSMatus Ujhelyi 		if (!is_valid_ether_addr(mac))
153ea13c9eeSMugunthan V N 			return -EFAULT;
1540ca7111aSMatus Ujhelyi 
1550ca7111aSMatus Ujhelyi 		for (i = 0; i < 3; i++) {
1560ca7111aSMatus Ujhelyi 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
1570ca7111aSMatus Ujhelyi 				  AT803X_DEVICE_ADDR);
1580ca7111aSMatus Ujhelyi 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
1590ca7111aSMatus Ujhelyi 				  offsets[i]);
1600ca7111aSMatus Ujhelyi 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
1610ca7111aSMatus Ujhelyi 				  AT803X_FUNC_DATA);
1620ca7111aSMatus Ujhelyi 			phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
1630ca7111aSMatus Ujhelyi 				  mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
1640ca7111aSMatus Ujhelyi 		}
165ea13c9eeSMugunthan V N 
166ea13c9eeSMugunthan V N 		value = phy_read(phydev, AT803X_INTR_ENABLE);
167ea13c9eeSMugunthan V N 		value |= AT803X_WOL_ENABLE;
168ea13c9eeSMugunthan V N 		ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
169ea13c9eeSMugunthan V N 		if (ret)
170ea13c9eeSMugunthan V N 			return ret;
171ea13c9eeSMugunthan V N 		value = phy_read(phydev, AT803X_INTR_STATUS);
172ea13c9eeSMugunthan V N 	} else {
173ea13c9eeSMugunthan V N 		value = phy_read(phydev, AT803X_INTR_ENABLE);
174ea13c9eeSMugunthan V N 		value &= (~AT803X_WOL_ENABLE);
175ea13c9eeSMugunthan V N 		ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
176ea13c9eeSMugunthan V N 		if (ret)
177ea13c9eeSMugunthan V N 			return ret;
178ea13c9eeSMugunthan V N 		value = phy_read(phydev, AT803X_INTR_STATUS);
179ea13c9eeSMugunthan V N 	}
180ea13c9eeSMugunthan V N 
181ea13c9eeSMugunthan V N 	return ret;
182ea13c9eeSMugunthan V N }
183ea13c9eeSMugunthan V N 
184ea13c9eeSMugunthan V N static void at803x_get_wol(struct phy_device *phydev,
185ea13c9eeSMugunthan V N 			   struct ethtool_wolinfo *wol)
186ea13c9eeSMugunthan V N {
187ea13c9eeSMugunthan V N 	u32 value;
188ea13c9eeSMugunthan V N 
189ea13c9eeSMugunthan V N 	wol->supported = WAKE_MAGIC;
190ea13c9eeSMugunthan V N 	wol->wolopts = 0;
191ea13c9eeSMugunthan V N 
192ea13c9eeSMugunthan V N 	value = phy_read(phydev, AT803X_INTR_ENABLE);
193ea13c9eeSMugunthan V N 	if (value & AT803X_WOL_ENABLE)
194ea13c9eeSMugunthan V N 		wol->wolopts |= WAKE_MAGIC;
1950ca7111aSMatus Ujhelyi }
1960ca7111aSMatus Ujhelyi 
1976229ed1fSDaniel Mack static int at803x_suspend(struct phy_device *phydev)
1986229ed1fSDaniel Mack {
1996229ed1fSDaniel Mack 	int value;
2006229ed1fSDaniel Mack 	int wol_enabled;
2016229ed1fSDaniel Mack 
2026229ed1fSDaniel Mack 	mutex_lock(&phydev->lock);
2036229ed1fSDaniel Mack 
2046229ed1fSDaniel Mack 	value = phy_read(phydev, AT803X_INTR_ENABLE);
2056229ed1fSDaniel Mack 	wol_enabled = value & AT803X_WOL_ENABLE;
2066229ed1fSDaniel Mack 
2076229ed1fSDaniel Mack 	value = phy_read(phydev, MII_BMCR);
2086229ed1fSDaniel Mack 
2096229ed1fSDaniel Mack 	if (wol_enabled)
2106229ed1fSDaniel Mack 		value |= BMCR_ISOLATE;
2116229ed1fSDaniel Mack 	else
2126229ed1fSDaniel Mack 		value |= BMCR_PDOWN;
2136229ed1fSDaniel Mack 
2146229ed1fSDaniel Mack 	phy_write(phydev, MII_BMCR, value);
2156229ed1fSDaniel Mack 
2166229ed1fSDaniel Mack 	mutex_unlock(&phydev->lock);
2176229ed1fSDaniel Mack 
2186229ed1fSDaniel Mack 	return 0;
2196229ed1fSDaniel Mack }
2206229ed1fSDaniel Mack 
2216229ed1fSDaniel Mack static int at803x_resume(struct phy_device *phydev)
2226229ed1fSDaniel Mack {
2236229ed1fSDaniel Mack 	int value;
2246229ed1fSDaniel Mack 
2256229ed1fSDaniel Mack 	mutex_lock(&phydev->lock);
2266229ed1fSDaniel Mack 
2276229ed1fSDaniel Mack 	value = phy_read(phydev, MII_BMCR);
2286229ed1fSDaniel Mack 	value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
2296229ed1fSDaniel Mack 	phy_write(phydev, MII_BMCR, value);
2306229ed1fSDaniel Mack 
2316229ed1fSDaniel Mack 	mutex_unlock(&phydev->lock);
2326229ed1fSDaniel Mack 
2336229ed1fSDaniel Mack 	return 0;
2346229ed1fSDaniel Mack }
2356229ed1fSDaniel Mack 
23613a56b44SDaniel Mack static int at803x_probe(struct phy_device *phydev)
23713a56b44SDaniel Mack {
238e5a03bfdSAndrew Lunn 	struct device *dev = &phydev->mdio.dev;
23913a56b44SDaniel Mack 	struct at803x_priv *priv;
240687908c2SUwe Kleine-König 	struct gpio_desc *gpiod_reset;
24113a56b44SDaniel Mack 
2428f2877caSFengguang Wu 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
24313a56b44SDaniel Mack 	if (!priv)
24413a56b44SDaniel Mack 		return -ENOMEM;
24513a56b44SDaniel Mack 
246687908c2SUwe Kleine-König 	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
247687908c2SUwe Kleine-König 	if (IS_ERR(gpiod_reset))
248687908c2SUwe Kleine-König 		return PTR_ERR(gpiod_reset);
249687908c2SUwe Kleine-König 
250687908c2SUwe Kleine-König 	priv->gpiod_reset = gpiod_reset;
25113a56b44SDaniel Mack 
25213a56b44SDaniel Mack 	phydev->priv = priv;
25313a56b44SDaniel Mack 
25413a56b44SDaniel Mack 	return 0;
25513a56b44SDaniel Mack }
25613a56b44SDaniel Mack 
2570ca7111aSMatus Ujhelyi static int at803x_config_init(struct phy_device *phydev)
2580ca7111aSMatus Ujhelyi {
2591ca6d1b1SMugunthan V N 	int ret;
2600ca7111aSMatus Ujhelyi 
2616ff01dbbSDaniel Mack 	ret = genphy_config_init(phydev);
2626ff01dbbSDaniel Mack 	if (ret < 0)
2636ff01dbbSDaniel Mack 		return ret;
2640ca7111aSMatus Ujhelyi 
2652e5f9f28SMartin Blumenstingl 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
2662e5f9f28SMartin Blumenstingl 			phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
2672e5f9f28SMartin Blumenstingl 		ret = at803x_enable_rx_delay(phydev);
2682e5f9f28SMartin Blumenstingl 		if (ret < 0)
2691ca6d1b1SMugunthan V N 			return ret;
2702e5f9f28SMartin Blumenstingl 	}
2712e5f9f28SMartin Blumenstingl 
2722e5f9f28SMartin Blumenstingl 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
2732e5f9f28SMartin Blumenstingl 			phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
2742e5f9f28SMartin Blumenstingl 		ret = at803x_enable_tx_delay(phydev);
2752e5f9f28SMartin Blumenstingl 		if (ret < 0)
2761ca6d1b1SMugunthan V N 			return ret;
2771ca6d1b1SMugunthan V N 	}
2781ca6d1b1SMugunthan V N 
2790ca7111aSMatus Ujhelyi 	return 0;
2800ca7111aSMatus Ujhelyi }
2810ca7111aSMatus Ujhelyi 
28277a99394SZhao Qiang static int at803x_ack_interrupt(struct phy_device *phydev)
28377a99394SZhao Qiang {
28477a99394SZhao Qiang 	int err;
28577a99394SZhao Qiang 
286a46bd63bSMartin Blumenstingl 	err = phy_read(phydev, AT803X_INTR_STATUS);
28777a99394SZhao Qiang 
28877a99394SZhao Qiang 	return (err < 0) ? err : 0;
28977a99394SZhao Qiang }
29077a99394SZhao Qiang 
29177a99394SZhao Qiang static int at803x_config_intr(struct phy_device *phydev)
29277a99394SZhao Qiang {
29377a99394SZhao Qiang 	int err;
29477a99394SZhao Qiang 	int value;
29577a99394SZhao Qiang 
296a46bd63bSMartin Blumenstingl 	value = phy_read(phydev, AT803X_INTR_ENABLE);
29777a99394SZhao Qiang 
29877a99394SZhao Qiang 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
299a46bd63bSMartin Blumenstingl 		err = phy_write(phydev, AT803X_INTR_ENABLE,
300a46bd63bSMartin Blumenstingl 				value | AT803X_INTR_ENABLE_INIT);
30177a99394SZhao Qiang 	else
302a46bd63bSMartin Blumenstingl 		err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
30377a99394SZhao Qiang 
30477a99394SZhao Qiang 	return err;
30577a99394SZhao Qiang }
30677a99394SZhao Qiang 
30713a56b44SDaniel Mack static void at803x_link_change_notify(struct phy_device *phydev)
30813a56b44SDaniel Mack {
30913a56b44SDaniel Mack 	struct at803x_priv *priv = phydev->priv;
31013a56b44SDaniel Mack 
31113a56b44SDaniel Mack 	/*
31213a56b44SDaniel Mack 	 * Conduct a hardware reset for AT8030 every time a link loss is
31313a56b44SDaniel Mack 	 * signalled. This is necessary to circumvent a hardware bug that
31413a56b44SDaniel Mack 	 * occurs when the cable is unplugged while TX packets are pending
31513a56b44SDaniel Mack 	 * in the FIFO. In such cases, the FIFO enters an error mode it
31613a56b44SDaniel Mack 	 * cannot recover from by software.
31713a56b44SDaniel Mack 	 */
31813a56b44SDaniel Mack 	if (phydev->drv->phy_id == ATH8030_PHY_ID) {
31913a56b44SDaniel Mack 		if (phydev->state == PHY_NOLINK) {
32013a56b44SDaniel Mack 			if (priv->gpiod_reset && !priv->phy_reset) {
32113a56b44SDaniel Mack 				struct at803x_context context;
32213a56b44SDaniel Mack 
32313a56b44SDaniel Mack 				at803x_context_save(phydev, &context);
32413a56b44SDaniel Mack 
32513a56b44SDaniel Mack 				gpiod_set_value(priv->gpiod_reset, 0);
32613a56b44SDaniel Mack 				msleep(1);
32713a56b44SDaniel Mack 				gpiod_set_value(priv->gpiod_reset, 1);
32813a56b44SDaniel Mack 				msleep(1);
32913a56b44SDaniel Mack 
33013a56b44SDaniel Mack 				at803x_context_restore(phydev, &context);
33113a56b44SDaniel Mack 
33272ba48beSAndrew Lunn 				phydev_dbg(phydev, "%s(): phy was reset\n",
33313a56b44SDaniel Mack 					   __func__);
33413a56b44SDaniel Mack 				priv->phy_reset = true;
33513a56b44SDaniel Mack 			}
33613a56b44SDaniel Mack 		} else {
33713a56b44SDaniel Mack 			priv->phy_reset = false;
33813a56b44SDaniel Mack 		}
33913a56b44SDaniel Mack 	}
34013a56b44SDaniel Mack }
34113a56b44SDaniel Mack 
342317420abSMugunthan V N static struct phy_driver at803x_driver[] = {
343317420abSMugunthan V N {
3440ca7111aSMatus Ujhelyi 	/* ATHEROS 8035 */
345bd8ca17fSDaniel Mack 	.phy_id			= ATH8035_PHY_ID,
3460ca7111aSMatus Ujhelyi 	.name			= "Atheros 8035 ethernet",
3470ca7111aSMatus Ujhelyi 	.phy_id_mask		= 0xffffffef,
34813a56b44SDaniel Mack 	.probe			= at803x_probe,
3490ca7111aSMatus Ujhelyi 	.config_init		= at803x_config_init,
35013a56b44SDaniel Mack 	.link_change_notify	= at803x_link_change_notify,
351ea13c9eeSMugunthan V N 	.set_wol		= at803x_set_wol,
352ea13c9eeSMugunthan V N 	.get_wol		= at803x_get_wol,
3536229ed1fSDaniel Mack 	.suspend		= at803x_suspend,
3546229ed1fSDaniel Mack 	.resume			= at803x_resume,
3550ca7111aSMatus Ujhelyi 	.features		= PHY_GBIT_FEATURES,
3560ca7111aSMatus Ujhelyi 	.flags			= PHY_HAS_INTERRUPT,
3570197ffedSDaniel Mack 	.config_aneg		= genphy_config_aneg,
3580197ffedSDaniel Mack 	.read_status		= genphy_read_status,
3590eae5982SMåns Rullgård 	.ack_interrupt		= at803x_ack_interrupt,
3600eae5982SMåns Rullgård 	.config_intr		= at803x_config_intr,
361317420abSMugunthan V N }, {
3620ca7111aSMatus Ujhelyi 	/* ATHEROS 8030 */
363bd8ca17fSDaniel Mack 	.phy_id			= ATH8030_PHY_ID,
3640ca7111aSMatus Ujhelyi 	.name			= "Atheros 8030 ethernet",
3650ca7111aSMatus Ujhelyi 	.phy_id_mask		= 0xffffffef,
36613a56b44SDaniel Mack 	.probe			= at803x_probe,
3670ca7111aSMatus Ujhelyi 	.config_init		= at803x_config_init,
36813a56b44SDaniel Mack 	.link_change_notify	= at803x_link_change_notify,
369ea13c9eeSMugunthan V N 	.set_wol		= at803x_set_wol,
370ea13c9eeSMugunthan V N 	.get_wol		= at803x_get_wol,
3716229ed1fSDaniel Mack 	.suspend		= at803x_suspend,
3726229ed1fSDaniel Mack 	.resume			= at803x_resume,
373e15bb4c6SMartin Blumenstingl 	.features		= PHY_BASIC_FEATURES,
3740ca7111aSMatus Ujhelyi 	.flags			= PHY_HAS_INTERRUPT,
3750197ffedSDaniel Mack 	.config_aneg		= genphy_config_aneg,
3760197ffedSDaniel Mack 	.read_status		= genphy_read_status,
3770eae5982SMåns Rullgård 	.ack_interrupt		= at803x_ack_interrupt,
3780eae5982SMåns Rullgård 	.config_intr		= at803x_config_intr,
37905d7cce8SMugunthan V N }, {
38005d7cce8SMugunthan V N 	/* ATHEROS 8031 */
381bd8ca17fSDaniel Mack 	.phy_id			= ATH8031_PHY_ID,
38205d7cce8SMugunthan V N 	.name			= "Atheros 8031 ethernet",
38305d7cce8SMugunthan V N 	.phy_id_mask		= 0xffffffef,
38413a56b44SDaniel Mack 	.probe			= at803x_probe,
38505d7cce8SMugunthan V N 	.config_init		= at803x_config_init,
38613a56b44SDaniel Mack 	.link_change_notify	= at803x_link_change_notify,
38705d7cce8SMugunthan V N 	.set_wol		= at803x_set_wol,
38805d7cce8SMugunthan V N 	.get_wol		= at803x_get_wol,
3896229ed1fSDaniel Mack 	.suspend		= at803x_suspend,
3906229ed1fSDaniel Mack 	.resume			= at803x_resume,
39105d7cce8SMugunthan V N 	.features		= PHY_GBIT_FEATURES,
39205d7cce8SMugunthan V N 	.flags			= PHY_HAS_INTERRUPT,
3930197ffedSDaniel Mack 	.config_aneg		= genphy_config_aneg,
3940197ffedSDaniel Mack 	.read_status		= genphy_read_status,
39577a99394SZhao Qiang 	.ack_interrupt		= &at803x_ack_interrupt,
39677a99394SZhao Qiang 	.config_intr		= &at803x_config_intr,
397317420abSMugunthan V N } };
3980ca7111aSMatus Ujhelyi 
39950fd7150SJohan Hovold module_phy_driver(at803x_driver);
4000ca7111aSMatus Ujhelyi 
4010ca7111aSMatus Ujhelyi static struct mdio_device_id __maybe_unused atheros_tbl[] = {
402bd8ca17fSDaniel Mack 	{ ATH8030_PHY_ID, 0xffffffef },
403bd8ca17fSDaniel Mack 	{ ATH8031_PHY_ID, 0xffffffef },
404bd8ca17fSDaniel Mack 	{ ATH8035_PHY_ID, 0xffffffef },
4050ca7111aSMatus Ujhelyi 	{ }
4060ca7111aSMatus Ujhelyi };
4070ca7111aSMatus Ujhelyi 
4080ca7111aSMatus Ujhelyi MODULE_DEVICE_TABLE(mdio, atheros_tbl);
409