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
);
54 led_trigger_event(&plt
->trigger
, LED_FULL
);
55 phy
->last_triggered
= plt
;
58 EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed
);
60 static void phy_led_trigger_format_name(struct phy_device
*phy
, char *buf
,
61 size_t size
, const char *suffix
)
63 snprintf(buf
, size
, PHY_ID_FMT
":%s",
64 phy
->mdio
.bus
->id
, phy
->mdio
.addr
, suffix
);
67 static int phy_led_trigger_register(struct phy_device
*phy
,
68 struct phy_led_trigger
*plt
,
73 phy_led_trigger_format_name(phy
, plt
->name
, sizeof(plt
->name
), suffix
);
74 plt
->trigger
.name
= plt
->name
;
76 return led_trigger_register(&plt
->trigger
);
79 static void phy_led_trigger_unregister(struct phy_led_trigger
*plt
)
81 led_trigger_unregister(&plt
->trigger
);
84 int phy_led_triggers_register(struct phy_device
*phy
)
87 unsigned int speeds
[50];
89 phy
->phy_num_led_triggers
= phy_supported_speeds(phy
, speeds
,
91 if (!phy
->phy_num_led_triggers
)
94 phy
->led_link_trigger
= devm_kzalloc(&phy
->mdio
.dev
,
95 sizeof(*phy
->led_link_trigger
),
97 if (!phy
->led_link_trigger
) {
102 err
= phy_led_trigger_register(phy
, phy
->led_link_trigger
, 0, "link");
106 phy
->phy_led_triggers
= devm_kcalloc(&phy
->mdio
.dev
,
107 phy
->phy_num_led_triggers
,
108 sizeof(struct phy_led_trigger
),
110 if (!phy
->phy_led_triggers
) {
115 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++) {
116 err
= phy_led_trigger_register(phy
, &phy
->phy_led_triggers
[i
],
118 phy_speed_to_str(speeds
[i
]));
123 phy
->last_triggered
= NULL
;
124 phy_led_trigger_change_speed(phy
);
129 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
130 devm_kfree(&phy
->mdio
.dev
, phy
->phy_led_triggers
);
132 phy_led_trigger_unregister(phy
->led_link_trigger
);
134 devm_kfree(&phy
->mdio
.dev
, phy
->led_link_trigger
);
135 phy
->led_link_trigger
= NULL
;
137 phy
->phy_num_led_triggers
= 0;
140 EXPORT_SYMBOL_GPL(phy_led_triggers_register
);
142 void phy_led_triggers_unregister(struct phy_device
*phy
)
146 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++)
147 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
149 if (phy
->led_link_trigger
)
150 phy_led_trigger_unregister(phy
->led_link_trigger
);
152 EXPORT_SYMBOL_GPL(phy_led_triggers_unregister
);