Skip to content

Commit c5a9657

Browse files
Dimitri Fedraukuba-moo
authored andcommitted
net: phy: dp83822: Add support for PHY LEDs on DP83822
The DP83822 supports up to three configurable Light Emitting Diode (LED) pins: LED_0, LED_1 (GPIO1), COL (GPIO2) and RX_D3 (GPIO3). Several functions can be multiplexed onto the LEDs for different modes of operation. LED_0 and COL (GPIO2) use the MLED function. MLED can be routed to only one of these two pins at a time. Add minimal LED controller driver supporting the most common uses with the 'netdev' trigger. Signed-off-by: Dimitri Fedrau <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 7dc8f80 commit c5a9657

File tree

1 file changed

+275
-2
lines changed

1 file changed

+275
-2
lines changed

drivers/net/phy/dp83822.c

Lines changed: 275 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
#define MII_DP83822_FCSCR 0x14
3131
#define MII_DP83822_RCSR 0x17
3232
#define MII_DP83822_RESET_CTRL 0x1f
33+
#define MII_DP83822_MLEDCR 0x25
34+
#define MII_DP83822_LEDCFG1 0x460
35+
#define MII_DP83822_IOCTRL1 0x462
3336
#define MII_DP83822_IOCTRL2 0x463
3437
#define MII_DP83822_GENCFG 0x465
3538
#define MII_DP83822_SOR1 0x467
@@ -105,10 +108,26 @@
105108
#define DP83822_RX_CLK_SHIFT BIT(12)
106109
#define DP83822_TX_CLK_SHIFT BIT(11)
107110

111+
/* MLEDCR bits */
112+
#define DP83822_MLEDCR_CFG GENMASK(6, 3)
113+
#define DP83822_MLEDCR_ROUTE GENMASK(1, 0)
114+
#define DP83822_MLEDCR_ROUTE_LED_0 DP83822_MLEDCR_ROUTE
115+
116+
/* LEDCFG1 bits */
117+
#define DP83822_LEDCFG1_LED1_CTRL GENMASK(11, 8)
118+
#define DP83822_LEDCFG1_LED3_CTRL GENMASK(7, 4)
119+
120+
/* IOCTRL1 bits */
121+
#define DP83822_IOCTRL1_GPIO3_CTRL GENMASK(10, 8)
122+
#define DP83822_IOCTRL1_GPIO3_CTRL_LED3 BIT(0)
123+
#define DP83822_IOCTRL1_GPIO1_CTRL GENMASK(2, 0)
124+
#define DP83822_IOCTRL1_GPIO1_CTRL_LED_1 BIT(0)
125+
108126
/* IOCTRL2 bits */
109127
#define DP83822_IOCTRL2_GPIO2_CLK_SRC GENMASK(6, 4)
110128
#define DP83822_IOCTRL2_GPIO2_CTRL GENMASK(2, 0)
111129
#define DP83822_IOCTRL2_GPIO2_CTRL_CLK_REF GENMASK(1, 0)
130+
#define DP83822_IOCTRL2_GPIO2_CTRL_MLED BIT(0)
112131

113132
#define DP83822_CLK_SRC_MAC_IF 0x0
114133
#define DP83822_CLK_SRC_XI 0x1
@@ -117,6 +136,22 @@
117136
#define DP83822_CLK_SRC_FREE_RUNNING 0x6
118137
#define DP83822_CLK_SRC_RECOVERED 0x7
119138

139+
#define DP83822_LED_FN_LINK 0x0 /* Link established */
140+
#define DP83822_LED_FN_RX_TX 0x1 /* Receive or Transmit activity */
141+
#define DP83822_LED_FN_TX 0x2 /* Transmit activity */
142+
#define DP83822_LED_FN_RX 0x3 /* Receive activity */
143+
#define DP83822_LED_FN_COLLISION 0x4 /* Collision detected */
144+
#define DP83822_LED_FN_LINK_100_BTX 0x5 /* 100 BTX link established */
145+
#define DP83822_LED_FN_LINK_10_BT 0x6 /* 10BT link established */
146+
#define DP83822_LED_FN_FULL_DUPLEX 0x7 /* Full duplex */
147+
#define DP83822_LED_FN_LINK_RX_TX 0x8 /* Link established, blink for rx or tx activity */
148+
#define DP83822_LED_FN_ACTIVE_STRETCH 0x9 /* Active Stretch Signal */
149+
#define DP83822_LED_FN_MII_LINK 0xa /* MII LINK (100BT+FD) */
150+
#define DP83822_LED_FN_LPI_MODE 0xb /* LPI Mode (EEE) */
151+
#define DP83822_LED_FN_RX_TX_ERR 0xc /* TX/RX MII Error */
152+
#define DP83822_LED_FN_LINK_LOST 0xd /* Link Lost */
153+
#define DP83822_LED_FN_PRBS_ERR 0xe /* Blink for PRBS error */
154+
120155
/* SOR1 mode */
121156
#define DP83822_STRAP_MODE1 0
122157
#define DP83822_STRAP_MODE2 BIT(0)
@@ -145,6 +180,13 @@
145180
ADVERTISED_FIBRE | \
146181
ADVERTISED_Pause | ADVERTISED_Asym_Pause)
147182

