1 // SPDX-License-Identifier: GPL-2.0-only
3 * LEDs triggers for power supply class
5 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
6 * Copyright © 2004 Szabolcs Gyurko
7 * Copyright © 2003 Ian Molton <spyro@f2s.com>
9 * Modified: 2004, Oct Szabolcs Gyurko
12 #include <linux/kernel.h>
13 #include <linux/device.h>
14 #include <linux/power_supply.h>
15 #include <linux/slab.h>
16 #include <linux/leds.h>
18 #include "power_supply.h"
20 /* Battery specific LEDs triggers. */
22 struct power_supply_led_trigger
{
23 struct led_trigger trig
;
24 struct power_supply
*psy
;
27 #define trigger_to_psy_trigger(trigger) \
28 container_of(trigger, struct power_supply_led_trigger, trig)
30 static int power_supply_led_trigger_activate(struct led_classdev
*led_cdev
)
32 struct power_supply_led_trigger
*psy_trig
=
33 trigger_to_psy_trigger(led_cdev
->trigger
);
35 /* Sync current power-supply state to LED being activated */
36 power_supply_update_leds(psy_trig
->psy
);
40 static int power_supply_register_led_trigger(struct power_supply
*psy
,
41 const char *name_template
,
42 struct led_trigger
**tp
, int *err
)
44 struct power_supply_led_trigger
*psy_trig
;
47 /* Bail on previous errors */
51 psy_trig
= kzalloc(sizeof(*psy_trig
), GFP_KERNEL
);
53 goto err_free_trigger
;
55 psy_trig
->trig
.name
= kasprintf(GFP_KERNEL
, name_template
, psy
->desc
->name
);
56 if (!psy_trig
->trig
.name
)
57 goto err_free_trigger
;
59 psy_trig
->trig
.activate
= power_supply_led_trigger_activate
;
62 ret
= led_trigger_register(&psy_trig
->trig
);
66 *tp
= &psy_trig
->trig
;
70 kfree(psy_trig
->trig
.name
);
79 static void power_supply_unregister_led_trigger(struct led_trigger
*trig
)
81 struct power_supply_led_trigger
*psy_trig
;
86 psy_trig
= trigger_to_psy_trigger(trig
);
87 led_trigger_unregister(&psy_trig
->trig
);
88 kfree(psy_trig
->trig
.name
);
92 static void power_supply_update_bat_leds(struct power_supply
*psy
)
94 union power_supply_propval status
;
95 unsigned int intensity_green
[3] = { 0, 255, 0 };
96 unsigned int intensity_orange
[3] = { 255, 128, 0 };
98 if (power_supply_get_property(psy
, POWER_SUPPLY_PROP_STATUS
, &status
))
101 dev_dbg(&psy
->dev
, "%s %d\n", __func__
, status
.intval
);
103 switch (status
.intval
) {
104 case POWER_SUPPLY_STATUS_FULL
:
105 led_trigger_event(psy
->trig
, LED_FULL
);
106 led_trigger_event(psy
->charging_trig
, LED_OFF
);
107 led_trigger_event(psy
->full_trig
, LED_FULL
);
108 /* Going from blink to LED on requires a LED_OFF event to stop blink */
109 led_trigger_event(psy
->charging_blink_full_solid_trig
, LED_OFF
);
110 led_trigger_event(psy
->charging_blink_full_solid_trig
, LED_FULL
);
111 led_mc_trigger_event(psy
->charging_orange_full_green_trig
,
113 ARRAY_SIZE(intensity_green
),
116 case POWER_SUPPLY_STATUS_CHARGING
:
117 led_trigger_event(psy
->trig
, LED_FULL
);
118 led_trigger_event(psy
->charging_trig
, LED_FULL
);
119 led_trigger_event(psy
->full_trig
, LED_OFF
);
120 led_trigger_blink(psy
->charging_blink_full_solid_trig
, 0, 0);
121 led_mc_trigger_event(psy
->charging_orange_full_green_trig
,
123 ARRAY_SIZE(intensity_orange
),
127 led_trigger_event(psy
->trig
, LED_OFF
);
128 led_trigger_event(psy
->charging_trig
, LED_OFF
);
129 led_trigger_event(psy
->full_trig
, LED_OFF
);
130 led_trigger_event(psy
->charging_blink_full_solid_trig
,
132 led_trigger_event(psy
->charging_orange_full_green_trig
,
138 static void power_supply_remove_bat_triggers(struct power_supply
*psy
)
140 power_supply_unregister_led_trigger(psy
->trig
);
141 power_supply_unregister_led_trigger(psy
->charging_trig
);
142 power_supply_unregister_led_trigger(psy
->full_trig
);
143 power_supply_unregister_led_trigger(psy
->charging_blink_full_solid_trig
);
144 power_supply_unregister_led_trigger(psy
->charging_orange_full_green_trig
);
147 static int power_supply_create_bat_triggers(struct power_supply
*psy
)
151 power_supply_register_led_trigger(psy
, "%s-charging-or-full",
153 power_supply_register_led_trigger(psy
, "%s-charging",
154 &psy
->charging_trig
, &err
);
155 power_supply_register_led_trigger(psy
, "%s-full",
156 &psy
->full_trig
, &err
);
157 power_supply_register_led_trigger(psy
, "%s-charging-blink-full-solid",
158 &psy
->charging_blink_full_solid_trig
, &err
);
159 power_supply_register_led_trigger(psy
, "%s-charging-orange-full-green",
160 &psy
->charging_orange_full_green_trig
, &err
);
162 power_supply_remove_bat_triggers(psy
);
167 /* Generated power specific LEDs triggers. */
169 static void power_supply_update_gen_leds(struct power_supply
*psy
)
171 union power_supply_propval online
;
173 if (power_supply_get_property(psy
, POWER_SUPPLY_PROP_ONLINE
, &online
))
176 dev_dbg(&psy
->dev
, "%s %d\n", __func__
, online
.intval
);
179 led_trigger_event(psy
->trig
, LED_FULL
);
181 led_trigger_event(psy
->trig
, LED_OFF
);
184 static int power_supply_create_gen_triggers(struct power_supply
*psy
)
186 return power_supply_register_led_trigger(psy
, "%s-online", &psy
->trig
, NULL
);
189 static void power_supply_remove_gen_triggers(struct power_supply
*psy
)
191 power_supply_unregister_led_trigger(psy
->trig
);
194 /* Choice what triggers to create&update. */
196 void power_supply_update_leds(struct power_supply
*psy
)
198 if (psy
->desc
->type
== POWER_SUPPLY_TYPE_BATTERY
)
199 power_supply_update_bat_leds(psy
);
201 power_supply_update_gen_leds(psy
);
204 int power_supply_create_triggers(struct power_supply
*psy
)
206 if (psy
->desc
->type
== POWER_SUPPLY_TYPE_BATTERY
)
207 return power_supply_create_bat_triggers(psy
);
208 return power_supply_create_gen_triggers(psy
);
211 void power_supply_remove_triggers(struct power_supply
*psy
)
213 if (psy
->desc
->type
== POWER_SUPPLY_TYPE_BATTERY
)
214 power_supply_remove_bat_triggers(psy
);
216 power_supply_remove_gen_triggers(psy
);