summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorDan Murphy <dmurphy@ti.com>2015-06-02 10:34:37 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-03 22:41:04 -0400
commit2a10154abcb75ad0d7b6bfea6210ac743ec60897 (patch)
tree6a622a29c4aa93bc029e5a5a1f17a57fb74d4aa3 /drivers/net/phy
parentf6b59f36b463ffdd82fc804f2772194eb8abd030 (diff)
net: phy: dp83867: Add TI dp83867 phy
Add support for the TI dp83867 Gigabit ethernet phy device. The DP83867 is a robust, low power, fully featured Physical Layer transceiver with integrated PMD sublayers to support 10BASE-T, 100BASE-TX and 1000BASE-T Ethernet protocols. Signed-off-by: Dan Murphy <dmurphy@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/dp83867.c239
3 files changed, 245 insertions, 1 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 7c0cb87d1f2f..cf18940f4e84 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -112,6 +112,11 @@ config MICREL_PHY
112 ---help--- 112 ---help---
113 Supports the KSZ9021, VSC8201, KS8001 PHYs. 113 Supports the KSZ9021, VSC8201, KS8001 PHYs.
114 114
115config DP83867_PHY
116 tristate "Drivers for Texas Instruments DP83867 Gigabit PHY"
117 ---help---
118 Currently supports the DP83867 PHY.
119
115config FIXED_PHY 120config FIXED_PHY
116 tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" 121 tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
117 depends on PHYLIB 122 depends on PHYLIB
@@ -205,7 +210,6 @@ config MDIO_BCM_UNIMAC
205 This hardware can be found in the Broadcom GENET Ethernet MAC 210 This hardware can be found in the Broadcom GENET Ethernet MAC
206 controllers as well as some Broadcom Ethernet switches such as the 211 controllers as well as some Broadcom Ethernet switches such as the
207 Starfighter 2 switches. 212 Starfighter 2 switches.
208
209endif # PHYLIB 213endif # PHYLIB
210 214
211config MICREL_KS8995MA 215config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index e97e7f921862..fcc25a0c45cd 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
22obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o 22obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
23obj-$(CONFIG_NATIONAL_PHY) += national.o 23obj-$(CONFIG_NATIONAL_PHY) += national.o
24obj-$(CONFIG_DP83640_PHY) += dp83640.o 24obj-$(CONFIG_DP83640_PHY) += dp83640.o
25obj-$(CONFIG_DP83867_PHY) += dp83867.o
25obj-$(CONFIG_STE10XP) += ste10Xp.o 26obj-$(CONFIG_STE10XP) += ste10Xp.o
26obj-$(CONFIG_MICREL_PHY) += micrel.o 27obj-$(CONFIG_MICREL_PHY) += micrel.o
27obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o 28obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
new file mode 100644
index 000000000000..ef0b4eb15f8d
--- /dev/null
+++ b/drivers/net/phy/dp83867.c
@@ -0,0 +1,239 @@
1/*
2 * Driver for the Texas Instruments DP83867 PHY
3 *
4 * Copyright (C) 2015 Texas Instruments Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/ethtool.h>
17#include <linux/kernel.h>
18#include <linux/mii.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/phy.h>
22
23#include <dt-bindings/net/ti-dp83867.h>
24
25#define DP83867_PHY_ID 0x2000a231
26#define DP83867_DEVADDR 0x1f
27
28#define MII_DP83867_PHYCTRL 0x10
29#define MII_DP83867_MICR 0x12
30#define MII_DP83867_ISR 0x13
31#define DP83867_CTRL 0x1f
32
33/* Extended Registers */
34#define DP83867_RGMIICTL 0x0032
35#define DP83867_RGMIIDCTL 0x0086
36
37#define DP83867_SW_RESET BIT(15)
38#define DP83867_SW_RESTART BIT(14)
39
40/* MICR Interrupt bits */
41#define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15)
42#define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14)
43#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13)
44#define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12)
45#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11)
46#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10)
47#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8)
48#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4)
49#define MII_DP83867_MICR_WOL_INT_EN BIT(3)
50#define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2)
51#define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1)
52#define MII_DP83867_MICR_JABBER_INT_EN BIT(0)
53
54/* RGMIICTL bits */
55#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
56#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
57
58/* PHY CTRL bits */
59#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
60
61/* RGMIIDCTL bits */
62#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
63
64struct dp83867_private {
65 int rx_id_delay;
66 int tx_id_delay;
67 int fifo_depth;
68};
69
70static int dp83867_ack_interrupt(struct phy_device *phydev)
71{
72 int err = phy_read(phydev, MII_DP83867_ISR);
73
74 if (err < 0)
75 return err;
76
77 return 0;
78}
79
80static int dp83867_config_intr(struct phy_device *phydev)
81{
82 int micr_status;
83
84 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
85 micr_status = phy_read(phydev, MII_DP83867_MICR);
86 if (micr_status < 0)
87 return micr_status;
88
89 micr_status |=
90 (MII_DP83867_MICR_AN_ERR_INT_EN |
91 MII_DP83867_MICR_SPEED_CHNG_INT_EN |
92 MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
93 MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
94
95 return phy_write(phydev, MII_DP83867_MICR, micr_status);
96 }
97
98 micr_status = 0x0;
99 return phy_write(phydev, MII_DP83867_MICR, micr_status);
100}
101
102#ifdef CONFIG_OF_MDIO
103static int dp83867_of_init(struct phy_device *phydev)
104{
105 struct dp83867_private *dp83867 = phydev->priv;
106 struct device *dev = &phydev->dev;
107 struct device_node *of_node = dev->of_node;
108 int ret;
109
110 if (!of_node && dev->parent->of_node)
111 of_node = dev->parent->of_node;
112
113 if (!phydev->dev.of_node)
114 return -ENODEV;
115
116 ret = of_property_read_u32(of_node, "ti,rx_int_delay",
117 &dp83867->rx_id_delay);
118 if (ret)
119 return ret;
120
121 ret = of_property_read_u32(of_node, "ti,tx_int_delay",
122 &dp83867->tx_id_delay);
123 if (ret)
124 return ret;
125
126 ret = of_property_read_u32(of_node, "ti,fifo_depth",
127 &dp83867->fifo_depth);
128 if (ret)
129 return ret;
130
131 return 0;
132}
133#else
134static int dp83867_of_init(struct phy_device *phydev)
135{
136 return 0;
137}
138#endif /* CONFIG_OF_MDIO */
139
140static int dp83867_config_init(struct phy_device *phydev)
141{
142 struct dp83867_private *dp83867;
143 int ret;
144 u16 val, delay;
145
146 if (!phydev->priv) {
147 dp83867 = devm_kzalloc(&phydev->dev, sizeof(*dp83867),
148 GFP_KERNEL);
149 if (!dp83867)
150 return -ENOMEM;
151
152 phydev->priv = dp83867;
153 ret = dp83867_of_init(phydev);
154 if (ret)
155 return ret;
156 } else {
157 dp83867 = (struct dp83867_private *)phydev->priv;
158 }
159
160 if (phy_interface_is_rgmii(phydev)) {
161 ret = phy_write(phydev, MII_DP83867_PHYCTRL,
162 (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT));
163 if (ret)
164 return ret;
165 }
166
167 if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) ||
168 (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
169 val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
170 DP83867_DEVADDR, phydev->addr);
171
172 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
173 val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
174
175 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
176 val |= DP83867_RGMII_TX_CLK_DELAY_EN;
177
178 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
179 val |= DP83867_RGMII_RX_CLK_DELAY_EN;
180
181 phy_write_mmd_indirect(phydev, DP83867_RGMIICTL,
182 DP83867_DEVADDR, phydev->addr, val);
183
184 delay = (dp83867->rx_id_delay |
185 (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
186
187 phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL,
188 DP83867_DEVADDR, phydev->addr, delay);
189 }
190
191 return 0;
192}
193
194static int dp83867_phy_reset(struct phy_device *phydev)
195{
196 int err;
197
198 err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESET);
199 if (err < 0)
200 return err;
201
202 return dp83867_config_init(phydev);
203}
204
205static struct phy_driver dp83867_driver[] = {
206 {
207 .phy_id = DP83867_PHY_ID,
208 .phy_id_mask = 0xfffffff0,
209 .name = "TI DP83867",
210 .features = PHY_GBIT_FEATURES,
211 .flags = PHY_HAS_INTERRUPT,
212
213 .config_init = dp83867_config_init,
214 .soft_reset = dp83867_phy_reset,
215
216 /* IRQ related */
217 .ack_interrupt = dp83867_ack_interrupt,
218 .config_intr = dp83867_config_intr,
219
220 .config_aneg = genphy_config_aneg,
221 .read_status = genphy_read_status,
222 .suspend = genphy_suspend,
223 .resume = genphy_resume,
224
225 .driver = {.owner = THIS_MODULE,}
226 },
227};
228module_phy_driver(dp83867_driver);
229
230static struct mdio_device_id __maybe_unused dp83867_tbl[] = {
231 { DP83867_PHY_ID, 0xfffffff0 },
232 { }
233};
234
235MODULE_DEVICE_TABLE(mdio, dp83867_tbl);
236
237MODULE_DESCRIPTION("Texas Instruments DP83867 PHY driver");
238MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
239MODULE_LICENSE("GPL");