183+
#define DP83822_MAX_LED_PINS 4
184+
185+
#define DP83822_LED_INDEX_LED_0 0
186+
#define DP83822_LED_INDEX_LED_1_GPIO1 1
187+
#define DP83822_LED_INDEX_COL_GPIO2 2
188+
#define DP83822_LED_INDEX_RX_D3_GPIO3 3
189+
148190
struct dp83822_private {
149191
bool fx_signal_det_low;
150192
int fx_enabled;
@@ -154,6 +196,7 @@ struct dp83822_private {
154196
struct ethtool_wolinfo wol;
155197
bool set_gpio2_clk_out;
156198
u32 gpio2_clk_out;
199+
bool led_pin_enable[DP83822_MAX_LED_PINS];
157200
};
158201

159202
static int dp83822_config_wol(struct phy_device *phydev,
@@ -418,6 +461,48 @@ static int dp83822_read_status(struct phy_device *phydev)
418461
return 0;
419462
}
420463

464+
static int dp83822_config_init_leds(struct phy_device *phydev)
465+
{
466+
struct dp83822_private *dp83822 = phydev->priv;
467+
int ret;
468+
469+
if (dp83822->led_pin_enable[DP83822_LED_INDEX_LED_0]) {
470+
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, MII_DP83822_MLEDCR,
471+
DP83822_MLEDCR_ROUTE,
472+
FIELD_PREP(DP83822_MLEDCR_ROUTE,
473+
DP83822_MLEDCR_ROUTE_LED_0));
474+
if (ret)
475+
return ret;
476+
} else if (dp83822->led_pin_enable[DP83822_LED_INDEX_COL_GPIO2]) {
477+
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, MII_DP83822_IOCTRL2,
478+
DP83822_IOCTRL2_GPIO2_CTRL,
479+
FIELD_PREP(DP83822_IOCTRL2_GPIO2_CTRL,
480+
DP83822_IOCTRL2_GPIO2_CTRL_MLED));
481+
if (ret)
482+
return ret;
483+
}
484+
485+
if (dp83822->led_pin_enable[DP83822_LED_INDEX_LED_1_GPIO1]) {
486+
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, MII_DP83822_IOCTRL1,
487+
DP83822_IOCTRL1_GPIO1_CTRL,
488+
FIELD_PREP(DP83822_IOCTRL1_GPIO1_CTRL,
489+
DP83822_IOCTRL1_GPIO1_CTRL_LED_1));
490+
if (ret)
491+
return ret;
492+
}
493+
494+
if (dp83822->led_pin_enable[DP83822_LED_INDEX_RX_D3_GPIO3]) {
495+
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, MII_DP83822_IOCTRL1,
496+
DP83822_IOCTRL1_GPIO3_CTRL,
497+
FIELD_PREP(DP83822_IOCTRL1_GPIO3_CTRL,
498+
DP83822_IOCTRL1_GPIO3_CTRL_LED3));
499+
if (ret)
500+
return ret;
501+
}
502+
503+
return 0;
504+
}
505+
421506
static int dp83822_config_init(struct phy_device *phydev)
422507
{
423508
struct dp83822_private *dp83822 = phydev->priv;
@@ -437,6 +522,10 @@ static int dp83822_config_init(struct phy_device *phydev)
437522
FIELD_PREP(DP83822_IOCTRL2_GPIO2_CLK_SRC,
438523
dp83822->gpio2_clk_out));
439524

525+
err = dp83822_config_init_leds(phydev);
526+
if (err)
527+
return err;
528+
440529
if (phy_interface_is_rgmii(phydev)) {
441530
rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
442531
true);
@@ -631,6 +720,61 @@ static int dp83822_phy_reset(struct phy_device *phydev)
631720
}
632721

