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
);
64 led_trigger_event(&plt
->trigger
, LED_FULL
);
65 phy
->last_triggered
= plt
;
68 EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed
);
70 static void phy_led_trigger_format_name(struct phy_device
*phy
, char *buf
,
71 size_t size
, char *suffix
)
73 snprintf(buf
, size
, PHY_ID_FMT
":%s",
74 phy
->mdio
.bus
->id
, phy
->mdio
.addr
, suffix
);
77 static int phy_led_trigger_register(struct phy_device
*phy
,
78 struct phy_led_trigger
*plt
,
81 char name_suffix
[PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE
];
85 if (speed
< SPEED_1000
)
86 snprintf(name_suffix
, sizeof(name_suffix
), "%dMbps", speed
);
87 else if (speed
== SPEED_2500
)
88 snprintf(name_suffix
, sizeof(name_suffix
), "2.5Gbps");
90 snprintf(name_suffix
, sizeof(name_suffix
), "%dGbps",
91 DIV_ROUND_CLOSEST(speed
, 1000));
93 phy_led_trigger_format_name(phy
, plt
->name
, sizeof(plt
->name
),
95 plt
->trigger
.name
= plt
->name
;
97 return led_trigger_register(&plt
->trigger
);
100 static void phy_led_trigger_unregister(struct phy_led_trigger
*plt
)
102 led_trigger_unregister(&plt
->trigger
);
105 int phy_led_triggers_register(struct phy_device
*phy
)
108 unsigned int speeds
[50];
110 phy
->phy_num_led_triggers
= phy_supported_speeds(phy
, speeds
,
112 if (!phy
->phy_num_led_triggers
)
115 phy
->led_link_trigger
= devm_kzalloc(&phy
->mdio
.dev
,
116 sizeof(*phy
->led_link_trigger
),
118 if (!phy
->led_link_trigger
) {
123 phy_led_trigger_format_name(phy
, phy
->led_link_trigger
->name
,
124 sizeof(phy
->led_link_trigger
->name
),
126 phy
->led_link_trigger
->trigger
.name
= phy
->led_link_trigger
->name
;
128 err
= led_trigger_register(&phy
->led_link_trigger
->trigger
);
132 phy
->phy_led_triggers
= devm_kzalloc(&phy
->mdio
.dev
,
133 sizeof(struct phy_led_trigger
) *
134 phy
->phy_num_led_triggers
,
136 if (!phy
->phy_led_triggers
) {
141 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++) {
142 err
= phy_led_trigger_register(phy
, &phy
->phy_led_triggers
[i
],
148 phy
->last_triggered
= NULL
;
149 phy_led_trigger_change_speed(phy
);
154 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
155 devm_kfree(&phy
->mdio
.dev
, phy
->phy_led_triggers
);
157 phy_led_trigger_unregister(phy
->led_link_trigger
);
159 devm_kfree(&phy
->mdio
.dev
, phy
->led_link_trigger
);
160 phy
->led_link_trigger
= NULL
;
162 phy
->phy_num_led_triggers
= 0;
165 EXPORT_SYMBOL_GPL(phy_led_triggers_register
);
167 void phy_led_triggers_unregister(struct phy_device
*phy
)
171 for (i
= 0; i
< phy
->phy_num_led_triggers
; i
++)
172 phy_led_trigger_unregister(&phy
->phy_led_triggers
[i
]);
174 if (phy
->led_link_trigger
)
175 phy_led_trigger_unregister(phy
->led_link_trigger
);
177 EXPORT_SYMBOL_GPL(phy_led_triggers_unregister
);