blob: 59051b0f5be9132f84f8928cf65e67c66f0eed51 [file] [log] [blame]
Andrew Lunn5f857572019-01-21 19:10:19 +01001// SPDX-License-Identifier: GPL-2.0
Dan Murphy2a101542015-06-02 09:34:37 -05002/*
3 * Driver for the Texas Instruments DP83867 PHY
4 *
5 * Copyright (C) 2015 Texas Instruments Inc.
Dan Murphy2a101542015-06-02 09:34:37 -05006 */
7
8#include <linux/ethtool.h>
9#include <linux/kernel.h>
10#include <linux/mii.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/phy.h>
Max Uvarov72a7d452019-02-25 12:15:10 +030014#include <linux/delay.h>
Dan Murphy2a101542015-06-02 09:34:37 -050015
16#include <dt-bindings/net/ti-dp83867.h>
17
18#define DP83867_PHY_ID 0x2000a231
19#define DP83867_DEVADDR 0x1f
20
21#define MII_DP83867_PHYCTRL 0x10
22#define MII_DP83867_MICR 0x12
23#define MII_DP83867_ISR 0x13
24#define DP83867_CTRL 0x1f
Grygorii Strashko5ca7d1c2017-01-05 14:48:07 -060025#define DP83867_CFG3 0x1e
Dan Murphy2a101542015-06-02 09:34:37 -050026
27/* Extended Registers */
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +010028#define DP83867_CFG4 0x0031
Dan Murphy2a101542015-06-02 09:34:37 -050029#define DP83867_RGMIICTL 0x0032
Lukasz Majewskiac6e0582017-02-07 06:20:24 +010030#define DP83867_STRAP_STS1 0x006E
Trent Piephoc11669a2019-05-22 18:43:23 +000031#define DP83867_STRAP_STS2 0x006f
Dan Murphy2a101542015-06-02 09:34:37 -050032#define DP83867_RGMIIDCTL 0x0086
Mugunthan V Ned838fe2016-10-18 16:50:18 +053033#define DP83867_IO_MUX_CFG 0x0170
Dan Murphy2a101542015-06-02 09:34:37 -050034
35#define DP83867_SW_RESET BIT(15)
36#define DP83867_SW_RESTART BIT(14)
37
38/* MICR Interrupt bits */
39#define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15)
40#define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14)
41#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13)
42#define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12)
43#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11)
44#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10)
45#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8)
46#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4)
47#define MII_DP83867_MICR_WOL_INT_EN BIT(3)
48#define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2)
49#define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1)
50#define MII_DP83867_MICR_JABBER_INT_EN BIT(0)
51
52/* RGMIICTL bits */
53#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
54#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
55
Lukasz Majewskiac6e0582017-02-07 06:20:24 +010056/* STRAP_STS1 bits */
57#define DP83867_STRAP_STS1_RESERVED BIT(11)
58
Trent Piephoc11669a2019-05-22 18:43:23 +000059/* STRAP_STS2 bits */
60#define DP83867_STRAP_STS2_CLK_SKEW_TX_MASK GENMASK(6, 4)
61#define DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT 4
62#define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK GENMASK(2, 0)
63#define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT 0
64#define DP83867_STRAP_STS2_CLK_SKEW_NONE BIT(2)
65
Dan Murphy2a101542015-06-02 09:34:37 -050066/* PHY CTRL bits */
67#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
Stefan Hauserb291c412016-07-01 22:35:03 +020068#define DP83867_PHYCR_FIFO_DEPTH_MASK (3 << 14)
Lukasz Majewskiac6e0582017-02-07 06:20:24 +010069#define DP83867_PHYCR_RESERVED_MASK BIT(11)
Dan Murphy2a101542015-06-02 09:34:37 -050070
71/* RGMIIDCTL bits */
Trent Piephoc11669a2019-05-22 18:43:23 +000072#define DP83867_RGMII_TX_CLK_DELAY_MAX 0xf
Dan Murphy2a101542015-06-02 09:34:37 -050073#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
Trent Piephoc11669a2019-05-22 18:43:23 +000074#define DP83867_RGMII_RX_CLK_DELAY_MAX 0xf
75#define DP83867_RGMII_RX_CLK_DELAY_SHIFT 0
Dan Murphy2a101542015-06-02 09:34:37 -050076
Mugunthan V Ned838fe2016-10-18 16:50:18 +053077/* IO_MUX_CFG bits */
78#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL 0x1f
79
80#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0
81#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f
Trent Piepho13c83cf2019-05-22 18:43:22 +000082#define DP83867_IO_MUX_CFG_CLK_O_DISABLE BIT(6)
Wadim Egorov9708fb62018-02-14 17:07:11 +010083#define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK (0x1f << 8)
84#define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8
Mugunthan V Ned838fe2016-10-18 16:50:18 +053085
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +010086/* CFG4 bits */
87#define DP83867_CFG4_PORT_MIRROR_EN BIT(0)
88
89enum {
90 DP83867_PORT_MIRROING_KEEP,
91 DP83867_PORT_MIRROING_EN,
92 DP83867_PORT_MIRROING_DIS,
93};
94
Dan Murphy2a101542015-06-02 09:34:37 -050095struct dp83867_private {
Trent Piepho1b9b2952019-05-22 18:43:24 +000096 u32 rx_id_delay;
97 u32 tx_id_delay;
98 u32 fifo_depth;
Mugunthan V Ned838fe2016-10-18 16:50:18 +053099 int io_impedance;
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +0100100 int port_mirroring;
Murali Karicheri37144472017-07-04 16:23:24 +0530101 bool rxctrl_strap_quirk;
Trent Piepho13c83cf2019-05-22 18:43:22 +0000102 bool set_clk_output;
103 u32 clk_output_sel;
Dan Murphy2a101542015-06-02 09:34:37 -0500104};
105
106static int dp83867_ack_interrupt(struct phy_device *phydev)
107{
108 int err = phy_read(phydev, MII_DP83867_ISR);
109
110 if (err < 0)
111 return err;
112
113 return 0;
114}
115
116static int dp83867_config_intr(struct phy_device *phydev)
117{
118 int micr_status;
119
120 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
121 micr_status = phy_read(phydev, MII_DP83867_MICR);
122 if (micr_status < 0)
123 return micr_status;
124
125 micr_status |=
126 (MII_DP83867_MICR_AN_ERR_INT_EN |
127 MII_DP83867_MICR_SPEED_CHNG_INT_EN |
Grygorii Strashko5ca7d1c2017-01-05 14:48:07 -0600128 MII_DP83867_MICR_AUTONEG_COMP_INT_EN |
129 MII_DP83867_MICR_LINK_STS_CHNG_INT_EN |
Dan Murphy2a101542015-06-02 09:34:37 -0500130 MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
131 MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
132
133 return phy_write(phydev, MII_DP83867_MICR, micr_status);
134 }
135
136 micr_status = 0x0;
137 return phy_write(phydev, MII_DP83867_MICR, micr_status);
138}
139
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +0100140static int dp83867_config_port_mirroring(struct phy_device *phydev)
141{
142 struct dp83867_private *dp83867 =
143 (struct dp83867_private *)phydev->priv;
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +0100144
145 if (dp83867->port_mirroring == DP83867_PORT_MIRROING_EN)
Heiner Kallweitb52c0182019-02-06 07:38:43 +0100146 phy_set_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
147 DP83867_CFG4_PORT_MIRROR_EN);
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +0100148 else
Heiner Kallweitb52c0182019-02-06 07:38:43 +0100149 phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
150 DP83867_CFG4_PORT_MIRROR_EN);
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +0100151 return 0;
152}
153
Dan Murphy2a101542015-06-02 09:34:37 -0500154#ifdef CONFIG_OF_MDIO
155static int dp83867_of_init(struct phy_device *phydev)
156{
157 struct dp83867_private *dp83867 = phydev->priv;
Andrew Lunne5a03bf2016-01-06 20:11:16 +0100158 struct device *dev = &phydev->mdio.dev;
Dan Murphy2a101542015-06-02 09:34:37 -0500159 struct device_node *of_node = dev->of_node;
160 int ret;
161
Andrew Lunn7bf9ae02015-12-07 04:38:58 +0100162 if (!of_node)
Dan Murphy2a101542015-06-02 09:34:37 -0500163 return -ENODEV;
164
Mugunthan V Ned838fe2016-10-18 16:50:18 +0530165 dp83867->io_impedance = -EINVAL;
166
167 /* Optional configuration */
Wadim Egorov9708fb62018-02-14 17:07:11 +0100168 ret = of_property_read_u32(of_node, "ti,clk-output-sel",
169 &dp83867->clk_output_sel);
Trent Piepho13c83cf2019-05-22 18:43:22 +0000170 /* If not set, keep default */
171 if (!ret) {
172 dp83867->set_clk_output = true;
173 /* Valid values are 0 to DP83867_CLK_O_SEL_REF_CLK or
174 * DP83867_CLK_O_SEL_OFF.
Wadim Egorov9708fb62018-02-14 17:07:11 +0100175 */
Trent Piepho13c83cf2019-05-22 18:43:22 +0000176 if (dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK &&
177 dp83867->clk_output_sel != DP83867_CLK_O_SEL_OFF) {
178 phydev_err(phydev, "ti,clk-output-sel value %u out of range\n",
179 dp83867->clk_output_sel);
180 return -EINVAL;
181 }
182 }
Wadim Egorov9708fb62018-02-14 17:07:11 +0100183
Mugunthan V Ned838fe2016-10-18 16:50:18 +0530184 if (of_property_read_bool(of_node, "ti,max-output-impedance"))
185 dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
186 else if (of_property_read_bool(of_node, "ti,min-output-impedance"))
187 dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN;
188
Murali Karicheri37144472017-07-04 16:23:24 +0530189 dp83867->rxctrl_strap_quirk = of_property_read_bool(of_node,
190 "ti,dp83867-rxctrl-strap-quirk");
191
Trent Piephoc11669a2019-05-22 18:43:23 +0000192 /* Existing behavior was to use default pin strapping delay in rgmii
193 * mode, but rgmii should have meant no delay. Warn existing users.
194 */
195 if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
196 const u16 val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS2);
197 const u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >>
198 DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT;
199 const u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >>
200 DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT;
Dan Murphy2a101542015-06-02 09:34:37 -0500201
Trent Piephoc11669a2019-05-22 18:43:23 +0000202 if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE ||
203 rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
204 phydev_warn(phydev,
205 "PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
206 "Should be 'rgmii-id' to use internal delays\n");
207 }
208
209 /* RX delay *must* be specified if internal delay of RX is used. */
210 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
211 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
212 ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
213 &dp83867->rx_id_delay);
214 if (ret) {
215 phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
216 return ret;
217 }
218 if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
219 phydev_err(phydev,
220 "ti,rx-internal-delay value of %u out of range\n",
221 dp83867->rx_id_delay);
222 return -EINVAL;
223 }
224 }
225
226 /* TX delay *must* be specified if internal delay of RX is used. */
227 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
228 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
229 ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
230 &dp83867->tx_id_delay);
231 if (ret) {
232 phydev_err(phydev, "ti,tx-internal-delay must be specified\n");
233 return ret;
234 }
235 if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
236 phydev_err(phydev,
237 "ti,tx-internal-delay value of %u out of range\n",
238 dp83867->tx_id_delay);
239 return -EINVAL;
240 }
241 }
Dan Murphy2a101542015-06-02 09:34:37 -0500242
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +0100243 if (of_property_read_bool(of_node, "enet-phy-lane-swap"))
244 dp83867->port_mirroring = DP83867_PORT_MIRROING_EN;
245
246 if (of_property_read_bool(of_node, "enet-phy-lane-no-swap"))
247 dp83867->port_mirroring = DP83867_PORT_MIRROING_DIS;
248
Wu Fengguang92671352015-07-24 14:16:10 +0800249 return of_property_read_u32(of_node, "ti,fifo-depth",
Dan Murphy2a101542015-06-02 09:34:37 -0500250 &dp83867->fifo_depth);
Dan Murphy2a101542015-06-02 09:34:37 -0500251}
252#else
253static int dp83867_of_init(struct phy_device *phydev)
254{
255 return 0;
256}
257#endif /* CONFIG_OF_MDIO */
258
259static int dp83867_config_init(struct phy_device *phydev)
260{
261 struct dp83867_private *dp83867;
Lukasz Majewskiac6e0582017-02-07 06:20:24 +0100262 int ret, val, bs;
Stefan Hauserb291c412016-07-01 22:35:03 +0200263 u16 delay;
Dan Murphy2a101542015-06-02 09:34:37 -0500264
265 if (!phydev->priv) {
Andrew Lunne5a03bf2016-01-06 20:11:16 +0100266 dp83867 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83867),
Dan Murphy2a101542015-06-02 09:34:37 -0500267 GFP_KERNEL);
268 if (!dp83867)
269 return -ENOMEM;
270
271 phydev->priv = dp83867;
272 ret = dp83867_of_init(phydev);
273 if (ret)
274 return ret;
275 } else {
276 dp83867 = (struct dp83867_private *)phydev->priv;
277 }
278
Murali Karicheri37144472017-07-04 16:23:24 +0530279 /* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */
Heiner Kallweitb52c0182019-02-06 07:38:43 +0100280 if (dp83867->rxctrl_strap_quirk)
281 phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
282 BIT(7));
Murali Karicheri37144472017-07-04 16:23:24 +0530283
Dan Murphy2a101542015-06-02 09:34:37 -0500284 if (phy_interface_is_rgmii(phydev)) {
Stefan Hauserb291c412016-07-01 22:35:03 +0200285 val = phy_read(phydev, MII_DP83867_PHYCTRL);
286 if (val < 0)
287 return val;
288 val &= ~DP83867_PHYCR_FIFO_DEPTH_MASK;
289 val |= (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT);
Lukasz Majewskiac6e0582017-02-07 06:20:24 +0100290
291 /* The code below checks if "port mirroring" N/A MODE4 has been
292 * enabled during power on bootstrap.
293 *
294 * Such N/A mode enabled by mistake can put PHY IC in some
295 * internal testing mode and disable RGMII transmission.
296 *
297 * In this particular case one needs to check STRAP_STS1
298 * register's bit 11 (marked as RESERVED).
299 */
300
Russell Kinga6d99fc2017-03-21 16:36:53 +0000301 bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS1);
Lukasz Majewskiac6e0582017-02-07 06:20:24 +0100302 if (bs & DP83867_STRAP_STS1_RESERVED)
303 val &= ~DP83867_PHYCR_RESERVED_MASK;
304
Stefan Hauserb291c412016-07-01 22:35:03 +0200305 ret = phy_write(phydev, MII_DP83867_PHYCTRL, val);
Dan Murphy2a101542015-06-02 09:34:37 -0500306 if (ret)
307 return ret;
308 }
309
Trent Piephoc11669a2019-05-22 18:43:23 +0000310 /* If rgmii mode with no internal delay is selected, we do NOT use
311 * aligned mode as one might expect. Instead we use the PHY's default
312 * based on pin strapping. And the "mode 0" default is to *use*
313 * internal delay with a value of 7 (2.00 ns).
314 */
Dan Murphya46fa262015-07-21 12:06:45 -0500315 if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) &&
Dan Murphy2a101542015-06-02 09:34:37 -0500316 (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
Russell Kinga6d99fc2017-03-21 16:36:53 +0000317 val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL);
Dan Murphy2a101542015-06-02 09:34:37 -0500318
Trent Piephoc11669a2019-05-22 18:43:23 +0000319 val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
Dan Murphy2a101542015-06-02 09:34:37 -0500320 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
321 val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
322
323 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
324 val |= DP83867_RGMII_TX_CLK_DELAY_EN;
325
326 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
327 val |= DP83867_RGMII_RX_CLK_DELAY_EN;
328
Russell Kinga6d99fc2017-03-21 16:36:53 +0000329 phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL, val);
Dan Murphy2a101542015-06-02 09:34:37 -0500330
331 delay = (dp83867->rx_id_delay |
332 (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
333
Russell Kinga6d99fc2017-03-21 16:36:53 +0000334 phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIIDCTL,
335 delay);
Mugunthan V Ned838fe2016-10-18 16:50:18 +0530336
Heiner Kallweitb52c0182019-02-06 07:38:43 +0100337 if (dp83867->io_impedance >= 0)
338 phy_modify_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG,
339 DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL,
340 dp83867->io_impedance &
341 DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL);
Dan Murphy2a101542015-06-02 09:34:37 -0500342 }
343
Grygorii Strashko5ca7d1c2017-01-05 14:48:07 -0600344 /* Enable Interrupt output INT_OE in CFG3 register */
345 if (phy_interrupt_is_valid(phydev)) {
346 val = phy_read(phydev, DP83867_CFG3);
347 val |= BIT(7);
348 phy_write(phydev, DP83867_CFG3, val);
349 }
350
Lukasz Majewskifc6d39c2017-02-07 06:20:23 +0100351 if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP)
352 dp83867_config_port_mirroring(phydev);
353
Wadim Egorov9708fb62018-02-14 17:07:11 +0100354 /* Clock output selection if muxing property is set */
Trent Piepho13c83cf2019-05-22 18:43:22 +0000355 if (dp83867->set_clk_output) {
356 u16 mask = DP83867_IO_MUX_CFG_CLK_O_DISABLE;
357
358 if (dp83867->clk_output_sel == DP83867_CLK_O_SEL_OFF) {
359 val = DP83867_IO_MUX_CFG_CLK_O_DISABLE;
360 } else {
361 mask |= DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
362 val = dp83867->clk_output_sel <<
363 DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT;
364 }
365
Heiner Kallweitb52c0182019-02-06 07:38:43 +0100366 phy_modify_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG,
Trent Piepho13c83cf2019-05-22 18:43:22 +0000367 mask, val);
368 }
Wadim Egorov9708fb62018-02-14 17:07:11 +0100369
Dan Murphy2a101542015-06-02 09:34:37 -0500370 return 0;
371}
372
373static int dp83867_phy_reset(struct phy_device *phydev)
374{
375 int err;
376
377 err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESET);
378 if (err < 0)
379 return err;
380
Max Uvarov72a7d452019-02-25 12:15:10 +0300381 usleep_range(10, 20);
382
Dan Murphy2a101542015-06-02 09:34:37 -0500383 return dp83867_config_init(phydev);
384}
385
386static struct phy_driver dp83867_driver[] = {
387 {
388 .phy_id = DP83867_PHY_ID,
389 .phy_id_mask = 0xfffffff0,
390 .name = "TI DP83867",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +0200391 /* PHY_GBIT_FEATURES */
Dan Murphy2a101542015-06-02 09:34:37 -0500392
393 .config_init = dp83867_config_init,
394 .soft_reset = dp83867_phy_reset,
395
396 /* IRQ related */
397 .ack_interrupt = dp83867_ack_interrupt,
398 .config_intr = dp83867_config_intr,
399
Dan Murphy2a101542015-06-02 09:34:37 -0500400 .suspend = genphy_suspend,
401 .resume = genphy_resume,
Dan Murphy2a101542015-06-02 09:34:37 -0500402 },
403};
404module_phy_driver(dp83867_driver);
405
406static struct mdio_device_id __maybe_unused dp83867_tbl[] = {
407 { DP83867_PHY_ID, 0xfffffff0 },
408 { }
409};
410
411MODULE_DEVICE_TABLE(mdio, dp83867_tbl);
412
413MODULE_DESCRIPTION("Texas Instruments DP83867 PHY driver");
414MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
Andrew Lunn5f857572019-01-21 19:10:19 +0100415MODULE_LICENSE("GPL v2");