633722
#ifdef CONFIG_OF_MDIO
723+
static int dp83822_of_init_leds(struct phy_device *phydev)
724+
{
725+
struct device_node *node = phydev->mdio.dev.of_node;
726+
struct dp83822_private *dp83822 = phydev->priv;
727+
struct device_node *leds;
728+
u32 index;
729+
int err;
730+
731+
if (!node)
732+
return 0;
733+
734+
leds = of_get_child_by_name(node, "leds");
735+
if (!leds)
736+
return 0;
737+
738+
for_each_available_child_of_node_scoped(leds, led) {
739+
err = of_property_read_u32(led, "reg", &index);
740+
if (err) {
741+
of_node_put(leds);
742+
return err;
743+
}
744+
745+
if (index <= DP83822_LED_INDEX_RX_D3_GPIO3) {
746+
dp83822->led_pin_enable[index] = true;
747+
} else {
748+
of_node_put(leds);
749+
return -EINVAL;
750+
}
751+
}
752+
753+
of_node_put(leds);
754+
/* LED_0 and COL(GPIO2) use the MLED function. MLED can be routed to
755+
* only one of these two pins at a time.
756+
*/
757+
if (dp83822->led_pin_enable[DP83822_LED_INDEX_LED_0] &&
758+
dp83822->led_pin_enable[DP83822_LED_INDEX_COL_GPIO2]) {
759+
phydev_err(phydev, "LED_0 and COL(GPIO2) cannot be used as LED output at the same time\n");
760+
return -EINVAL;
761+
}
762+
763+
if (dp83822->led_pin_enable[DP83822_LED_INDEX_COL_GPIO2] &&
764+
dp83822->set_gpio2_clk_out) {
765+
phydev_err(phydev, "COL(GPIO2) cannot be used as LED outout, already used as clock output\n");
766+
return -EINVAL;
767+
}
768+
769+
if (dp83822->led_pin_enable[DP83822_LED_INDEX_RX_D3_GPIO3] &&
770+
phydev->interface != PHY_INTERFACE_MODE_RMII) {
771+
phydev_err(phydev, "RX_D3 can only be used as LED output when in RMII mode\n");
772+
return -EINVAL;
773+
}
774+
775+
return 0;
776+
}
777+
634778
static int dp83822_of_init(struct phy_device *phydev)
635779
{
636780
struct dp83822_private *dp83822 = phydev->priv;
@@ -671,7 +815,7 @@ static int dp83822_of_init(struct phy_device *phydev)
671815
dp83822->set_gpio2_clk_out = true;
672816
}
673817

674-
return 0;
818+
return dp83822_of_init_leds(phydev);
675819
}
676820

677821
static int dp83826_to_dac_minus_one_regval(int percent)
@@ -769,7 +913,9 @@ static int dp83822_probe(struct phy_device *phydev)
769913
if (ret)
770914
return ret;
771915

772-
dp83822_of_init(phydev);
916+
ret = dp83822_of_init(phydev);
917+
if (ret)
918+
return ret;
773919

774920
if (dp83822->fx_enabled)
775921
phydev->port = PORT_FIBRE;
@@ -816,6 +962,130 @@ static int dp83822_resume(struct phy_device *phydev)
816962
return 0;
817963
}
818964

