phylib: Add device reset delay support
authorRichard Leitner <richard.leitner@skidata.com>
Mon, 11 Dec 2017 12:16:57 +0000 (13:16 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 13 Dec 2017 16:22:53 +0000 (11:22 -0500)
Some PHYs need a minimum time after the reset gpio was asserted and/or
deasserted. To ensure we meet these timing requirements add two new
optional devicetree parameters for the phy: reset-delay-us and
reset-post-delay-us.

Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/devicetree/bindings/net/phy.txt
drivers/net/phy/mdio_device.c
drivers/of/of_mdio.c
include/linux/mdio.h

index c05479f5ac7cc837b39808cd030b50273ea1e083..72860ce7f61016b6bd91186d2cb7a77103357b27 100644 (file)
@@ -55,6 +55,12 @@ Optional Properties:
 
 - reset-gpios: The GPIO phandle and specifier for the PHY reset signal.
 
+- reset-delay-us: Delay after the reset was asserted in microseconds.
+  If this property is missing the delay will be skipped.
+
+- reset-post-delay-us: Delay after the reset was deasserted in microseconds.
+  If this property is missing the delay will be skipped.
+
 Example:
 
 ethernet-phy@0 {
@@ -62,4 +68,8 @@ ethernet-phy@0 {
        interrupt-parent = <&PIC>;
        interrupts = <35 IRQ_TYPE_EDGE_RISING>;
        reg = <0>;
+
+       reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+       reset-delay-us = <1000>;
+       reset-post-delay-us = <2000>;
 };
index 75d97dd9fb281704ce955ac516d878cd92124ed8..843c1dde93e4552880841dfb535d676a6ad58ed3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/unistd.h>
+#include <linux/delay.h>
 
 void mdio_device_free(struct mdio_device *mdiodev)
 {
@@ -118,8 +119,16 @@ EXPORT_SYMBOL(mdio_device_remove);
 
 void mdio_device_reset(struct mdio_device *mdiodev, int value)
 {
-       if (mdiodev->reset)
-               gpiod_set_value(mdiodev->reset, value);
+       unsigned int d;
+
+       if (!mdiodev->reset)
+               return;
+
+       gpiod_set_value(mdiodev->reset, value);
+
+       d = value ? mdiodev->reset_delay : mdiodev->reset_post_delay;
+       if (d)
+               usleep_range(d, d + max_t(unsigned int, d / 10, 100));
 }
 EXPORT_SYMBOL(mdio_device_reset);
 
index 98258583abb0b40529056767c91401296e0013d4..7c87671763156b4d76707a3af041d49a897e3c58 100644 (file)
@@ -77,6 +77,10 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio,
        if (of_property_read_bool(child, "broken-turn-around"))
                mdio->phy_ignore_ta_mask |= 1 << addr;
 
+       of_property_read_u32(child, "reset-delay-us", &phy->mdio.reset_delay);
+       of_property_read_u32(child, "reset-post-delay-us",
+                            &phy->mdio.reset_post_delay);
+
        /* Associate the OF node with the device structure so it
         * can be looked up later */
        of_node_get(child);
index 92d4e55ffe6756378eaa8cf48eb2f6dbe08f65e2..e37c21d8eb19da5f375d0e4d41b70e659dc827b6 100644 (file)
@@ -41,6 +41,8 @@ struct mdio_device {
        int addr;
        int flags;
        struct gpio_desc *reset;
+       unsigned int reset_delay;
+       unsigned int reset_post_delay;
 };
 #define to_mdio_device(d) container_of(d, struct mdio_device, dev)