History

net: phy: Add a helper to return the index for of the internal delay

Add a helper function that will return the index in the array for the passed in internal delay value. The helper requires the array, size and delay value. The helper will then return the index for the exact match or return the index for the index to the closest smaller value.

Dan Murphy committed 6 years ago

Commit 92252ee1 parent 91500692 files · +103 −0Browse files

Unified · Split

2 files
  1. drivers/net/phy/phy_device.c +99 −0
  2. include/linux/phy.h +4 −0
drivers/net/phy/phy_device.c+99−0
@@ -31,6 +31,7 @@ · 30 unmodified lines
3131 #include <linux/mdio.h>
3232 #include <linux/io.h>
3333 #include <linux/uaccess.h>
34+#include <linux/property.h>
3435
3536 MODULE_DESCRIPTION("PHY library");
3637 MODULE_AUTHOR("Andy Fleming");
@@ -2708,6 +2709,104 @@ void phy_get_pause(struct phy_device *phydev, bool *tx_pause, bool *rx_pause) · 2671 unmodified lines
27082709 }
27092710 EXPORT_SYMBOL(phy_get_pause);
27102711
2712+#if IS_ENABLED(CONFIG_OF_MDIO)
2713+static int phy_get_int_delay_property(struct device *dev, const char *name)
2714+{
2715+ s32 int_delay;
2716+ int ret;
2717+
2718+ ret = device_property_read_u32(dev, name, &int_delay);
2719+ if (ret)
2720+ return ret;
2721+
2722+ return int_delay;
2723+}
2724+#else
2725+static int phy_get_int_delay_property(struct device *dev, const char *name)
2726+{
2727+ return -EINVAL;
2728+}
2729+#endif
2730+
2731+/**
2732+ * phy_get_delay_index - returns the index of the internal delay
2733+ * @phydev: phy_device struct
2734+ * @dev: pointer to the devices device struct
2735+ * @delay_values: array of delays the PHY supports
2736+ * @size: the size of the delay array
2737+ * @is_rx: boolean to indicate to get the rx internal delay
2738+ *
2739+ * Returns the index within the array of internal delay passed in.
2740+ * If the device property is not present then the interface type is checked
2741+ * if the interface defines use of internal delay then a 1 is returned otherwise
2742+ * a 0 is returned.
2743+ * The array must be in ascending order. If PHY does not have an ascending order
2744+ * array then size = 0 and the value of the delay property is returned.
2745+ * Return -EINVAL if the delay is invalid or cannot be found.
2746+ */
2747+s32 phy_get_internal_delay(struct phy_device *phydev, struct device *dev,
2748+ const int *delay_values, int size, bool is_rx)
2749+{
2750+ s32 delay;
2751+ int i;
2752+
2753+ if (is_rx) {
2754+ delay = phy_get_int_delay_property(dev, "rx-internal-delay-ps");
2755+ if (delay < 0 && size == 0) {
2756+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
2757+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
2758+ return 1;
2759+ else
2760+ return 0;
2761+ }
2762+
2763+ } else {
2764+ delay = phy_get_int_delay_property(dev, "tx-internal-delay-ps");
2765+ if (delay < 0 && size == 0) {
2766+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
2767+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
2768+ return 1;
2769+ else
2770+ return 0;
2771+ }
2772+ }
2773+
2774+ if (delay < 0)
2775+ return delay;
2776+
2777+ if (delay && size == 0)
2778+ return delay;
2779+
2780+ if (delay < delay_values[0] || delay > delay_values[size - 1]) {
2781+ phydev_err(phydev, "Delay %d is out of range\n", delay);
2782+ return -EINVAL;
2783+ }
2784+
2785+ if (delay == delay_values[0])
2786+ return 0;
2787+
2788+ for (i = 1; i < size; i++) {
2789+ if (delay == delay_values[i])
2790+ return i;
2791+
2792+ /* Find an approximate index by looking up the table */
2793+ if (delay > delay_values[i - 1] &&
2794+ delay < delay_values[i]) {
2795+ if (delay - delay_values[i - 1] <
2796+ delay_values[i] - delay)
2797+ return i - 1;
2798+ else
2799+ return i;
2800+ }
2801+ }
2802+
2803+ phydev_err(phydev, "error finding internal delay index for %d\n",
2804+ delay);
2805+
2806+ return -EINVAL;
2807+}
2808+EXPORT_SYMBOL(phy_get_internal_delay);
2809+
27112810 static bool phy_drv_supports_irq(struct phy_driver *phydrv)
27122811 {
27132812 return phydrv->config_intr && phydrv->ack_interrupt;
include/linux/phy.h+4−0
@@ -1443,6 +1443,10 @@ void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx); · 1442 unmodified lines
14431443 bool phy_validate_pause(struct phy_device *phydev,
14441444 struct ethtool_pauseparam *pp);
14451445 void phy_get_pause(struct phy_device *phydev, bool *tx_pause, bool *rx_pause);
1446+
1447+s32 phy_get_internal_delay(struct phy_device *phydev, struct device *dev,
1448+ const int *delay_values, int size, bool is_rx);
1449+
14461450 void phy_resolve_pause(unsigned long *local_adv, unsigned long *partner_adv,
14471451 bool *tx_pause, bool *rx_pause);
14481452