1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
4*4882a593Smuzhiyun * Copyright 2012, Kurt Van Dijck <kurt.van.dijck@eia.be>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/device.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/netdevice.h>
12*4882a593Smuzhiyun #include <linux/can/dev.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <linux/can/led.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun static unsigned long led_delay = 50;
17*4882a593Smuzhiyun module_param(led_delay, ulong, 0644);
18*4882a593Smuzhiyun MODULE_PARM_DESC(led_delay,
19*4882a593Smuzhiyun "blink delay time for activity leds (msecs, default: 50).");
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /* Trigger a LED event in response to a CAN device event */
can_led_event(struct net_device * netdev,enum can_led_event event)22*4882a593Smuzhiyun void can_led_event(struct net_device *netdev, enum can_led_event event)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun struct can_priv *priv = netdev_priv(netdev);
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun switch (event) {
27*4882a593Smuzhiyun case CAN_LED_EVENT_OPEN:
28*4882a593Smuzhiyun led_trigger_event(priv->tx_led_trig, LED_FULL);
29*4882a593Smuzhiyun led_trigger_event(priv->rx_led_trig, LED_FULL);
30*4882a593Smuzhiyun led_trigger_event(priv->rxtx_led_trig, LED_FULL);
31*4882a593Smuzhiyun break;
32*4882a593Smuzhiyun case CAN_LED_EVENT_STOP:
33*4882a593Smuzhiyun led_trigger_event(priv->tx_led_trig, LED_OFF);
34*4882a593Smuzhiyun led_trigger_event(priv->rx_led_trig, LED_OFF);
35*4882a593Smuzhiyun led_trigger_event(priv->rxtx_led_trig, LED_OFF);
36*4882a593Smuzhiyun break;
37*4882a593Smuzhiyun case CAN_LED_EVENT_TX:
38*4882a593Smuzhiyun if (led_delay) {
39*4882a593Smuzhiyun led_trigger_blink_oneshot(priv->tx_led_trig,
40*4882a593Smuzhiyun &led_delay, &led_delay, 1);
41*4882a593Smuzhiyun led_trigger_blink_oneshot(priv->rxtx_led_trig,
42*4882a593Smuzhiyun &led_delay, &led_delay, 1);
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun break;
45*4882a593Smuzhiyun case CAN_LED_EVENT_RX:
46*4882a593Smuzhiyun if (led_delay) {
47*4882a593Smuzhiyun led_trigger_blink_oneshot(priv->rx_led_trig,
48*4882a593Smuzhiyun &led_delay, &led_delay, 1);
49*4882a593Smuzhiyun led_trigger_blink_oneshot(priv->rxtx_led_trig,
50*4882a593Smuzhiyun &led_delay, &led_delay, 1);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun break;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(can_led_event);
56*4882a593Smuzhiyun
can_led_release(struct device * gendev,void * res)57*4882a593Smuzhiyun static void can_led_release(struct device *gendev, void *res)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun struct can_priv *priv = netdev_priv(to_net_dev(gendev));
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun led_trigger_unregister_simple(priv->tx_led_trig);
62*4882a593Smuzhiyun led_trigger_unregister_simple(priv->rx_led_trig);
63*4882a593Smuzhiyun led_trigger_unregister_simple(priv->rxtx_led_trig);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /* Register CAN LED triggers for a CAN device
67*4882a593Smuzhiyun *
68*4882a593Smuzhiyun * This is normally called from a driver's probe function
69*4882a593Smuzhiyun */
devm_can_led_init(struct net_device * netdev)70*4882a593Smuzhiyun void devm_can_led_init(struct net_device *netdev)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun struct can_priv *priv = netdev_priv(netdev);
73*4882a593Smuzhiyun void *res;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun res = devres_alloc(can_led_release, 0, GFP_KERNEL);
76*4882a593Smuzhiyun if (!res) {
77*4882a593Smuzhiyun netdev_err(netdev, "cannot register LED triggers\n");
78*4882a593Smuzhiyun return;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun snprintf(priv->tx_led_trig_name, sizeof(priv->tx_led_trig_name),
82*4882a593Smuzhiyun "%s-tx", netdev->name);
83*4882a593Smuzhiyun snprintf(priv->rx_led_trig_name, sizeof(priv->rx_led_trig_name),
84*4882a593Smuzhiyun "%s-rx", netdev->name);
85*4882a593Smuzhiyun snprintf(priv->rxtx_led_trig_name, sizeof(priv->rxtx_led_trig_name),
86*4882a593Smuzhiyun "%s-rxtx", netdev->name);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun led_trigger_register_simple(priv->tx_led_trig_name,
89*4882a593Smuzhiyun &priv->tx_led_trig);
90*4882a593Smuzhiyun led_trigger_register_simple(priv->rx_led_trig_name,
91*4882a593Smuzhiyun &priv->rx_led_trig);
92*4882a593Smuzhiyun led_trigger_register_simple(priv->rxtx_led_trig_name,
93*4882a593Smuzhiyun &priv->rxtx_led_trig);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun devres_add(&netdev->dev, res);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(devm_can_led_init);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* NETDEV rename notifier to rename the associated led triggers too */
can_led_notifier(struct notifier_block * nb,unsigned long msg,void * ptr)100*4882a593Smuzhiyun static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
101*4882a593Smuzhiyun void *ptr)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
104*4882a593Smuzhiyun struct can_priv *priv = safe_candev_priv(netdev);
105*4882a593Smuzhiyun char name[CAN_LED_NAME_SZ];
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (!priv)
108*4882a593Smuzhiyun return NOTIFY_DONE;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (!priv->tx_led_trig || !priv->rx_led_trig || !priv->rxtx_led_trig)
111*4882a593Smuzhiyun return NOTIFY_DONE;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun if (msg == NETDEV_CHANGENAME) {
114*4882a593Smuzhiyun snprintf(name, sizeof(name), "%s-tx", netdev->name);
115*4882a593Smuzhiyun led_trigger_rename_static(name, priv->tx_led_trig);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun snprintf(name, sizeof(name), "%s-rx", netdev->name);
118*4882a593Smuzhiyun led_trigger_rename_static(name, priv->rx_led_trig);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun snprintf(name, sizeof(name), "%s-rxtx", netdev->name);
121*4882a593Smuzhiyun led_trigger_rename_static(name, priv->rxtx_led_trig);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun return NOTIFY_DONE;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* notifier block for netdevice event */
128*4882a593Smuzhiyun static struct notifier_block can_netdev_notifier __read_mostly = {
129*4882a593Smuzhiyun .notifier_call = can_led_notifier,
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun
can_led_notifier_init(void)132*4882a593Smuzhiyun int __init can_led_notifier_init(void)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun return register_netdevice_notifier(&can_netdev_notifier);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
can_led_notifier_exit(void)137*4882a593Smuzhiyun void __exit can_led_notifier_exit(void)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun unregister_netdevice_notifier(&can_netdev_notifier);
140*4882a593Smuzhiyun }
141