1a63a5fa9SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28c0984e5SSebastian Reichel /*
38c0984e5SSebastian Reichel  *  LEDs triggers for power supply class
48c0984e5SSebastian Reichel  *
58c0984e5SSebastian Reichel  *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
68c0984e5SSebastian Reichel  *  Copyright © 2004  Szabolcs Gyurko
78c0984e5SSebastian Reichel  *  Copyright © 2003  Ian Molton <spyro@f2s.com>
88c0984e5SSebastian Reichel  *
98c0984e5SSebastian Reichel  *  Modified: 2004, Oct     Szabolcs Gyurko
108c0984e5SSebastian Reichel  */
118c0984e5SSebastian Reichel 
128c0984e5SSebastian Reichel #include <linux/kernel.h>
138c0984e5SSebastian Reichel #include <linux/device.h>
148c0984e5SSebastian Reichel #include <linux/power_supply.h>
158c0984e5SSebastian Reichel #include <linux/slab.h>
169de10a51SThomas Weißschuh #include <linux/leds.h>
178c0984e5SSebastian Reichel 
188c0984e5SSebastian Reichel #include "power_supply.h"
198c0984e5SSebastian Reichel 
208c0984e5SSebastian Reichel /* Battery specific LEDs triggers. */
218c0984e5SSebastian Reichel 
power_supply_update_bat_leds(struct power_supply * psy)228c0984e5SSebastian Reichel static void power_supply_update_bat_leds(struct power_supply *psy)
238c0984e5SSebastian Reichel {
248c0984e5SSebastian Reichel 	union power_supply_propval status;
258c0984e5SSebastian Reichel 
268c0984e5SSebastian Reichel 	if (power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
278c0984e5SSebastian Reichel 		return;
288c0984e5SSebastian Reichel 
298c0984e5SSebastian Reichel 	dev_dbg(&psy->dev, "%s %d\n", __func__, status.intval);
308c0984e5SSebastian Reichel 
318c0984e5SSebastian Reichel 	switch (status.intval) {
328c0984e5SSebastian Reichel 	case POWER_SUPPLY_STATUS_FULL:
338c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_full_trig, LED_FULL);
348c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_trig, LED_OFF);
358c0984e5SSebastian Reichel 		led_trigger_event(psy->full_trig, LED_FULL);
368c0984e5SSebastian Reichel 		/* Going from blink to LED on requires a LED_OFF event to stop blink */
378c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_blink_full_solid_trig, LED_OFF);
388c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_blink_full_solid_trig, LED_FULL);
398c0984e5SSebastian Reichel 		break;
408c0984e5SSebastian Reichel 	case POWER_SUPPLY_STATUS_CHARGING:
418c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_full_trig, LED_FULL);
428c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_trig, LED_FULL);
43*e298d8a3SHans de Goede 		led_trigger_event(psy->full_trig, LED_OFF);
448c0984e5SSebastian Reichel 		led_trigger_blink(psy->charging_blink_full_solid_trig, 0, 0);
458c0984e5SSebastian Reichel 		break;
468c0984e5SSebastian Reichel 	default:
478c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_full_trig, LED_OFF);
488c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_trig, LED_OFF);
498c0984e5SSebastian Reichel 		led_trigger_event(psy->full_trig, LED_OFF);
508c0984e5SSebastian Reichel 		led_trigger_event(psy->charging_blink_full_solid_trig,
518c0984e5SSebastian Reichel 			LED_OFF);
528c0984e5SSebastian Reichel 		break;
538c0984e5SSebastian Reichel 	}
548c0984e5SSebastian Reichel }
558c0984e5SSebastian Reichel 
power_supply_create_bat_triggers(struct power_supply * psy)568c0984e5SSebastian Reichel static int power_supply_create_bat_triggers(struct power_supply *psy)
578c0984e5SSebastian Reichel {
588c0984e5SSebastian Reichel 	psy->charging_full_trig_name = kasprintf(GFP_KERNEL,
598c0984e5SSebastian Reichel 					"%s-charging-or-full", psy->desc->name);
608c0984e5SSebastian Reichel 	if (!psy->charging_full_trig_name)
618c0984e5SSebastian Reichel 		goto charging_full_failed;
628c0984e5SSebastian Reichel 
638c0984e5SSebastian Reichel 	psy->charging_trig_name = kasprintf(GFP_KERNEL,
648c0984e5SSebastian Reichel 					"%s-charging", psy->desc->name);
658c0984e5SSebastian Reichel 	if (!psy->charging_trig_name)
668c0984e5SSebastian Reichel 		goto charging_failed;
678c0984e5SSebastian Reichel 
688c0984e5SSebastian Reichel 	psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->desc->name);
698c0984e5SSebastian Reichel 	if (!psy->full_trig_name)
708c0984e5SSebastian Reichel 		goto full_failed;
718c0984e5SSebastian Reichel 
728c0984e5SSebastian Reichel 	psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL,
738c0984e5SSebastian Reichel 		"%s-charging-blink-full-solid", psy->desc->name);
748c0984e5SSebastian Reichel 	if (!psy->charging_blink_full_solid_trig_name)
758c0984e5SSebastian Reichel 		goto charging_blink_full_solid_failed;
768c0984e5SSebastian Reichel 
778c0984e5SSebastian Reichel 	led_trigger_register_simple(psy->charging_full_trig_name,
788c0984e5SSebastian Reichel 				    &psy->charging_full_trig);
798c0984e5SSebastian Reichel 	led_trigger_register_simple(psy->charging_trig_name,
808c0984e5SSebastian Reichel 				    &psy->charging_trig);
818c0984e5SSebastian Reichel 	led_trigger_register_simple(psy->full_trig_name,
828c0984e5SSebastian Reichel 				    &psy->full_trig);
838c0984e5SSebastian Reichel 	led_trigger_register_simple(psy->charging_blink_full_solid_trig_name,
848c0984e5SSebastian Reichel 				    &psy->charging_blink_full_solid_trig);
858c0984e5SSebastian Reichel 
868c0984e5SSebastian Reichel 	return 0;
878c0984e5SSebastian Reichel 
888c0984e5SSebastian Reichel charging_blink_full_solid_failed:
898c0984e5SSebastian Reichel 	kfree(psy->full_trig_name);
908c0984e5SSebastian Reichel full_failed:
918c0984e5SSebastian Reichel 	kfree(psy->charging_trig_name);
928c0984e5SSebastian Reichel charging_failed:
938c0984e5SSebastian Reichel 	kfree(psy->charging_full_trig_name);
948c0984e5SSebastian Reichel charging_full_failed:
958c0984e5SSebastian Reichel 	return -ENOMEM;
968c0984e5SSebastian Reichel }
978c0984e5SSebastian Reichel 
power_supply_remove_bat_triggers(struct power_supply * psy)988c0984e5SSebastian Reichel static void power_supply_remove_bat_triggers(struct power_supply *psy)
998c0984e5SSebastian Reichel {
1008c0984e5SSebastian Reichel 	led_trigger_unregister_simple(psy->charging_full_trig);
1018c0984e5SSebastian Reichel 	led_trigger_unregister_simple(psy->charging_trig);
1028c0984e5SSebastian Reichel 	led_trigger_unregister_simple(psy->full_trig);
1038c0984e5SSebastian Reichel 	led_trigger_unregister_simple(psy->charging_blink_full_solid_trig);
1048c0984e5SSebastian Reichel 	kfree(psy->charging_blink_full_solid_trig_name);
1058c0984e5SSebastian Reichel 	kfree(psy->full_trig_name);
1068c0984e5SSebastian Reichel 	kfree(psy->charging_trig_name);
1078c0984e5SSebastian Reichel 	kfree(psy->charging_full_trig_name);
1088c0984e5SSebastian Reichel }
1098c0984e5SSebastian Reichel 
1108c0984e5SSebastian Reichel /* Generated power specific LEDs triggers. */
1118c0984e5SSebastian Reichel 
power_supply_update_gen_leds(struct power_supply * psy)1128c0984e5SSebastian Reichel static void power_supply_update_gen_leds(struct power_supply *psy)
1138c0984e5SSebastian Reichel {
1148c0984e5SSebastian Reichel 	union power_supply_propval online;
1158c0984e5SSebastian Reichel 
1168c0984e5SSebastian Reichel 	if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
1178c0984e5SSebastian Reichel 		return;
1188c0984e5SSebastian Reichel 
1198c0984e5SSebastian Reichel 	dev_dbg(&psy->dev, "%s %d\n", __func__, online.intval);
1208c0984e5SSebastian Reichel 
1218c0984e5SSebastian Reichel 	if (online.intval)
1228c0984e5SSebastian Reichel 		led_trigger_event(psy->online_trig, LED_FULL);
1238c0984e5SSebastian Reichel 	else
1248c0984e5SSebastian Reichel 		led_trigger_event(psy->online_trig, LED_OFF);
1258c0984e5SSebastian Reichel }
1268c0984e5SSebastian Reichel 
power_supply_create_gen_triggers(struct power_supply * psy)1278c0984e5SSebastian Reichel static int power_supply_create_gen_triggers(struct power_supply *psy)
1288c0984e5SSebastian Reichel {
1298c0984e5SSebastian Reichel 	psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online",
1308c0984e5SSebastian Reichel 					  psy->desc->name);
1318c0984e5SSebastian Reichel 	if (!psy->online_trig_name)
1328c0984e5SSebastian Reichel 		return -ENOMEM;
1338c0984e5SSebastian Reichel 
1348c0984e5SSebastian Reichel 	led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
1358c0984e5SSebastian Reichel 
1368c0984e5SSebastian Reichel 	return 0;
1378c0984e5SSebastian Reichel }
1388c0984e5SSebastian Reichel 
power_supply_remove_gen_triggers(struct power_supply * psy)1398c0984e5SSebastian Reichel static void power_supply_remove_gen_triggers(struct power_supply *psy)
1408c0984e5SSebastian Reichel {
1418c0984e5SSebastian Reichel 	led_trigger_unregister_simple(psy->online_trig);
1428c0984e5SSebastian Reichel 	kfree(psy->online_trig_name);
1438c0984e5SSebastian Reichel }
1448c0984e5SSebastian Reichel 
1458c0984e5SSebastian Reichel /* Choice what triggers to create&update. */
1468c0984e5SSebastian Reichel 
power_supply_update_leds(struct power_supply * psy)1478c0984e5SSebastian Reichel void power_supply_update_leds(struct power_supply *psy)
1488c0984e5SSebastian Reichel {
1498c0984e5SSebastian Reichel 	if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY)
1508c0984e5SSebastian Reichel 		power_supply_update_bat_leds(psy);
1518c0984e5SSebastian Reichel 	else
1528c0984e5SSebastian Reichel 		power_supply_update_gen_leds(psy);
1538c0984e5SSebastian Reichel }
1548c0984e5SSebastian Reichel 
power_supply_create_triggers(struct power_supply * psy)1558c0984e5SSebastian Reichel int power_supply_create_triggers(struct power_supply *psy)
1568c0984e5SSebastian Reichel {
1578c0984e5SSebastian Reichel 	if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY)
1588c0984e5SSebastian Reichel 		return power_supply_create_bat_triggers(psy);
1598c0984e5SSebastian Reichel 	return power_supply_create_gen_triggers(psy);
1608c0984e5SSebastian Reichel }
1618c0984e5SSebastian Reichel 
power_supply_remove_triggers(struct power_supply * psy)1628c0984e5SSebastian Reichel void power_supply_remove_triggers(struct power_supply *psy)
1638c0984e5SSebastian Reichel {
1648c0984e5SSebastian Reichel 	if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY)
1658c0984e5SSebastian Reichel 		power_supply_remove_bat_triggers(psy);
1668c0984e5SSebastian Reichel 	else
1678c0984e5SSebastian Reichel 		power_supply_remove_gen_triggers(psy);
168 }
169