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