965+
static int dp83822_led_mode(u8 index, unsigned long rules)
966+
{
967+
switch (rules) {
968+
case BIT(TRIGGER_NETDEV_LINK):
969+
return DP83822_LED_FN_LINK;
970+
case BIT(TRIGGER_NETDEV_LINK_10):
971+
return DP83822_LED_FN_LINK_10_BT;
972+
case BIT(TRIGGER_NETDEV_LINK_100):
973+
return DP83822_LED_FN_LINK_100_BTX;
974+
case BIT(TRIGGER_NETDEV_FULL_DUPLEX):
975+
return DP83822_LED_FN_FULL_DUPLEX;
976+
case BIT(TRIGGER_NETDEV_TX):
977+
return DP83822_LED_FN_TX;
978+
case BIT(TRIGGER_NETDEV_RX):
979+
return DP83822_LED_FN_RX;
980+
case BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX):
981+
return DP83822_LED_FN_RX_TX;
982+
case BIT(TRIGGER_NETDEV_TX_ERR) | BIT(TRIGGER_NETDEV_RX_ERR):
983+
return DP83822_LED_FN_RX_TX_ERR;
984+
case BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX):
985+
return DP83822_LED_FN_LINK_RX_TX;
986+
default:
987+
return -EOPNOTSUPP;
988+
}
989+
}
990+
991+
static int dp83822_led_hw_is_supported(struct phy_device *phydev, u8 index,
992+
unsigned long rules)
993+
{
994+
int mode;
995+
996+
mode = dp83822_led_mode(index, rules);
997+
if (mode < 0)
998+
return mode;
999+
1000+
return 0;
1001+
}
1002+
1003+
static int dp83822_led_hw_control_set(struct phy_device *phydev, u8 index,
1004+
unsigned long rules)
1005+
{
1006+
int mode;
1007+
1008+
mode = dp83822_led_mode(index, rules);
1009+
if (mode < 0)
1010+
return mode;
1011+
1012+
if (index == DP83822_LED_INDEX_LED_0 || index == DP83822_LED_INDEX_COL_GPIO2)
1013+
return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
1014+
MII_DP83822_MLEDCR, DP83822_MLEDCR_CFG,
1015+
FIELD_PREP(DP83822_MLEDCR_CFG, mode));
1016+
else if (index == DP83822_LED_INDEX_LED_1_GPIO1)
1017+
return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
1018+
MII_DP83822_LEDCFG1,
1019+
DP83822_LEDCFG1_LED1_CTRL,
1020+
FIELD_PREP(DP83822_LEDCFG1_LED1_CTRL,
1021+
mode));
1022+
else
1023+
return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
1024+
MII_DP83822_LEDCFG1,
1025+
DP83822_LEDCFG1_LED3_CTRL,
1026+
FIELD_PREP(DP83822_LEDCFG1_LED3_CTRL,
1027+
mode));
1028+
}
1029+
1030+
static int dp83822_led_hw_control_get(struct phy_device *phydev, u8 index,
1031+
unsigned long *rules)
1032+
{
1033+
int val;
1034+
1035+
if (index == DP83822_LED_INDEX_LED_0 || index == DP83822_LED_INDEX_COL_GPIO2) {
1036+
val = phy_read_mmd(phydev, MDIO_MMD_VEND2, MII_DP83822_MLEDCR);
1037+
if (val < 0)
1038+
return val;
1039+
1040+
val = FIELD_GET(DP83822_MLEDCR_CFG, val);
1041+
} else {
1042+
val = phy_read_mmd(phydev, MDIO_MMD_VEND2, MII_DP83822_LEDCFG1);
1043+
if (val < 0)
1044+
return val;
1045+
1046+
if (index == DP83822_LED_INDEX_LED_1_GPIO1)
1047+
val = FIELD_GET(DP83822_LEDCFG1_LED1_CTRL, val);
1048+
else
1049+
val = FIELD_GET(DP83822_LEDCFG1_LED3_CTRL, val);
1050+
}
1051+
1052+
switch (val) {
1053+
case DP83822_LED_FN_LINK:
1054+
*rules = BIT(TRIGGER_NETDEV_LINK);
1055+
break;
1056+
case DP83822_LED_FN_LINK_10_BT:
1057+
*rules = BIT(TRIGGER_NETDEV_LINK_10);
1058+
break;
1059+
case DP83822_LED_FN_LINK_100_BTX:
1060+
*rules = BIT(TRIGGER_NETDEV_LINK_100);
1061+
break;
1062+
case DP83822_LED_FN_FULL_DUPLEX:
1063+
*rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX);
1064+
break;
1065+
case DP83822_LED_FN_TX:
1066+
*rules = BIT(TRIGGER_NETDEV_TX);
1067+
break;
1068+
case DP83822_LED_FN_RX:
1069+
*rules = BIT(TRIGGER_NETDEV_RX);
1070+
break;
1071+
case DP83822_LED_FN_RX_TX:
1072+
*rules = BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
1073+
break;
1074+
case DP83822_LED_FN_RX_TX_ERR:
1075+
*rules = BIT(TRIGGER_NETDEV_TX_ERR) | BIT(TRIGGER_NETDEV_RX_ERR);
1076+
break;
1077+
case DP83822_LED_FN_LINK_RX_TX:
1078+
*rules = BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) |
1079+
BIT(TRIGGER_NETDEV_RX);
1080+
break;
1081+
default:
1082+
*rules = 0;
1083+
break;
1084+
}
1085+
1086+
return 0;
1087+
}
1088+
8191089
#define DP83822_PHY_DRIVER(_id, _name) \
8201090
{ \
8211091
PHY_ID_MATCH_MODEL(_id), \
@@ -831,6 +1101,9 @@ static int dp83822_resume(struct phy_device *phydev)
8311101
.handle_interrupt = dp83822_handle_interrupt, \
8321102
.suspend = dp83822_suspend, \
8331103
.resume = dp83822_resume, \
1104+
.led_hw_is_supported = dp83822_led_hw_is_supported, \
1105+
.led_hw_control_set = dp83822_led_hw_control_set, \
1106+
.led_hw_control_get = dp83822_led_hw_control_get, \
8341107
}
8351108

8361109
#define DP83825_PHY_DRIVER(_id, _name) \

0 commit comments

Comments
 (0)