mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
net: phy: phy_device: Call into the PHY driver to set LED offload
Linux LEDs can be requested to perform hardware accelerated blinking to indicate link, RX, TX etc. Pass the rules for blinking to the PHY driver, if it implements the ops needed to determine if a given pattern can be offloaded, to offload it, and what the current offload is. Additionally implement the op needed to get what device the LED is for. Reviewed-by: Simon Horman <simon.horman@corigine.com> Signed-off-by: Andrew Lunn <andrew@lunn.ch> Tested-by: Daniel Golle <daniel@makrotopia.org> Link: https://lore.kernel.org/r/20230808210436.838995-3-andrew@lunn.ch Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
7df1f14c04
commit
1dcc03c9a7
2 changed files with 101 additions and 0 deletions
|
@ -3020,6 +3020,61 @@ static int phy_led_blink_set(struct led_classdev *led_cdev,
|
|||
return err;
|
||||
}
|
||||
|
||||
static __maybe_unused struct device *
|
||||
phy_led_hw_control_get_device(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct phy_led *phyled = to_phy_led(led_cdev);
|
||||
struct phy_device *phydev = phyled->phydev;
|
||||
|
||||
if (phydev->attached_dev)
|
||||
return &phydev->attached_dev->dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
phy_led_hw_control_get(struct led_classdev *led_cdev,
|
||||
unsigned long *rules)
|
||||
{
|
||||
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_hw_control_get(phydev, phyled->index, rules);
|
||||
mutex_unlock(&phydev->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
phy_led_hw_control_set(struct led_classdev *led_cdev,
|
||||
unsigned long rules)
|
||||
{
|
||||
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_hw_control_set(phydev, phyled->index, rules);
|
||||
mutex_unlock(&phydev->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static __maybe_unused int phy_led_hw_is_supported(struct led_classdev *led_cdev,
|
||||
unsigned long rules)
|
||||
{
|
||||
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_hw_is_supported(phydev, phyled->index, rules);
|
||||
mutex_unlock(&phydev->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void phy_leds_unregister(struct phy_device *phydev)
|
||||
{
|
||||
struct phy_led *phyled;
|
||||
|
@ -3057,6 +3112,19 @@ static int of_phy_led(struct phy_device *phydev,
|
|||
cdev->brightness_set_blocking = phy_led_set_brightness;
|
||||
if (phydev->drv->led_blink_set)
|
||||
cdev->blink_set = phy_led_blink_set;
|
||||
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
if (phydev->drv->led_hw_is_supported &&
|
||||
phydev->drv->led_hw_control_set &&
|
||||
phydev->drv->led_hw_control_get) {
|
||||
cdev->hw_control_is_supported = phy_led_hw_is_supported;
|
||||
cdev->hw_control_set = phy_led_hw_control_set;
|
||||
cdev->hw_control_get = phy_led_hw_control_get;
|
||||
cdev->hw_control_trigger = "netdev";
|
||||
}
|
||||
|
||||
cdev->hw_control_get_device = phy_led_hw_control_get_device;
|
||||
#endif
|
||||
cdev->max_brightness = 1;
|
||||
init_data.devicename = dev_name(&phydev->mdio.dev);
|
||||
init_data.fwnode = of_fwnode_handle(led);
|
||||
|
|
|
@ -1105,6 +1105,39 @@ struct phy_driver {
|
|||
int (*led_blink_set)(struct phy_device *dev, u8 index,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off);
|
||||
/**
|
||||
* @led_hw_is_supported: Can the HW support the given rules.
|
||||
* @dev: PHY device which has the LED
|
||||
* @index: Which LED of the PHY device
|
||||
* @rules The core is interested in these rules
|
||||
*
|
||||
* Return 0 if yes, -EOPNOTSUPP if not, or an error code.
|
||||
*/
|
||||
int (*led_hw_is_supported)(struct phy_device *dev, u8 index,
|
||||
unsigned long rules);
|
||||
/**
|
||||
* @led_hw_control_set: Set the HW to control the LED
|
||||
* @dev: PHY device which has the LED
|
||||
* @index: Which LED of the PHY device
|
||||
* @rules The rules used to control the LED
|
||||
*
|
||||
* Returns 0, or a an error code.
|
||||
*/
|
||||
int (*led_hw_control_set)(struct phy_device *dev, u8 index,
|
||||
unsigned long rules);
|
||||
/**
|
||||
* @led_hw_control_get: Get how the HW is controlling the LED
|
||||
* @dev: PHY device which has the LED
|
||||
* @index: Which LED of the PHY device
|
||||
* @rules Pointer to the rules used to control the LED
|
||||
*
|
||||
* Set *@rules to how the HW is currently blinking. Returns 0
|
||||
* on success, or a error code if the current blinking cannot
|
||||
* be represented in rules, or some other error happens.
|
||||
*/
|
||||
int (*led_hw_control_get)(struct phy_device *dev, u8 index,
|
||||
unsigned long *rules);
|
||||
|
||||
};
|
||||
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
|
||||
struct phy_driver, mdiodrv)
|
||||
|
|
Loading…
Reference in a new issue