1 From 1dcc03c9a7a824a31eaaecdfaa03542fb25feb6c Mon Sep 17 00:00:00 2001
2 From: Andrew Lunn <andrew@lunn.ch>
3 Date: Tue, 8 Aug 2023 23:04:34 +0200
4 Subject: [PATCH 2/4] net: phy: phy_device: Call into the PHY driver to set LED
7 Linux LEDs can be requested to perform hardware accelerated blinking
8 to indicate link, RX, TX etc. Pass the rules for blinking to the PHY
9 driver, if it implements the ops needed to determine if a given
10 pattern can be offloaded, to offload it, and what the current offload
11 is. Additionally implement the op needed to get what device the LED is
14 Reviewed-by: Simon Horman <simon.horman@corigine.com>
15 Signed-off-by: Andrew Lunn <andrew@lunn.ch>
16 Tested-by: Daniel Golle <daniel@makrotopia.org>
17 Link: https://lore.kernel.org/r/20230808210436.838995-3-andrew@lunn.ch
18 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
20 drivers/net/phy/phy_device.c | 68 ++++++++++++++++++++++++++++++++++++
21 include/linux/phy.h | 33 +++++++++++++++++
22 2 files changed, 101 insertions(+)
24 --- a/drivers/net/phy/phy_device.c
25 +++ b/drivers/net/phy/phy_device.c
26 @@ -2964,6 +2964,61 @@ static int phy_led_blink_set(struct led_
30 +static __maybe_unused struct device *
31 +phy_led_hw_control_get_device(struct led_classdev *led_cdev)
33 + struct phy_led *phyled = to_phy_led(led_cdev);
34 + struct phy_device *phydev = phyled->phydev;
36 + if (phydev->attached_dev)
37 + return &phydev->attached_dev->dev;
41 +static int __maybe_unused
42 +phy_led_hw_control_get(struct led_classdev *led_cdev,
43 + unsigned long *rules)
45 + struct phy_led *phyled = to_phy_led(led_cdev);
46 + struct phy_device *phydev = phyled->phydev;
49 + mutex_lock(&phydev->lock);
50 + err = phydev->drv->led_hw_control_get(phydev, phyled->index, rules);
51 + mutex_unlock(&phydev->lock);
56 +static int __maybe_unused
57 +phy_led_hw_control_set(struct led_classdev *led_cdev,
58 + unsigned long rules)
60 + struct phy_led *phyled = to_phy_led(led_cdev);
61 + struct phy_device *phydev = phyled->phydev;
64 + mutex_lock(&phydev->lock);
65 + err = phydev->drv->led_hw_control_set(phydev, phyled->index, rules);
66 + mutex_unlock(&phydev->lock);
71 +static __maybe_unused int phy_led_hw_is_supported(struct led_classdev *led_cdev,
72 + unsigned long rules)
74 + struct phy_led *phyled = to_phy_led(led_cdev);
75 + struct phy_device *phydev = phyled->phydev;
78 + mutex_lock(&phydev->lock);
79 + err = phydev->drv->led_hw_is_supported(phydev, phyled->index, rules);
80 + mutex_unlock(&phydev->lock);
85 static void phy_leds_unregister(struct phy_device *phydev)
87 struct phy_led *phyled;
88 @@ -3001,6 +3056,19 @@ static int of_phy_led(struct phy_device
89 cdev->brightness_set_blocking = phy_led_set_brightness;
90 if (phydev->drv->led_blink_set)
91 cdev->blink_set = phy_led_blink_set;
93 +#ifdef CONFIG_LEDS_TRIGGERS
94 + if (phydev->drv->led_hw_is_supported &&
95 + phydev->drv->led_hw_control_set &&
96 + phydev->drv->led_hw_control_get) {
97 + cdev->hw_control_is_supported = phy_led_hw_is_supported;
98 + cdev->hw_control_set = phy_led_hw_control_set;
99 + cdev->hw_control_get = phy_led_hw_control_get;
100 + cdev->hw_control_trigger = "netdev";
103 + cdev->hw_control_get_device = phy_led_hw_control_get_device;
105 cdev->max_brightness = 1;
106 init_data.devicename = dev_name(&phydev->mdio.dev);
107 init_data.fwnode = of_fwnode_handle(led);
108 --- a/include/linux/phy.h
109 +++ b/include/linux/phy.h
110 @@ -1022,6 +1022,39 @@ struct phy_driver {
111 int (*led_blink_set)(struct phy_device *dev, u8 index,
112 unsigned long *delay_on,
113 unsigned long *delay_off);
115 + * @led_hw_is_supported: Can the HW support the given rules.
116 + * @dev: PHY device which has the LED
117 + * @index: Which LED of the PHY device
118 + * @rules The core is interested in these rules
120 + * Return 0 if yes, -EOPNOTSUPP if not, or an error code.
122 + int (*led_hw_is_supported)(struct phy_device *dev, u8 index,
123 + unsigned long rules);
125 + * @led_hw_control_set: Set the HW to control the LED
126 + * @dev: PHY device which has the LED
127 + * @index: Which LED of the PHY device
128 + * @rules The rules used to control the LED
130 + * Returns 0, or a an error code.
132 + int (*led_hw_control_set)(struct phy_device *dev, u8 index,
133 + unsigned long rules);
135 + * @led_hw_control_get: Get how the HW is controlling the LED
136 + * @dev: PHY device which has the LED
137 + * @index: Which LED of the PHY device
138 + * @rules Pointer to the rules used to control the LED
140 + * Set *@rules to how the HW is currently blinking. Returns 0
141 + * on success, or a error code if the current blinking cannot
142 + * be represented in rules, or some other error happens.
144 + int (*led_hw_control_get)(struct phy_device *dev, u8 index,
145 + unsigned long *rules);
148 #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
149 struct phy_driver, mdiodrv)