1 /*
2  *  LEDs triggers for power supply class
3  *
4  *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
5  *  Copyright © 2004  Szabolcs Gyurko
6  *  Copyright © 2003  Ian Molton <spyro@f2s.com>
7  *
8  *  Modified: 2004, Oct     Szabolcs Gyurko
9  *
10  *  You may use this code as per GPL version 2
11  */
12 
13 #include <linux/kernel.h>
14 #include <linux/power_supply.h>
15 #include <linux/slab.h>
16 
17 #include "power_supply.h"
18 
19 /* Battery specific LEDs triggers. */
20 
power_supply_update_bat_leds(struct power_supply * psy)21 static void power_supply_update_bat_leds(struct power_supply *psy)
22 {
23 	union power_supply_propval status;
24 	unsigned long delay_on = 0;
25 	unsigned long delay_off = 0;
26 
27 	if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
28 		return;
29 
30 	dev_dbg(psy->dev, "%s %d\n", __func__, status.intval);
31 
32 	switch (status.intval) {
33 	case POWER_SUPPLY_STATUS_FULL:
34 		led_trigger_event(psy->charging_full_trig, LED_FULL);
35 		led_trigger_event(psy->charging_trig, LED_OFF);
36 		led_trigger_event(psy->full_trig, LED_FULL);
37 		led_trigger_event(psy->charging_blink_full_solid_trig,
38 			LED_FULL);
39 		break;
40 	case POWER_SUPPLY_STATUS_CHARGING:
41 		led_trigger_event(psy->charging_full_trig, LED_FULL);
42 		led_trigger_event(psy->charging_trig, LED_FULL);
43 		led_trigger_event(psy->full_trig, LED_OFF);
44 		led_trigger_blink(psy->charging_blink_full_solid_trig,
45 			&delay_on, &delay_off);
46 		break;
47 	default:
48 		led_trigger_event(psy->charging_full_trig, LED_OFF);
49 		led_trigger_event(psy->charging_trig, LED_OFF);
50 		led_trigger_event(psy->full_trig, LED_OFF);
51 		led_trigger_event(psy->charging_blink_full_solid_trig,
52 			LED_OFF);
53 		break;
54 	}
55 }
56 
power_supply_create_bat_triggers(struct power_supply * psy)57 static int power_supply_create_bat_triggers(struct power_supply *psy)
58 {
59 	int rc = 0;
60 
61 	psy->charging_full_trig_name = kasprintf(GFP_KERNEL,
62 					"%s-charging-or-full", psy->name);
63 	if (!psy->charging_full_trig_name)
64 		goto charging_full_failed;
65 
66 	psy->charging_trig_name = kasprintf(GFP_KERNEL,
67 					"%s-charging", psy->name);
68 	if (!psy->charging_trig_name)
69 		goto charging_failed;
70 
71 	psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->name);
72 	if (!psy->full_trig_name)
73 		goto full_failed;
74 
75 	psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL,
76 		"%s-charging-blink-full-solid", psy->name);
77 	if (!psy->charging_blink_full_solid_trig_name)
78 		goto charging_blink_full_solid_failed;
79 
80 	led_trigger_register_simple(psy->charging_full_trig_name,
81 				    &psy->charging_full_trig);
82 	led_trigger_register_simple(psy->charging_trig_name,
83 				    &psy->charging_trig);
84 	led_trigger_register_simple(psy->full_trig_name,
85 				    &psy->full_trig);
86 	led_trigger_register_simple(psy->charging_blink_full_solid_trig_name,
87 				    &psy->charging_blink_full_solid_trig);
88 
89 	goto success;
90 
91 charging_blink_full_solid_failed:
92 	kfree(psy->full_trig_name);
93 full_failed:
94 	kfree(psy->charging_trig_name);
95 charging_failed:
96 	kfree(psy->charging_full_trig_name);
97 charging_full_failed:
98 	rc = -ENOMEM;
99 success:
100 	return rc;
101 }
102 
power_supply_remove_bat_triggers(struct power_supply * psy)103 static void power_supply_remove_bat_triggers(struct power_supply *psy)
104 {
105 	led_trigger_unregister_simple(psy->charging_full_trig);
106 	led_trigger_unregister_simple(psy->charging_trig);
107 	led_trigger_unregister_simple(psy->full_trig);
108 	led_trigger_unregister_simple(psy->charging_blink_full_solid_trig);
109 	kfree(psy->charging_blink_full_solid_trig_name);
110 	kfree(psy->full_trig_name);
111 	kfree(psy->charging_trig_name);
112 	kfree(psy->charging_full_trig_name);
113 }
114 
115 /* Generated power specific LEDs triggers. */
116 
power_supply_update_gen_leds(struct power_supply * psy)117 static void power_supply_update_gen_leds(struct power_supply *psy)
118 {
119 	union power_supply_propval online;
120 
121 	if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
122 		return;
123 
124 	dev_dbg(psy->dev, "%s %d\n", __func__, online.intval);
125 
126 	if (online.intval)
127 		led_trigger_event(psy->online_trig, LED_FULL);
128 	else
129 		led_trigger_event(psy->online_trig, LED_OFF);
130 }
131 
power_supply_create_gen_triggers(struct power_supply * psy)132 static int power_supply_create_gen_triggers(struct power_supply *psy)
133 {
134 	int rc = 0;
135 
136 	psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online", psy->name);
137 	if (!psy->online_trig_name)
138 		goto online_failed;
139 
140 	led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
141 
142 	goto success;
143 
144 online_failed:
145 	rc = -ENOMEM;
146 success:
147 	return rc;
148 }
149 
power_supply_remove_gen_triggers(struct power_supply * psy)150 static void power_supply_remove_gen_triggers(struct power_supply *psy)
151 {
152 	led_trigger_unregister_simple(psy->online_trig);
153 	kfree(psy->online_trig_name);
154 }
155 
156 /* Choice what triggers to create&update. */
157 
power_supply_update_leds(struct power_supply * psy)158 void power_supply_update_leds(struct power_supply *psy)
159 {
160 	if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
161 		power_supply_update_bat_leds(psy);
162 	else
163 		power_supply_update_gen_leds(psy);
164 }
165 
power_supply_create_triggers(struct power_supply * psy)166 int power_supply_create_triggers(struct power_supply *psy)
167 {
168 	if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
169 		return power_supply_create_bat_triggers(psy);
170 	return power_supply_create_gen_triggers(psy);
171 }
172 
power_supply_remove_triggers(struct power_supply * psy)173 void power_supply_remove_triggers(struct power_supply *psy)
174 {
175 	if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
176 		power_supply_remove_bat_triggers(psy);
177 	else
178 		power_supply_remove_gen_triggers(psy);
179 }
180