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 void phy_led_trigger_change_speed(struct phy_device
*phy
)
32 struct phy_led_trigger
*plt
;
35 goto out_change_speed
;
40 plt
= phy_speed_to_led_trigger(phy
, phy
->speed
);
42 netdev_alert(phy
->attached_dev
,
43 "No phy led trigger registered for speed(%d)\n",
45 goto out_change_speed
;
48 if (plt
!= phy
->last_triggered
) {
49 led_trigger_event(&phy
->last_triggered
->trigger
, LED_OFF
);
50 led_trigger_event(&plt
->trigger
, LED_FULL
);
51 phy
->last_triggered
= plt
;
56 if (phy
->last_triggered
) {
57 led_trigger_event(&phy
->last_triggered
->trigger
,
59 phy
->last_triggered
= NULL
;
62 EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed
);
64 static int phy_led_trigger_register(struct phy_device
*phy
,
65 struct phy_led_trigger
*plt
,
68 char name_suffix
[PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE
];
72 if (speed
< SPEED_1000
)
73 snprintf(name_suffix
, sizeof(name_suffix
), "%dMbps", speed
);
74 else if (speed
== SPEED_2500
)
75 snprintf(name_suffix
, sizeof(name_suffix
), "2.5Gbps");
77 snprintf(name_suffix
, sizeof(name_suffix
), "%dGbps",
78 DIV_ROUND_CLOSEST(speed
, 1000));
80 snprintf(plt
->name
, sizeof(plt
->name
), PHY_ID_FMT
":%s",
81 phy
->mdio
.bus
->id
, phy
->mdio
.addr
, name_suffix
);
82 plt
->trigger
.name
= plt
->name
;
84 return led_trigger_register(&plt
->trigger
);
87 static void phy_led_trigger_unregister(struct phy_led_trigger
*plt
)
89 led_trigger_unregister(&plt
->trigger
);
92 int phy_led_triggers_register(struct phy_device
*phy
)
95 unsigned int speeds
[50];
97 phy
->phy_num_led_triggers
= phy_supported_speeds(phy
, speeds
,
99 if (!phy
->phy_num_led_triggers
)
102 phy
->phy_led_triggers
= devm_kzalloc(&phy
->mdio
.dev
,
103 sizeof(struct phy_led_trigger
) *
104 phy
->phy_num_led_triggers
,
106 if (!phy
->phy_led_triggers
) {
111 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++) {
112 err
= phy_led_trigger_register(phy
, &phy
->phy_led_triggers
[i
],
118 phy
->last_triggered
= NULL
;
119 phy_led_trigger_change_speed(phy
);
124 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
125 devm_kfree(&phy
->mdio
.dev
, phy
->phy_led_triggers
);
127 phy
->phy_num_led_triggers
= 0;
130 EXPORT_SYMBOL_GPL(phy_led_triggers_register
);
132 void phy_led_triggers_unregister(struct phy_device
*phy
)
136 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++)
137 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
139 EXPORT_SYMBOL_GPL(phy_led_triggers_unregister
);