net: phy: Add phy_read_mmd_poll_timeout() from Linux
authorMarek Vasut <marek.vasut+renesas@mailbox.org>
Sun, 19 Mar 2023 17:08:08 +0000 (18:08 +0100)
committerMarek Vasut <marek.vasut+renesas@mailbox.org>
Fri, 7 Apr 2023 12:21:37 +0000 (14:21 +0200)
Add phy_read_mmd_poll_timeout() from Linux 5.7.y as of commit
bd971ff0b7392 ("net: phy: introduce phy_read_mmd_poll_timeout macro")
This is used by the upcoming Marvell 10G PHY driver.

Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
include/phy.h

index 34675b2..a837fed 100644 (file)
@@ -282,6 +282,37 @@ static inline ofnode phy_get_ofnode(struct phy_device *phydev)
                return dev_ofnode(phydev->dev);
 }
 
+/**
+ * phy_read_mmd_poll_timeout - Periodically poll a PHY register until a
+ *                             condition is met or a timeout occurs
+ *
+ * @phydev: The phy_device struct
+ * @devaddr: The MMD to read from
+ * @regnum: The register on the MMD to read
+ * @val: Variable to read the register into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in us (0
+ *            tight-loops).  Should be less than ~20ms since usleep_range
+ *            is used (see Documentation/timers/timers-howto.rst).
+ * @timeout_us: Timeout in us, 0 means never timeout
+ * @sleep_before_read: if it is true, sleep @sleep_us before read.
+ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
+ * case, the last read value at @args is stored in @val. Must not
+ * be called from atomic context if sleep_us or timeout_us are used.
+ */
+#define phy_read_mmd_poll_timeout(phydev, devaddr, regnum, val, cond, \
+                                 sleep_us, timeout_us, sleep_before_read) \
+({ \
+       int __ret = read_poll_timeout(phy_read_mmd, val, (cond) || val < 0, \
+                                 sleep_us, timeout_us, \
+                                 phydev, devaddr, regnum); \
+       if (val <  0) \
+               __ret = val; \
+       if (__ret) \
+               dev_err(phydev->dev, "%s failed: %d\n", __func__, __ret); \
+       __ret; \
+})
+
 int phy_read(struct phy_device *phydev, int devad, int regnum);
 int phy_write(struct phy_device *phydev, int devad, int regnum, u16 val);
 void phy_mmd_start_indirect(struct phy_device *phydev, int devad, int regnum);