File Index
Files and directories
Sign in
FILE

aquantia_leds.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/phy/aquantia/aquantia_leds.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* LED driver for Aquantia PHY
  3 *
  4 * Author: Daniel Golle <daniel@makrotopia.org>
  5 */
  6
  7#include <linux/phy.h>
  8
  9#include "aquantia.h"
 10
 11int aqr_phy_led_brightness_set(struct phy_device *phydev,
 12			       u8 index, enum led_brightness value)
 13{
 14	if (index >= AQR_MAX_LEDS)
 15		return -EINVAL;
 16
 17	return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
 18			      VEND1_GLOBAL_LED_PROV_LINK_MASK |
 19			      VEND1_GLOBAL_LED_PROV_FORCE_ON |
 20			      VEND1_GLOBAL_LED_PROV_RX_ACT |
 21			      VEND1_GLOBAL_LED_PROV_TX_ACT,
 22			      value ? VEND1_GLOBAL_LED_PROV_FORCE_ON : 0);
 23}
 24
 25static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
 26						 BIT(TRIGGER_NETDEV_LINK_100) |
 27						 BIT(TRIGGER_NETDEV_LINK_1000) |
 28						 BIT(TRIGGER_NETDEV_LINK_2500) |
 29						 BIT(TRIGGER_NETDEV_LINK_5000) |
 30						 BIT(TRIGGER_NETDEV_LINK_10000)  |
 31						 BIT(TRIGGER_NETDEV_RX) |
 32						 BIT(TRIGGER_NETDEV_TX));
 33
 34int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
 35				unsigned long rules)
 36{
 37	if (index >= AQR_MAX_LEDS)
 38		return -EINVAL;
 39
 40	/* All combinations of the supported triggers are allowed */
 41	if (rules & ~supported_triggers)
 42		return -EOPNOTSUPP;
 43
 44	return 0;
 45}
 46
 47int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
 48			       unsigned long *rules)
 49{
 50	int val;
 51
 52	if (index >= AQR_MAX_LEDS)
 53		return -EINVAL;
 54
 55	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index));
 56	if (val < 0)
 57		return val;
 58
 59	*rules = 0;
 60	if (val & VEND1_GLOBAL_LED_PROV_LINK100)
 61		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
 62
 63	if (val & VEND1_GLOBAL_LED_PROV_LINK1000)
 64		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
 65
 66	if (val & VEND1_GLOBAL_LED_PROV_LINK2500)
 67		*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
 68
 69	if (val & VEND1_GLOBAL_LED_PROV_LINK5000)
 70		*rules |= BIT(TRIGGER_NETDEV_LINK_5000);
 71
 72	if (val & VEND1_GLOBAL_LED_PROV_LINK10000)
 73		*rules |= BIT(TRIGGER_NETDEV_LINK_10000);
 74
 75	if (val & VEND1_GLOBAL_LED_PROV_RX_ACT)
 76		*rules |= BIT(TRIGGER_NETDEV_RX);
 77
 78	if (val & VEND1_GLOBAL_LED_PROV_TX_ACT)
 79		*rules |= BIT(TRIGGER_NETDEV_TX);
 80
 81	return 0;
 82}
 83
 84int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
 85			       unsigned long rules)
 86{
 87	u16 val = 0;
 88
 89	if (index >= AQR_MAX_LEDS)
 90		return -EINVAL;
 91
 92	if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
 93		val |= VEND1_GLOBAL_LED_PROV_LINK100;
 94
 95	if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
 96		val |= VEND1_GLOBAL_LED_PROV_LINK1000;
 97
 98	if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
 99		val |= VEND1_GLOBAL_LED_PROV_LINK2500;
100
101	if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK)))
102		val |= VEND1_GLOBAL_LED_PROV_LINK5000;
103
104	if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK)))
105		val |= VEND1_GLOBAL_LED_PROV_LINK10000;
106
107	if (rules & BIT(TRIGGER_NETDEV_RX))
108		val |= VEND1_GLOBAL_LED_PROV_RX_ACT;
109
110	if (rules & BIT(TRIGGER_NETDEV_TX))
111		val |= VEND1_GLOBAL_LED_PROV_TX_ACT;
112
113	return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
114			      VEND1_GLOBAL_LED_PROV_LINK_MASK |
115			      VEND1_GLOBAL_LED_PROV_FORCE_ON |
116			      VEND1_GLOBAL_LED_PROV_RX_ACT |
117			      VEND1_GLOBAL_LED_PROV_TX_ACT, val);
118}
119
120int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable)
121{
122	return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
123			      VEND1_GLOBAL_LED_DRIVE_VDD,
124			      enable ? 0 : VEND1_GLOBAL_LED_DRIVE_VDD);
125}
126
127int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
128{
129	bool force_active_low = false, force_active_high = false;
130	struct aqr107_priv *priv = phydev->priv;
131	u32 mode;
132
133	if (index >= AQR_MAX_LEDS)
134		return -EINVAL;
135
136	for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
137		switch (mode) {
138		case PHY_LED_ACTIVE_LOW:
139			force_active_low = true;
140			break;
141		case PHY_LED_ACTIVE_HIGH:
142			force_active_high = true;
143			break;
144		default:
145			return -EINVAL;
146		}
147	}
148
149	/* Save LED driver vdd state to restore on SW reset */
150	if (force_active_low)
151		priv->leds_active_low |= BIT(index);
152
153	if (force_active_high)
154		priv->leds_active_high |= BIT(index);
155
156	if (force_active_high || force_active_low)
157		return aqr_phy_led_active_low_set(phydev, index, force_active_low);
158
159	return -EINVAL;
160}
~/ Read-only file preview.