aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch620
1 files changed, 0 insertions, 620 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch b/target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch
deleted file mode 100644
index dcb6071e28..0000000000
--- a/target/linux/layerscape/patches-5.4/701-net-0328-net-phy-Inphi-IN112525_s03-retimer-support.patch
+++ /dev/null
@@ -1,620 +0,0 @@
-From 630ee8f358d961a7c8295d60a112e27cbfe4478d Mon Sep 17 00:00:00 2001
-From: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
-Date: Fri, 9 Nov 2018 06:20:36 +0200
-Subject: [PATCH] net/phy: Inphi IN112525_s03 retimer support
-
-Software controller for IN112525_s03 retimer
-
-Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
----
- drivers/net/phy/Kconfig | 5 +
- drivers/net/phy/Makefile | 1 +
- drivers/net/phy/inphi.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 584 insertions(+)
- create mode 100644 drivers/net/phy/inphi.c
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -471,6 +471,11 @@ config ICPLUS_PHY
- ---help---
- Currently supports the IP175C and IP1001 PHYs.
-
-+config INPHI_PHY
-+ tristate "Inphi CDR 10G/25G Ethernet PHY"
-+ ---help---
-+ Currently supports the IN112525_S03 part @ 25G
-+
- config INTEL_XWAY_PHY
- tristate "Intel XWAY PHYs"
- ---help---
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -86,6 +86,7 @@ obj-$(CONFIG_DP83848_PHY) += dp83848.o
- obj-$(CONFIG_DP83867_PHY) += dp83867.o
- obj-$(CONFIG_FIXED_PHY) += fixed_phy.o
- obj-$(CONFIG_ICPLUS_PHY) += icplus.o
-+obj-$(CONFIG_INPHI_PHY) += inphi.o
- obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o
- obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
- obj-$(CONFIG_LXT_PHY) += lxt.o
---- /dev/null
-+++ b/drivers/net/phy/inphi.c
-@@ -0,0 +1,578 @@
-+/*
-+ * Copyright 2018 NXP
-+ * Copyright 2018 INPHI
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright notice,
-+ * this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright notice,
-+ * this list of conditions and the following disclaimer in the documentation
-+ * and/or other materials provided with the distribution.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-+ * POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ * Inphi is a registered trademark of Inphi Corporation
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/phy.h>
-+#include <linux/mdio.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/of_irq.h>
-+#include <linux/workqueue.h>
-+#include <linux/i2c.h>
-+#include <linux/timer.h>
-+#include <linux/delay.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/cdev.h>
-+#include <linux/device.h>
-+#include <linux/slab.h>
-+#include <linux/uaccess.h>
-+
-+#define PHY_ID_IN112525 0x02107440
-+
-+#define INPHI_S03_DEVICE_ID_MSB 0x2
-+#define INPHI_S03_DEVICE_ID_LSB 0x3
-+
-+#define ALL_LANES 4
-+#define INPHI_POLL_DELAY 2500
-+
-+#define PHYCTRL_REG1 0x0012
-+#define PHYCTRL_REG2 0x0014
-+#define PHYCTRL_REG3 0x0120
-+#define PHYCTRL_REG4 0x0121
-+#define PHYCTRL_REG5 0x0180
-+#define PHYCTRL_REG6 0x0580
-+#define PHYCTRL_REG7 0x05C4
-+#define PHYCTRL_REG8 0x01C8
-+#define PHYCTRL_REG9 0x0521
-+
-+#define PHYSTAT_REG1 0x0021
-+#define PHYSTAT_REG2 0x0022
-+#define PHYSTAT_REG3 0x0123
-+
-+#define PHYMISC_REG1 0x0025
-+#define PHYMISC_REG2 0x002c
-+#define PHYMISC_REG3 0x00b3
-+#define PHYMISC_REG4 0x0181
-+#define PHYMISC_REG5 0x019D
-+#define PHYMISC_REG6 0x0198
-+#define PHYMISC_REG7 0x0199
-+#define PHYMISC_REG8 0x0581
-+#define PHYMISC_REG9 0x0598
-+#define PHYMISC_REG10 0x059c
-+#define PHYMISC_REG20 0x01B0
-+#define PHYMISC_REG21 0x01BC
-+#define PHYMISC_REG22 0x01C0
-+
-+#define RX_VCO_CODE_OFFSET 5
-+
-+#define mdio_wr(a, b) phy_write_mmd(inphi_phydev, MDIO_MMD_VEND1, (a), (b))
-+#define mdio_rd(a) phy_read_mmd(inphi_phydev, MDIO_MMD_VEND1, (a))
-+
-+#define VCO_CODE 390
-+
-+int vco_codes[ALL_LANES] = {
-+ VCO_CODE,
-+ VCO_CODE,
-+ VCO_CODE,
-+ VCO_CODE
-+};
-+
-+static void mykmod_work_handler(struct work_struct *w);
-+
-+static struct workqueue_struct *wq;
-+static DECLARE_DELAYED_WORK(mykmod_work, mykmod_work_handler);
-+static unsigned long onesec;
-+struct phy_device *inphi_phydev;
-+
-+int bit_test(int value, int bit_field)
-+{
-+ int result;
-+ int bit_mask = (1 << bit_field);
-+
-+ result = ((value & bit_mask) == bit_mask);
-+ return result;
-+}
-+
-+int tx_pll_lock_test(int lane)
-+{
-+ int i, val, locked = 1;
-+
-+ if (lane == ALL_LANES) {
-+ for (i = 0; i < ALL_LANES; i++) {
-+ val = mdio_rd(i * 0x100 + PHYSTAT_REG3);
-+ locked = locked & bit_test(val, 15);
-+ }
-+ } else {
-+ val = mdio_rd(lane * 0x100 + PHYSTAT_REG3);
-+ locked = locked & bit_test(val, 15);
-+ }
-+
-+ return locked;
-+}
-+
-+void rx_reset_assert(int lane)
-+{
-+ int mask, val;
-+
-+ if (lane == ALL_LANES) {
-+ val = mdio_rd(PHYMISC_REG2);
-+ mask = (1 << 15);
-+ mdio_wr(PHYMISC_REG2, val + mask);
-+ } else {
-+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
-+ mask = (1 << 6);
-+ mdio_wr(lane * 0x100 + PHYCTRL_REG8, val + mask);
-+ }
-+}
-+
-+void rx_reset_de_assert(int lane)
-+{
-+ int mask, val;
-+
-+ if (lane == ALL_LANES) {
-+ val = mdio_rd(PHYMISC_REG2);
-+ mask = 0xffff - (1 << 15);
-+ mdio_wr(PHYMISC_REG2, val & mask);
-+ } else {
-+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
-+ mask = 0xffff - (1 << 6);
-+ mdio_wr(lane * 0x100 + PHYCTRL_REG8, val & mask);
-+ }
-+}
-+
-+void rx_powerdown_assert(int lane)
-+{
-+ int mask, val;
-+
-+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
-+ mask = (1 << 5);
-+ mdio_wr(lane * 0x100 + PHYCTRL_REG8, val + mask);
-+}
-+
-+void rx_powerdown_de_assert(int lane)
-+{
-+ int mask, val;
-+
-+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
-+ mask = 0xffff - (1 << 5);
-+ mdio_wr(lane * 0x100 + PHYCTRL_REG8, val & mask);
-+}
-+
-+void tx_pll_assert(int lane)
-+{
-+ int val, recal;
-+
-+ if (lane == ALL_LANES) {
-+ val = mdio_rd(PHYMISC_REG2);
-+ recal = (1 << 12);
-+ mdio_wr(PHYMISC_REG2, val | recal);
-+ } else {
-+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG4);
-+ recal = (1 << 15);
-+ mdio_wr(lane * 0x100 + PHYCTRL_REG4, val | recal);
-+ }
-+}
-+
-+void tx_pll_de_assert(int lane)
-+{
-+ int recal, val;
-+
-+ if (lane == ALL_LANES) {
-+ val = mdio_rd(PHYMISC_REG2);
-+ recal = 0xefff;
-+ mdio_wr(PHYMISC_REG2, val & recal);
-+ } else {
-+ val = mdio_rd(lane * 0x100 + PHYCTRL_REG4);
-+ recal = 0x7fff;
-+ mdio_wr(lane * 0x100 + PHYCTRL_REG4, val & recal);
-+ }
-+}
-+
-+void tx_core_assert(int lane)
-+{
-+ int recal, val, val2, core_reset;
-+
-+ if (lane == 4) {
-+ val = mdio_rd(PHYMISC_REG2);
-+ recal = 1 << 10;
-+ mdio_wr(PHYMISC_REG2, val | recal);
-+ } else {
-+ val2 = mdio_rd(PHYMISC_REG3);
-+ core_reset = (1 << (lane + 8));
-+ mdio_wr(PHYMISC_REG3, val2 | core_reset);
-+ }
-+}
-+
-+void lol_disable(int lane)
-+{
-+ int val, mask;
-+
-+ val = mdio_rd(PHYMISC_REG3);
-+ mask = 1 << (lane + 4);
-+ mdio_wr(PHYMISC_REG3, val | mask);
-+}
-+
-+void tx_core_de_assert(int lane)
-+{
-+ int val, recal, val2, core_reset;
-+
-+ if (lane == ALL_LANES) {
-+ val = mdio_rd(PHYMISC_REG2);
-+ recal = 0xffff - (1 << 10);
-+ mdio_wr(PHYMISC_REG2, val & recal);
-+ } else {
-+ val2 = mdio_rd(PHYMISC_REG3);
-+ core_reset = 0xffff - (1 << (lane + 8));
-+ mdio_wr(PHYMISC_REG3, val2 & core_reset);
-+ }
-+}
-+
-+void tx_restart(int lane)
-+{
-+ tx_core_assert(lane);
-+ tx_pll_assert(lane);
-+ tx_pll_de_assert(lane);
-+ usleep_range(1500, 1600);
-+ tx_core_de_assert(lane);
-+}
-+
-+void disable_lane(int lane)
-+{
-+ rx_reset_assert(lane);
-+ rx_powerdown_assert(lane);
-+ tx_core_assert(lane);
-+ lol_disable(lane);
-+}
-+
-+void toggle_reset(int lane)
-+{
-+ int reg, val, orig;
-+
-+ if (lane == ALL_LANES) {
-+ mdio_wr(PHYMISC_REG2, 0x8000);
-+ udelay(100);
-+ mdio_wr(PHYMISC_REG2, 0x0000);
-+ } else {
-+ reg = lane * 0x100 + PHYCTRL_REG8;
-+ val = (1 << 6);
-+ orig = mdio_rd(reg);
-+ mdio_wr(reg, orig + val);
-+ udelay(100);
-+ mdio_wr(reg, orig);
-+ }
-+}
-+
-+int az_complete_test(int lane)
-+{
-+ int success = 1, value;
-+
-+ if (lane == 0 || lane == ALL_LANES) {
-+ value = mdio_rd(PHYCTRL_REG5);
-+ success = success & bit_test(value, 2);
-+ }
-+ if (lane == 1 || lane == ALL_LANES) {
-+ value = mdio_rd(PHYCTRL_REG5 + 0x100);
-+ success = success & bit_test(value, 2);
-+ }
-+ if (lane == 2 || lane == ALL_LANES) {
-+ value = mdio_rd(PHYCTRL_REG5 + 0x200);
-+ success = success & bit_test(value, 2);
-+ }
-+ if (lane == 3 || lane == ALL_LANES) {
-+ value = mdio_rd(PHYCTRL_REG5 + 0x300);
-+ success = success & bit_test(value, 2);
-+ }
-+
-+ return success;
-+}
-+
-+void save_az_offsets(int lane)
-+{
-+ int i;
-+
-+#define AZ_OFFSET_LANE_UPDATE(reg, lane) \
-+ mdio_wr((reg) + (lane) * 0x100, \
-+ (mdio_rd((reg) + (lane) * 0x100) >> 8))
-+
-+ if (lane == ALL_LANES) {
-+ for (i = 0; i < ALL_LANES; i++) {
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20, i);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 1, i);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 2, i);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 3, i);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21, i);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 1, i);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 2, i);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 3, i);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG22, i);
-+ }
-+ } else {
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20, lane);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 1, lane);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 2, lane);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 3, lane);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21, lane);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 1, lane);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 2, lane);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 3, lane);
-+ AZ_OFFSET_LANE_UPDATE(PHYMISC_REG22, lane);
-+ }
-+
-+ mdio_wr(PHYCTRL_REG7, 0x0001);
-+}
-+
-+void save_vco_codes(int lane)
-+{
-+ int i;
-+
-+ if (lane == ALL_LANES) {
-+ for (i = 0; i < ALL_LANES; i++) {
-+ vco_codes[i] = mdio_rd(PHYMISC_REG5 + i * 0x100);
-+ mdio_wr(PHYMISC_REG5 + i * 0x100,
-+ vco_codes[i] + RX_VCO_CODE_OFFSET);
-+ }
-+ } else {
-+ vco_codes[lane] = mdio_rd(PHYMISC_REG5 + lane * 0x100);
-+ mdio_wr(PHYMISC_REG5 + lane * 0x100,
-+ vco_codes[lane] + RX_VCO_CODE_OFFSET);
-+ }
-+}
-+
-+int inphi_lane_recovery(int lane)
-+{
-+ int i, value, az_pass;
-+
-+ switch (lane) {
-+ case 0:
-+ case 1:
-+ case 2:
-+ case 3:
-+ rx_reset_assert(lane);
-+ mdelay(20);
-+ break;
-+ case ALL_LANES:
-+ mdio_wr(PHYMISC_REG2, 0x9C00);
-+ mdelay(20);
-+ do {
-+ value = mdio_rd(PHYMISC_REG2);
-+ udelay(10);
-+ } while (!bit_test(value, 4));
-+ break;
-+ default:
-+ dev_err(&inphi_phydev->mdio.dev,
-+ "Incorrect usage of APIs in %s driver\n",
-+ inphi_phydev->drv->name);
-+ break;
-+ }
-+
-+ if (lane == ALL_LANES) {
-+ for (i = 0; i < ALL_LANES; i++)
-+ mdio_wr(PHYMISC_REG7 + i * 0x100, VCO_CODE);
-+ } else {
-+ mdio_wr(PHYMISC_REG7 + lane * 0x100, VCO_CODE);
-+ }
-+
-+ if (lane == ALL_LANES)
-+ for (i = 0; i < ALL_LANES; i++)
-+ mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0418);
-+ else
-+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0418);
-+
-+ mdio_wr(PHYCTRL_REG7, 0x0000);
-+
-+ rx_reset_de_assert(lane);
-+
-+ if (lane == ALL_LANES) {
-+ for (i = 0; i < ALL_LANES; i++) {
-+ mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0410);
-+ mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0412);
-+ }
-+ } else {
-+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0410);
-+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0412);
-+ }
-+
-+ for (i = 0; i < 64; i++) {
-+ mdelay(100);
-+ az_pass = az_complete_test(lane);
-+ if (az_pass) {
-+ save_az_offsets(lane);
-+ break;
-+ }
-+ }
-+
-+ if (!az_pass) {
-+ pr_info("in112525: AZ calibration fail @ lane=%d\n", lane);
-+ return -1;
-+ }
-+
-+ if (lane == ALL_LANES) {
-+ mdio_wr(PHYMISC_REG8, 0x0002);
-+ mdio_wr(PHYMISC_REG9, 0x2028);
-+ mdio_wr(PHYCTRL_REG6, 0x0010);
-+ usleep_range(1000, 1200);
-+ mdio_wr(PHYCTRL_REG6, 0x0110);
-+ mdelay(30);
-+ mdio_wr(PHYMISC_REG9, 0x3020);
-+ } else {
-+ mdio_wr(PHYMISC_REG4 + lane * 0x100, 0x0002);
-+ mdio_wr(PHYMISC_REG6 + lane * 0x100, 0x2028);
-+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0010);
-+ usleep_range(1000, 1200);
-+ mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0110);
-+ mdelay(30);
-+ mdio_wr(PHYMISC_REG6 + lane * 0x100, 0x3020);
-+ }
-+
-+ if (lane == ALL_LANES) {
-+ mdio_wr(PHYMISC_REG2, 0x1C00);
-+ mdio_wr(PHYMISC_REG2, 0x0C00);
-+ } else {
-+ tx_restart(lane);
-+ mdelay(11);
-+ }
-+
-+ if (lane == ALL_LANES) {
-+ if (bit_test(mdio_rd(PHYMISC_REG2), 6) == 0)
-+ return -1;
-+ } else {
-+ if (tx_pll_lock_test(lane) == 0)
-+ return -1;
-+ }
-+
-+ save_vco_codes(lane);
-+
-+ if (lane == ALL_LANES) {
-+ mdio_wr(PHYMISC_REG2, 0x0400);
-+ mdio_wr(PHYMISC_REG2, 0x0000);
-+ value = mdio_rd(PHYCTRL_REG1);
-+ value = value & 0xffbf;
-+ mdio_wr(PHYCTRL_REG2, value);
-+ } else {
-+ tx_core_de_assert(lane);
-+ }
-+
-+ if (lane == ALL_LANES) {
-+ mdio_wr(PHYMISC_REG1, 0x8000);
-+ mdio_wr(PHYMISC_REG1, 0x0000);
-+ }
-+ mdio_rd(PHYMISC_REG1);
-+ mdio_rd(PHYMISC_REG1);
-+ usleep_range(1000, 1200);
-+ mdio_rd(PHYSTAT_REG1);
-+ mdio_rd(PHYSTAT_REG2);
-+
-+ return 0;
-+}
-+
-+static void mykmod_work_handler(struct work_struct *w)
-+{
-+ int all_lanes_lock, lane0_lock, lane1_lock, lane2_lock, lane3_lock;
-+
-+ lane0_lock = bit_test(mdio_rd(0x123), 15);
-+ lane1_lock = bit_test(mdio_rd(0x223), 15);
-+ lane2_lock = bit_test(mdio_rd(0x323), 15);
-+ lane3_lock = bit_test(mdio_rd(0x423), 15);
-+
-+ /* check if the chip had any successful lane lock from the previous
-+ * stage (e.g. u-boot)
-+ */
-+ all_lanes_lock = lane0_lock | lane1_lock | lane2_lock | lane3_lock;
-+
-+ if (!all_lanes_lock) {
-+ /* start fresh */
-+ inphi_lane_recovery(ALL_LANES);
-+ } else {
-+ if (!lane0_lock)
-+ inphi_lane_recovery(0);
-+ if (!lane1_lock)
-+ inphi_lane_recovery(1);
-+ if (!lane2_lock)
-+ inphi_lane_recovery(2);
-+ if (!lane3_lock)
-+ inphi_lane_recovery(3);
-+ }
-+
-+ queue_delayed_work(wq, &mykmod_work, onesec);
-+}
-+
-+int inphi_probe(struct phy_device *phydev)
-+{
-+ int phy_id = 0, id_lsb = 0, id_msb = 0;
-+
-+ /* Read device id from phy registers */
-+ id_lsb = phy_read_mmd(phydev, MDIO_MMD_VEND1, INPHI_S03_DEVICE_ID_MSB);
-+ if (id_lsb < 0)
-+ return -ENXIO;
-+
-+ phy_id = id_lsb << 16;
-+
-+ id_msb = phy_read_mmd(phydev, MDIO_MMD_VEND1, INPHI_S03_DEVICE_ID_LSB);
-+ if (id_msb < 0)
-+ return -ENXIO;
-+
-+ phy_id |= id_msb;
-+
-+ /* Make sure the device tree binding matched the driver with the
-+ * right device.
-+ */
-+ if (phy_id != phydev->drv->phy_id) {
-+ dev_err(&phydev->mdio.dev,
-+ "Error matching phy with %s driver\n",
-+ phydev->drv->name);
-+ return -ENODEV;
-+ }
-+
-+ /* update the local phydev pointer, used inside all APIs */
-+ inphi_phydev = phydev;
-+ onesec = msecs_to_jiffies(INPHI_POLL_DELAY);
-+
-+ wq = create_singlethread_workqueue("inphi_kmod");
-+ if (wq) {
-+ queue_delayed_work(wq, &mykmod_work, onesec);
-+ } else {
-+ dev_err(&phydev->mdio.dev,
-+ "Error creating kernel workqueue for %s driver\n",
-+ phydev->drv->name);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static struct phy_driver inphi_driver[] = {
-+{
-+ .phy_id = PHY_ID_IN112525,
-+ .phy_id_mask = 0x0ff0fff0,
-+ .name = "Inphi 112525_S03",
-+ .features = PHY_GBIT_FEATURES,
-+ .probe = &inphi_probe,
-+},
-+};
-+
-+module_phy_driver(inphi_driver);
-+
-+static struct mdio_device_id __maybe_unused inphi_tbl[] = {
-+ { PHY_ID_IN112525, 0x0ff0fff0},
-+ {},
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, inphi_tbl);