diff mbox series

[net-next,v4,2/4] net: phy: add support for PHY LEDs polarity modes

Message ID 20231215212244.1658-3-ansuelsmth@gmail.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: phy: generic polarity + LED support for qca808x | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1564 this patch: 1564
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang success Errors and warnings before: 1156 this patch: 1156
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1600 this patch: 1600
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 100 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Christian Marangi Dec. 15, 2023, 9:22 p.m. UTC
Add support for PHY LEDs polarity modes. Some device might require
special polarity mode for the LED to correctly work and those mode
doesn't reflect what the PHY sets by default.

An example is a PHY device that set LED to active high but the attached
LEDs require to be active low to correctly work (and turn on when
actually requested)

PHY driver needs to declare .led_polarity_set() to configure LED
polarity. Index of the LED is passed and the polarity mode in the enum.

If a polarity is not set in DT and .led_polarity_set() is declared,
PHY_LED_POLARITY_DEFAULT is passed as polarity mode to let the PHY
driver decide a default polarity mode for the attached LEDs.

This is needed for PHY that sets active high on reset and the common
configuration is LEDs with active low polarity.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
Changes v4:
- Drop for global active-low
- Rework to polarity option (for marvell10g series support)
Changes v3:
- Out of RFC
Changes v2:
- Add this patch

 drivers/net/phy/phy_device.c | 45 ++++++++++++++++++++++++++++++++++++
 include/linux/phy.h          | 25 ++++++++++++++++++++
 2 files changed, 70 insertions(+)
diff mbox series

Patch

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index d8e9335d415c..b35b7a8717cc 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -43,6 +43,13 @@  MODULE_DESCRIPTION("PHY library");
 MODULE_AUTHOR("Andy Fleming");
 MODULE_LICENSE("GPL");
 
+static const char * const phy_led_polarity_mode_strings[] = {
+	[PHY_LED_POLARITY_ACTIVE_LOW] = "active-low",
+	[PHY_LED_POLARITY_ACTIVE_HIGH] = "active-high",
+	[PHY_LED_POLARITY_ACTIVE_LOW_TRISTATED] = "active-low-tristated",
+	[PHY_LED_POLARITY_ACTIVE_HIGH_TRISTATED] = "active-low-tristated",
+};
+
 __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) __ro_after_init;
 EXPORT_SYMBOL_GPL(phy_basic_features);
 
@@ -3086,6 +3093,40 @@  static void phy_leds_unregister(struct phy_device *phydev)
 	}
 }
 
+static int of_phy_set_led_polarity(struct phy_device *phydev,
+				   struct device_node *led, u32 index)
+{
+	const char *polarity_str;
+	int i, err;
+
+	err = of_property_read_string(led, "polarity", &polarity_str);
+	if (err) {
+		if (err != -EINVAL)
+			return err;
+
+		/* Nothing to do, polarity setting not supported */
+		if (!phydev->drv->led_polarity_set)
+			return 0;
+
+		/* Apply default polarity if supported */
+		return phydev->drv->led_polarity_set(phydev, index,
+						     PHY_LED_POLARITY_DEFAULT);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(phy_led_polarity_mode_strings); i++)
+		if (!strcmp(phy_led_polarity_mode_strings[i], polarity_str)) {
+			if (!phydev->drv->led_polarity_set) {
+				phydev_warn(phydev, "Ignoring LED polarity in DT. Setting polarity not supported\n");
+				return 0;
+			}
+
+			return phydev->drv->led_polarity_set(phydev, index, i);
+		}
+
+	/* Unknown polarity mode declared */
+	return -EINVAL;
+}
+
 static int of_phy_led(struct phy_device *phydev,
 		      struct device_node *led)
 {
@@ -3109,6 +3150,10 @@  static int of_phy_led(struct phy_device *phydev,
 	if (index > U8_MAX)
 		return -EINVAL;
 
+	err = of_phy_set_led_polarity(phydev, led, index);
+	if (err)
+		return err;
+
 	phyled->index = index;
 	if (phydev->drv->led_brightness_set)
 		cdev->brightness_set_blocking = phy_led_set_brightness;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 6e7ebcc50b85..88ff4195bc4f 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -852,6 +852,16 @@  struct phy_plca_status {
 	bool pst;
 };
 
+enum phy_led_polarity_modes {
+	PHY_LED_POLARITY_ACTIVE_LOW,
+	PHY_LED_POLARITY_ACTIVE_HIGH,
+	PHY_LED_POLARITY_ACTIVE_LOW_TRISTATED,
+	PHY_LED_POLARITY_ACTIVE_HIGH_TRISTATED,
+
+	/* PHY driver apply a default value */
+	PHY_LED_POLARITY_DEFAULT,
+};
+
 /**
  * struct phy_led: An LED driven by the PHY
  *
@@ -1145,6 +1155,21 @@  struct phy_driver {
 	int (*led_hw_control_get)(struct phy_device *dev, u8 index,
 				  unsigned long *rules);
 
+	/**
+	 * @led_polarity_set: Set the LED polarity mode
+	 * @dev: PHY device which has the LED
+	 * @index: Which LED of the PHY device
+	 * @polarity_mode: LED polarity mode from enum
+	 *
+	 * Set PHY to requested LED polarity mode.
+	 *
+	 * If polarity mode PHY_LED_POLARITY_DEFAULT is passed,
+	 * PHY driver should apply a default LED polarity mode.
+	 *
+	 * Returns 0, or an error code.
+	 */
+	int (*led_polarity_set)(struct phy_device *dev, int index,
+				enum phy_led_polarity_modes polarity_mode);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),		\
 				      struct phy_driver, mdiodrv)