1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000-2003
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6 
7 #include <common.h>
8 #include <status_led.h>
9 
10 /*
11  * The purpose of this code is to signal the operational status of a
12  * target which usually boots over the network; while running in
13  * U-Boot, a status LED is blinking. As soon as a valid BOOTP reply
14  * message has been received, the LED is turned off. The Linux
15  * kernel, once it is running, will start blinking the LED again,
16  * with another frequency.
17  */
18 
19 /* ------------------------------------------------------------------------- */
20 
21 typedef struct {
22 	led_id_t mask;
23 	int state;
24 	int period;
25 	int cnt;
26 } led_dev_t;
27 
28 led_dev_t led_dev[] = {
29 	{	CONFIG_LED_STATUS_BIT,
30 		CONFIG_LED_STATUS_STATE,
31 		LED_STATUS_PERIOD,
32 		0,
33 	},
34 #if defined(CONFIG_LED_STATUS1)
35 	{	CONFIG_LED_STATUS_BIT1,
36 		CONFIG_LED_STATUS_STATE1,
37 		LED_STATUS_PERIOD1,
38 		0,
39 	},
40 #endif
41 #if defined(CONFIG_LED_STATUS2)
42 	{	CONFIG_LED_STATUS_BIT2,
43 		CONFIG_LED_STATUS_STATE2,
44 		LED_STATUS_PERIOD2,
45 		0,
46 	},
47 #endif
48 #if defined(CONFIG_LED_STATUS3)
49 	{	CONFIG_LED_STATUS_BIT3,
50 		CONFIG_LED_STATUS_STATE3,
51 		LED_STATUS_PERIOD3,
52 		0,
53 	},
54 #endif
55 #if defined(CONFIG_LED_STATUS4)
56 	{	CONFIG_LED_STATUS_BIT4,
57 		CONFIG_LED_STATUS_STATE4,
58 		LED_STATUS_PERIOD4,
59 		0,
60 	},
61 #endif
62 #if defined(CONFIG_LED_STATUS5)
63 	{	CONFIG_LED_STATUS_BIT5,
64 		CONFIG_LED_STATUS_STATE5,
65 		LED_STATUS_PERIOD5,
66 		0,
67 	},
68 #endif
69 };
70 
71 #define MAX_LED_DEV	(sizeof(led_dev)/sizeof(led_dev_t))
72 
73 static int status_led_init_done = 0;
74 
status_led_init(void)75 void status_led_init(void)
76 {
77 	led_dev_t *ld;
78 	int i;
79 
80 	for (i = 0, ld = led_dev; i < MAX_LED_DEV; i++, ld++)
81 		__led_init (ld->mask, ld->state);
82 	status_led_init_done = 1;
83 }
84 
status_led_tick(ulong timestamp)85 void status_led_tick(ulong timestamp)
86 {
87 	led_dev_t *ld;
88 	int i;
89 
90 	if (!status_led_init_done)
91 		status_led_init();
92 
93 	for (i = 0, ld = led_dev; i < MAX_LED_DEV; i++, ld++) {
94 
95 		if (ld->state != CONFIG_LED_STATUS_BLINKING)
96 			continue;
97 
98 		if (++ld->cnt >= ld->period) {
99 			__led_toggle (ld->mask);
100 			ld->cnt -= ld->period;
101 		}
102 
103 	}
104 }
105 
status_led_set(int led,int state)106 void status_led_set(int led, int state)
107 {
108 	led_dev_t *ld;
109 
110 	if (led < 0 || led >= MAX_LED_DEV)
111 		return;
112 
113 	if (!status_led_init_done)
114 		status_led_init();
115 
116 	ld = &led_dev[led];
117 
118 	ld->state = state;
119 	if (state == CONFIG_LED_STATUS_BLINKING) {
120 		ld->cnt = 0;		/* always start with full period    */
121 		state = CONFIG_LED_STATUS_ON;	/* always start with LED _ON_ */
122 	}
123 	__led_set (ld->mask, state);
124 }
125