xref: /openbmc/linux/drivers/net/phy/ste10Xp.c (revision 3bdee6a8)
1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+
2f95be180SGiuseppe Cavallaro /*
3f95be180SGiuseppe Cavallaro  * drivers/net/phy/ste10Xp.c
4f95be180SGiuseppe Cavallaro  *
5f95be180SGiuseppe Cavallaro  * Driver for STMicroelectronics STe10Xp PHYs
6f95be180SGiuseppe Cavallaro  *
7f95be180SGiuseppe Cavallaro  * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
8f95be180SGiuseppe Cavallaro  *
9f95be180SGiuseppe Cavallaro  * Copyright (c) 2008 STMicroelectronics Limited
10f95be180SGiuseppe Cavallaro  */
11f95be180SGiuseppe Cavallaro 
12f95be180SGiuseppe Cavallaro #include <linux/module.h>
13f95be180SGiuseppe Cavallaro #include <linux/init.h>
14f95be180SGiuseppe Cavallaro #include <linux/sched.h>
15f95be180SGiuseppe Cavallaro #include <linux/kernel.h>
16f95be180SGiuseppe Cavallaro #include <linux/moduleparam.h>
17f95be180SGiuseppe Cavallaro #include <linux/interrupt.h>
18f95be180SGiuseppe Cavallaro #include <linux/netdevice.h>
19f95be180SGiuseppe Cavallaro #include <linux/ethtool.h>
20f95be180SGiuseppe Cavallaro #include <linux/mii.h>
21f95be180SGiuseppe Cavallaro #include <linux/phy.h>
22f95be180SGiuseppe Cavallaro 
23f95be180SGiuseppe Cavallaro #define MII_XCIIS	0x11	/* Configuration Info IRQ & Status Reg */
24f95be180SGiuseppe Cavallaro #define MII_XIE		0x12	/* Interrupt Enable Register */
25f95be180SGiuseppe Cavallaro #define MII_XIE_DEFAULT_MASK 0x0070 /* ANE complete, Remote Fault, Link Down */
26f95be180SGiuseppe Cavallaro 
27f95be180SGiuseppe Cavallaro #define STE101P_PHY_ID		0x00061c50
28f95be180SGiuseppe Cavallaro #define STE100P_PHY_ID		0x1c040011
29f95be180SGiuseppe Cavallaro 
ste10Xp_config_init(struct phy_device * phydev)30f95be180SGiuseppe Cavallaro static int ste10Xp_config_init(struct phy_device *phydev)
31f95be180SGiuseppe Cavallaro {
32f95be180SGiuseppe Cavallaro 	int value, err;
33f95be180SGiuseppe Cavallaro 
34f95be180SGiuseppe Cavallaro 	/* Software Reset PHY */
35f95be180SGiuseppe Cavallaro 	value = phy_read(phydev, MII_BMCR);
36f95be180SGiuseppe Cavallaro 	if (value < 0)
37f95be180SGiuseppe Cavallaro 		return value;
38f95be180SGiuseppe Cavallaro 
39f95be180SGiuseppe Cavallaro 	value |= BMCR_RESET;
40f95be180SGiuseppe Cavallaro 	err = phy_write(phydev, MII_BMCR, value);
41f95be180SGiuseppe Cavallaro 	if (err < 0)
42f95be180SGiuseppe Cavallaro 		return err;
43f95be180SGiuseppe Cavallaro 
44f95be180SGiuseppe Cavallaro 	do {
45f95be180SGiuseppe Cavallaro 		value = phy_read(phydev, MII_BMCR);
46f95be180SGiuseppe Cavallaro 	} while (value & BMCR_RESET);
47f95be180SGiuseppe Cavallaro 
48f95be180SGiuseppe Cavallaro 	return 0;
49f95be180SGiuseppe Cavallaro }
50f95be180SGiuseppe Cavallaro 
ste10Xp_ack_interrupt(struct phy_device * phydev)51f95be180SGiuseppe Cavallaro static int ste10Xp_ack_interrupt(struct phy_device *phydev)
52f95be180SGiuseppe Cavallaro {
53f95be180SGiuseppe Cavallaro 	int err = phy_read(phydev, MII_XCIIS);
54*e1bc534dSIoana Ciornei 
55f95be180SGiuseppe Cavallaro 	if (err < 0)
56f95be180SGiuseppe Cavallaro 		return err;
57f95be180SGiuseppe Cavallaro 
58f95be180SGiuseppe Cavallaro 	return 0;
59f95be180SGiuseppe Cavallaro }
60f95be180SGiuseppe Cavallaro 
ste10Xp_config_intr(struct phy_device * phydev)61*e1bc534dSIoana Ciornei static int ste10Xp_config_intr(struct phy_device *phydev)
62*e1bc534dSIoana Ciornei {
63*e1bc534dSIoana Ciornei 	int err;
64*e1bc534dSIoana Ciornei 
65*e1bc534dSIoana Ciornei 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
66*e1bc534dSIoana Ciornei 		/* clear any pending interrupts */
67*e1bc534dSIoana Ciornei 		err = ste10Xp_ack_interrupt(phydev);
68*e1bc534dSIoana Ciornei 		if (err)
69*e1bc534dSIoana Ciornei 			return err;
70*e1bc534dSIoana Ciornei 
71*e1bc534dSIoana Ciornei 		/* Enable all STe101P interrupts (PR12) */
72*e1bc534dSIoana Ciornei 		err = phy_write(phydev, MII_XIE, MII_XIE_DEFAULT_MASK);
73*e1bc534dSIoana Ciornei 	} else {
74*e1bc534dSIoana Ciornei 		err = phy_write(phydev, MII_XIE, 0);
75*e1bc534dSIoana Ciornei 		if (err)
76*e1bc534dSIoana Ciornei 			return err;
77*e1bc534dSIoana Ciornei 
78*e1bc534dSIoana Ciornei 		err = ste10Xp_ack_interrupt(phydev);
79*e1bc534dSIoana Ciornei 	}
80*e1bc534dSIoana Ciornei 
81*e1bc534dSIoana Ciornei 	return err;
82*e1bc534dSIoana Ciornei }
83*e1bc534dSIoana Ciornei 
ste10Xp_handle_interrupt(struct phy_device * phydev)8480ca9ee7SIoana Ciornei static irqreturn_t ste10Xp_handle_interrupt(struct phy_device *phydev)
8580ca9ee7SIoana Ciornei {
8680ca9ee7SIoana Ciornei 	int irq_status;
8780ca9ee7SIoana Ciornei 
8880ca9ee7SIoana Ciornei 	irq_status = phy_read(phydev, MII_XCIIS);
8980ca9ee7SIoana Ciornei 	if (irq_status < 0) {
9080ca9ee7SIoana Ciornei 		phy_error(phydev);
9180ca9ee7SIoana Ciornei 		return IRQ_NONE;
9280ca9ee7SIoana Ciornei 	}
9380ca9ee7SIoana Ciornei 
9480ca9ee7SIoana Ciornei 	if (!(irq_status & MII_XIE_DEFAULT_MASK))
9580ca9ee7SIoana Ciornei 		return IRQ_NONE;
9680ca9ee7SIoana Ciornei 
9780ca9ee7SIoana Ciornei 	phy_trigger_machine(phydev);
9880ca9ee7SIoana Ciornei 
9980ca9ee7SIoana Ciornei 	return IRQ_HANDLED;
10080ca9ee7SIoana Ciornei }
10180ca9ee7SIoana Ciornei 
102d5bf9071SChristian Hohnstaedt static struct phy_driver ste10xp_pdriver[] = {
103d5bf9071SChristian Hohnstaedt {
104f95be180SGiuseppe Cavallaro 	.phy_id = STE101P_PHY_ID,
105f95be180SGiuseppe Cavallaro 	.phy_id_mask = 0xfffffff0,
106f95be180SGiuseppe Cavallaro 	.name = "STe101p",
107dcdecdcfSHeiner Kallweit 	/* PHY_BASIC_FEATURES */
108f95be180SGiuseppe Cavallaro 	.config_init = ste10Xp_config_init,
109f95be180SGiuseppe Cavallaro 	.config_intr = ste10Xp_config_intr,
11080ca9ee7SIoana Ciornei 	.handle_interrupt = ste10Xp_handle_interrupt,
111f95be180SGiuseppe Cavallaro 	.suspend = genphy_suspend,
112f95be180SGiuseppe Cavallaro 	.resume = genphy_resume,
113d5bf9071SChristian Hohnstaedt }, {
114f95be180SGiuseppe Cavallaro 	.phy_id = STE100P_PHY_ID,
115f95be180SGiuseppe Cavallaro 	.phy_id_mask = 0xffffffff,
116f95be180SGiuseppe Cavallaro 	.name = "STe100p",
117dcdecdcfSHeiner Kallweit 	/* PHY_BASIC_FEATURES */
118f95be180SGiuseppe Cavallaro 	.config_init = ste10Xp_config_init,
119f95be180SGiuseppe Cavallaro 	.config_intr = ste10Xp_config_intr,
12080ca9ee7SIoana Ciornei 	.handle_interrupt = ste10Xp_handle_interrupt,
121f95be180SGiuseppe Cavallaro 	.suspend = genphy_suspend,
122f95be180SGiuseppe Cavallaro 	.resume = genphy_resume,
123d5bf9071SChristian Hohnstaedt } };
124f95be180SGiuseppe Cavallaro 
12550fd7150SJohan Hovold module_phy_driver(ste10xp_pdriver);
126f95be180SGiuseppe Cavallaro 
127cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused ste10Xp_tbl[] = {
1284e4f10f6SDavid Woodhouse 	{ STE101P_PHY_ID, 0xfffffff0 },
1294e4f10f6SDavid Woodhouse 	{ STE100P_PHY_ID, 0xffffffff },
1304e4f10f6SDavid Woodhouse 	{ }
1314e4f10f6SDavid Woodhouse };
1324e4f10f6SDavid Woodhouse 
1334e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, ste10Xp_tbl);
1344e4f10f6SDavid Woodhouse 
135f95be180SGiuseppe Cavallaro MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver");
136f95be180SGiuseppe Cavallaro MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
137f95be180SGiuseppe Cavallaro MODULE_LICENSE("GPL");
138