net: phy: phy_device: Call into the PHY driver to set LED brightness
authorAndrew Lunn <andrew@lunn.ch>
Mon, 17 Apr 2023 15:17:28 +0000 (17:17 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 19 Apr 2023 11:59:16 +0000 (12:59 +0100)
Linux LEDs can be software controlled via the brightness file in /sys.
LED drivers need to implement a brightness_set function which the core
will call. Implement an intermediary in phy_device, which will call
into the phy driver if it implements the necessary function.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/phy_device.c
include/linux/phy.h

index 61b971251de52c7f519a2fe9fe1781b8f752a49a..5c1200160c51eff42431ca6a9aa6192349af6e3b 100644 (file)
@@ -2991,11 +2991,18 @@ static bool phy_drv_supports_irq(struct phy_driver *phydrv)
        return phydrv->config_intr && phydrv->handle_interrupt;
 }
 
-/* Dummy implementation until calls into PHY driver are added */
 static int phy_led_set_brightness(struct led_classdev *led_cdev,
                                  enum led_brightness value)
 {
-       return 0;
+       struct phy_led *phyled = to_phy_led(led_cdev);
+       struct phy_device *phydev = phyled->phydev;
+       int err;
+
+       mutex_lock(&phydev->lock);
+       err = phydev->drv->led_brightness_set(phydev, phyled->index, value);
+       mutex_unlock(&phydev->lock);
+
+       return err;
 }
 
 static int of_phy_led(struct phy_device *phydev,
@@ -3012,12 +3019,14 @@ static int of_phy_led(struct phy_device *phydev,
                return -ENOMEM;
 
        cdev = &phyled->led_cdev;
+       phyled->phydev = phydev;
 
        err = of_property_read_u8(led, "reg", &phyled->index);
        if (err)
                return err;
 
-       cdev->brightness_set_blocking = phy_led_set_brightness;
+       if (phydev->drv->led_brightness_set)
+               cdev->brightness_set_blocking = phy_led_set_brightness;
        cdev->max_brightness = 1;
        init_data.devicename = dev_name(&phydev->mdio.dev);
        init_data.fwnode = of_fwnode_handle(led);
index bd6b5e9bb7296f32cacdacc649e2ff275413a93e..f3c7e3c99f24017de2f17691b7e672216f0f0eef 100644 (file)
@@ -841,15 +841,19 @@ struct phy_plca_status {
  * struct phy_led: An LED driven by the PHY
  *
  * @list: List of LEDs
+ * @phydev: PHY this LED is attached to
  * @led_cdev: Standard LED class structure
  * @index: Number of the LED
  */
 struct phy_led {
        struct list_head list;
+       struct phy_device *phydev;
        struct led_classdev led_cdev;
        u8 index;
 };
 
+#define to_phy_led(d) container_of(d, struct phy_led, led_cdev)
+
 /**
  * struct phy_driver - Driver structure for a particular PHY type
  *
@@ -1072,6 +1076,15 @@ struct phy_driver {
        /** @get_plca_status: Return the current PLCA status info */
        int (*get_plca_status)(struct phy_device *dev,
                               struct phy_plca_status *plca_st);
+
+       /**
+        * @led_brightness_set: Set a PHY LED brightness. Index
+        * indicates which of the PHYs led should be set. Value
+        * follows the standard LED class meaning, e.g. LED_OFF,
+        * LED_HALF, LED_FULL.
+        */
+       int (*led_brightness_set)(struct phy_device *dev,
+                                 u8 index, enum led_brightness value);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),                \
                                      struct phy_driver, mdiodrv)