1 /* Copyright (C) 2016 National Instruments Corp.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 #include <linux/leds.h>
14 #include <linux/phy.h>
15 #include <linux/phy_led_triggers.h>
16 #include <linux/netdevice.h>
18 static struct phy_led_trigger
*phy_speed_to_led_trigger(struct phy_device
*phy
,
23 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++) {
24 if (phy
->phy_led_triggers
[i
].speed
== speed
)
25 return &phy
->phy_led_triggers
[i
];
30 static void phy_led_trigger_no_link(struct phy_device
*phy
)
32 if (phy
->last_triggered
) {
33 led_trigger_event(&phy
->last_triggered
->trigger
, LED_OFF
);
34 led_trigger_event(&phy
->led_link_trigger
->trigger
, LED_OFF
);
35 phy
->last_triggered
= NULL
;
39 void phy_led_trigger_change_speed(struct phy_device
*phy
)
41 struct phy_led_trigger
*plt
;
44 return phy_led_trigger_no_link(phy
);
49 plt
= phy_speed_to_led_trigger(phy
, phy
->speed
);
51 netdev_alert(phy
->attached_dev
,
52 "No phy led trigger registered for speed(%d)\n",
54 return phy_led_trigger_no_link(phy
);
57 if (plt
!= phy
->last_triggered
) {
58 if (!phy
->last_triggered
)
59 led_trigger_event(&phy
->led_link_trigger
->trigger
,
62 led_trigger_event(&phy
->last_triggered
->trigger
, LED_OFF
);
63 led_trigger_event(&plt
->trigger
, LED_FULL
);
64 phy
->last_triggered
= plt
;
67 EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed
);
69 static void phy_led_trigger_format_name(struct phy_device
*phy
, char *buf
,
70 size_t size
, char *suffix
)
72 snprintf(buf
, size
, PHY_ID_FMT
":%s",
73 phy
->mdio
.bus
->id
, phy
->mdio
.addr
, suffix
);
76 static int phy_led_trigger_register(struct phy_device
*phy
,
77 struct phy_led_trigger
*plt
,
80 char name_suffix
[PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE
];
84 if (speed
< SPEED_1000
)
85 snprintf(name_suffix
, sizeof(name_suffix
), "%dMbps", speed
);
86 else if (speed
== SPEED_2500
)
87 snprintf(name_suffix
, sizeof(name_suffix
), "2.5Gbps");
89 snprintf(name_suffix
, sizeof(name_suffix
), "%dGbps",
90 DIV_ROUND_CLOSEST(speed
, 1000));
92 phy_led_trigger_format_name(phy
, plt
->name
, sizeof(plt
->name
),
94 plt
->trigger
.name
= plt
->name
;
96 return led_trigger_register(&plt
->trigger
);
99 static void phy_led_trigger_unregister(struct phy_led_trigger
*plt
)
101 led_trigger_unregister(&plt
->trigger
);
104 int phy_led_triggers_register(struct phy_device
*phy
)
107 unsigned int speeds
[50];
109 phy
->phy_num_led_triggers
= phy_supported_speeds(phy
, speeds
,
111 if (!phy
->phy_num_led_triggers
)
114 phy
->led_link_trigger
= devm_kzalloc(&phy
->mdio
.dev
,
115 sizeof(*phy
->led_link_trigger
),
117 if (!phy
->led_link_trigger
) {
122 phy_led_trigger_format_name(phy
, phy
->led_link_trigger
->name
,
123 sizeof(phy
->led_link_trigger
->name
),
125 phy
->led_link_trigger
->trigger
.name
= phy
->led_link_trigger
->name
;
127 err
= led_trigger_register(&phy
->led_link_trigger
->trigger
);
131 phy
->phy_led_triggers
= devm_kzalloc(&phy
->mdio
.dev
,
132 sizeof(struct phy_led_trigger
) *
133 phy
->phy_num_led_triggers
,
135 if (!phy
->phy_led_triggers
) {
140 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++) {
141 err
= phy_led_trigger_register(phy
, &phy
->phy_led_triggers
[i
],
147 phy
->last_triggered
= NULL
;
148 phy_led_trigger_change_speed(phy
);
153 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
154 devm_kfree(&phy
->mdio
.dev
, phy
->phy_led_triggers
);
156 phy_led_trigger_unregister(phy
->led_link_trigger
);
158 devm_kfree(&phy
->mdio
.dev
, phy
->led_link_trigger
);
159 phy
->led_link_trigger
= NULL
;
161 phy
->phy_num_led_triggers
= 0;
164 EXPORT_SYMBOL_GPL(phy_led_triggers_register
);
166 void phy_led_triggers_unregister(struct phy_device
*phy
)
170 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++)
171 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
173 if (phy
->led_link_trigger
)
174 phy_led_trigger_unregister(phy
->led_link_trigger
);
176 EXPORT_SYMBOL_GPL(phy_led_triggers_unregister
);