-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net: phy: aquantia: add support for PHY LEDs
Aquantia Ethernet PHYs got 3 LED output pins which are typically used to indicate link status and activity. Add a minimal LED controller driver supporting the most common uses with the 'netdev' trigger as well as software-driven forced control of the LEDs. Signed-off-by: Daniel Golle <daniel@makrotopia.org> [ rework indentation, fix checkpatch error and improve some functions ] Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Daniel Golle
authored and
David S. Miller
committed
Jun 5, 2024
1 parent
c11d5db
commit 61578f6
Showing
4 changed files
with
252 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* LED driver for Aquantia PHY | ||
* | ||
* Author: Daniel Golle <daniel@makrotopia.org> | ||
*/ | ||
|
||
#include <linux/phy.h> | ||
|
||
#include "aquantia.h" | ||
|
||
int aqr_phy_led_brightness_set(struct phy_device *phydev, | ||
u8 index, enum led_brightness value) | ||
{ | ||
if (index >= AQR_MAX_LEDS) | ||
return -EINVAL; | ||
|
||
return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index), | ||
VEND1_GLOBAL_LED_PROV_LINK_MASK | | ||
VEND1_GLOBAL_LED_PROV_FORCE_ON | | ||
VEND1_GLOBAL_LED_PROV_RX_ACT | | ||
VEND1_GLOBAL_LED_PROV_TX_ACT, | ||
value ? VEND1_GLOBAL_LED_PROV_FORCE_ON : 0); | ||
} | ||
|
||
static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | | ||
BIT(TRIGGER_NETDEV_LINK_100) | | ||
BIT(TRIGGER_NETDEV_LINK_1000) | | ||
BIT(TRIGGER_NETDEV_LINK_2500) | | ||
BIT(TRIGGER_NETDEV_LINK_5000) | | ||
BIT(TRIGGER_NETDEV_LINK_10000) | | ||
BIT(TRIGGER_NETDEV_RX) | | ||
BIT(TRIGGER_NETDEV_TX)); | ||
|
||
int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, | ||
unsigned long rules) | ||
{ | ||
if (index >= AQR_MAX_LEDS) | ||
return -EINVAL; | ||
|
||
/* All combinations of the supported triggers are allowed */ | ||
if (rules & ~supported_triggers) | ||
return -EOPNOTSUPP; | ||
|
||
return 0; | ||
} | ||
|
||
int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index, | ||
unsigned long *rules) | ||
{ | ||
int val; | ||
|
||
if (index >= AQR_MAX_LEDS) | ||
return -EINVAL; | ||
|
||
val = phy_read_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index)); | ||
if (val < 0) | ||
return val; | ||
|
||
*rules = 0; | ||
if (val & VEND1_GLOBAL_LED_PROV_LINK100) | ||
*rules |= BIT(TRIGGER_NETDEV_LINK_100); | ||
|
||
if (val & VEND1_GLOBAL_LED_PROV_LINK1000) | ||
*rules |= BIT(TRIGGER_NETDEV_LINK_1000); | ||
|
||
if (val & VEND1_GLOBAL_LED_PROV_LINK2500) | ||
*rules |= BIT(TRIGGER_NETDEV_LINK_2500); | ||
|
||
if (val & VEND1_GLOBAL_LED_PROV_LINK5000) | ||
*rules |= BIT(TRIGGER_NETDEV_LINK_5000); | ||
|
||
if (val & VEND1_GLOBAL_LED_PROV_LINK10000) | ||
*rules |= BIT(TRIGGER_NETDEV_LINK_10000); | ||
|
||
if (val & VEND1_GLOBAL_LED_PROV_RX_ACT) | ||
*rules |= BIT(TRIGGER_NETDEV_RX); | ||
|
||
if (val & VEND1_GLOBAL_LED_PROV_TX_ACT) | ||
*rules |= BIT(TRIGGER_NETDEV_TX); | ||
|
||
return 0; | ||
} | ||
|
||
int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index, | ||
unsigned long rules) | ||
{ | ||
u16 val = 0; | ||
|
||
if (index >= AQR_MAX_LEDS) | ||
return -EINVAL; | ||
|
||
if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) | ||
val |= VEND1_GLOBAL_LED_PROV_LINK100; | ||
|
||
if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) | ||
val |= VEND1_GLOBAL_LED_PROV_LINK1000; | ||
|
||
if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) | ||
val |= VEND1_GLOBAL_LED_PROV_LINK2500; | ||
|
||
if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK))) | ||
val |= VEND1_GLOBAL_LED_PROV_LINK5000; | ||
|
||
if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK))) | ||
val |= VEND1_GLOBAL_LED_PROV_LINK10000; | ||
|
||
if (rules & BIT(TRIGGER_NETDEV_RX)) | ||
val |= VEND1_GLOBAL_LED_PROV_RX_ACT; | ||
|
||
if (rules & BIT(TRIGGER_NETDEV_TX)) | ||
val |= VEND1_GLOBAL_LED_PROV_TX_ACT; | ||
|
||
return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index), | ||
VEND1_GLOBAL_LED_PROV_LINK_MASK | | ||
VEND1_GLOBAL_LED_PROV_FORCE_ON | | ||
VEND1_GLOBAL_LED_PROV_RX_ACT | | ||
VEND1_GLOBAL_LED_PROV_TX_ACT, val); | ||
} | ||
|
||
int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable) | ||
{ | ||
return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index), | ||
VEND1_GLOBAL_LED_DRIVE_VDD, enable); | ||
} | ||
|
||
int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes) | ||
{ | ||
struct aqr107_priv *priv = phydev->priv; | ||
bool active_low = false; | ||
u32 mode; | ||
|
||
if (index >= AQR_MAX_LEDS) | ||
return -EINVAL; | ||
|
||
for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { | ||
switch (mode) { | ||
case PHY_LED_ACTIVE_LOW: | ||
active_low = true; | ||
break; | ||
default: | ||
return -EINVAL; | ||
} | ||
} | ||
|
||
/* Save LED driver vdd state to restore on SW reset */ | ||
if (active_low) | ||
priv->leds_active_low |= BIT(index); | ||
|
||
return aqr_phy_led_active_low_set(phydev, index, active_low); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters