1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (C) 2016 National Instruments Corp. */
3 #include <linux/leds.h>
5 #include <linux/phy_led_triggers.h>
6 #include <linux/netdevice.h>
8 static struct phy_led_trigger
*phy_speed_to_led_trigger(struct phy_device
*phy
,
13 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++) {
14 if (phy
->phy_led_triggers
[i
].speed
== speed
)
15 return &phy
->phy_led_triggers
[i
];
20 static void phy_led_trigger_no_link(struct phy_device
*phy
)
22 if (phy
->last_triggered
) {
23 led_trigger_event(&phy
->last_triggered
->trigger
, LED_OFF
);
24 led_trigger_event(&phy
->led_link_trigger
->trigger
, LED_OFF
);
25 phy
->last_triggered
= NULL
;
29 void phy_led_trigger_change_speed(struct phy_device
*phy
)
31 struct phy_led_trigger
*plt
;
34 return phy_led_trigger_no_link(phy
);
39 plt
= phy_speed_to_led_trigger(phy
, phy
->speed
);
41 netdev_alert(phy
->attached_dev
,
42 "No phy led trigger registered for speed(%d)\n",
44 return phy_led_trigger_no_link(phy
);
47 if (plt
!= phy
->last_triggered
) {
48 if (!phy
->last_triggered
)
49 led_trigger_event(&phy
->led_link_trigger
->trigger
,
52 led_trigger_event(&phy
->last_triggered
->trigger
, LED_OFF
);
53 led_trigger_event(&plt
->trigger
, LED_FULL
);
54 phy
->last_triggered
= plt
;
57 EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed
);
59 static void phy_led_trigger_format_name(struct phy_device
*phy
, char *buf
,
60 size_t size
, const char *suffix
)
62 snprintf(buf
, size
, PHY_ID_FMT
":%s",
63 phy
->mdio
.bus
->id
, phy
->mdio
.addr
, suffix
);
66 static int phy_led_trigger_register(struct phy_device
*phy
,
67 struct phy_led_trigger
*plt
,
71 phy_led_trigger_format_name(phy
, plt
->name
, sizeof(plt
->name
),
72 phy_speed_to_str(speed
));
73 plt
->trigger
.name
= plt
->name
;
75 return led_trigger_register(&plt
->trigger
);
78 static void phy_led_trigger_unregister(struct phy_led_trigger
*plt
)
80 led_trigger_unregister(&plt
->trigger
);
83 int phy_led_triggers_register(struct phy_device
*phy
)
86 unsigned int speeds
[50];
88 phy
->phy_num_led_triggers
= phy_supported_speeds(phy
, speeds
,
90 if (!phy
->phy_num_led_triggers
)
93 phy
->led_link_trigger
= devm_kzalloc(&phy
->mdio
.dev
,
94 sizeof(*phy
->led_link_trigger
),
96 if (!phy
->led_link_trigger
) {
101 phy_led_trigger_format_name(phy
, phy
->led_link_trigger
->name
,
102 sizeof(phy
->led_link_trigger
->name
),
104 phy
->led_link_trigger
->trigger
.name
= phy
->led_link_trigger
->name
;
106 err
= led_trigger_register(&phy
->led_link_trigger
->trigger
);
110 phy
->phy_led_triggers
= devm_kcalloc(&phy
->mdio
.dev
,
111 phy
->phy_num_led_triggers
,
112 sizeof(struct phy_led_trigger
),
114 if (!phy
->phy_led_triggers
) {
119 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++) {
120 err
= phy_led_trigger_register(phy
, &phy
->phy_led_triggers
[i
],
126 phy
->last_triggered
= NULL
;
127 phy_led_trigger_change_speed(phy
);
132 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
133 devm_kfree(&phy
->mdio
.dev
, phy
->phy_led_triggers
);
135 phy_led_trigger_unregister(phy
->led_link_trigger
);
137 devm_kfree(&phy
->mdio
.dev
, phy
->led_link_trigger
);
138 phy
->led_link_trigger
= NULL
;
140 phy
->phy_num_led_triggers
= 0;
143 EXPORT_SYMBOL_GPL(phy_led_triggers_register
);
145 void phy_led_triggers_unregister(struct phy_device
*phy
)
149 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++)
150 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
152 if (phy
->led_link_trigger
)
153 phy_led_trigger_unregister(phy
->led_link_trigger
);
155 EXPORT_SYMBOL_GPL(phy_led_triggers_unregister
);