1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * LEDs triggers for power supply class 4 * 5 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> 6 * Copyright © 2004 Szabolcs Gyurko 7 * Copyright © 2003 Ian Molton <spyro@f2s.com> 8 * 9 * Modified: 2004, Oct Szabolcs Gyurko 10 */ 11 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> 17 18 #include "power_supply.h" 19 20 /* Battery specific LEDs triggers. */ 21 22 static void power_supply_update_bat_leds(struct power_supply *psy) 23 { 24 union power_supply_propval status; 25 unsigned long delay_on = 0; 26 unsigned long delay_off = 0; 27 28 if (power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) 29 return; 30 31 dev_dbg(&psy->dev, "%s %d\n", __func__, status.intval); 32 33 switch (status.intval) { 34 case POWER_SUPPLY_STATUS_FULL: 35 led_trigger_event(psy->charging_full_trig, LED_FULL); 36 led_trigger_event(psy->charging_trig, LED_OFF); 37 led_trigger_event(psy->full_trig, LED_FULL); 38 /* Going from blink to LED on requires a LED_OFF event to stop blink */ 39 led_trigger_event(psy->charging_blink_full_solid_trig, LED_OFF); 40 led_trigger_event(psy->charging_blink_full_solid_trig, LED_FULL); 41 break; 42 case POWER_SUPPLY_STATUS_CHARGING: 43 led_trigger_event(psy->charging_full_trig, LED_FULL); 44 led_trigger_event(psy->charging_trig, LED_FULL); 45 led_trigger_event(psy->full_trig, LED_OFF); 46 led_trigger_blink(psy->charging_blink_full_solid_trig, 47 &delay_on, &delay_off); 48 break; 49 default: 50 led_trigger_event(psy->charging_full_trig, LED_OFF); 51 led_trigger_event(psy->charging_trig, LED_OFF); 52 led_trigger_event(psy->full_trig, LED_OFF); 53 led_trigger_event(psy->charging_blink_full_solid_trig, 54 LED_OFF); 55 break; 56 } 57 } 58 59 static int power_supply_create_bat_triggers(struct power_supply *psy) 60 { 61 psy->charging_full_trig_name = kasprintf(GFP_KERNEL, 62 "%s-charging-or-full", psy->desc->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->desc->name); 68 if (!psy->charging_trig_name) 69 goto charging_failed; 70 71 psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->desc->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->desc->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 return 0; 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 return -ENOMEM; 99 } 100 101 static void power_supply_remove_bat_triggers(struct power_supply *psy) 102 { 103 led_trigger_unregister_simple(psy->charging_full_trig); 104 led_trigger_unregister_simple(psy->charging_trig); 105 led_trigger_unregister_simple(psy->full_trig); 106 led_trigger_unregister_simple(psy->charging_blink_full_solid_trig); 107 kfree(psy->charging_blink_full_solid_trig_name); 108 kfree(psy->full_trig_name); 109 kfree(psy->charging_trig_name); 110 kfree(psy->charging_full_trig_name); 111 } 112 113 /* Generated power specific LEDs triggers. */ 114 115 static void power_supply_update_gen_leds(struct power_supply *psy) 116 { 117 union power_supply_propval online; 118 119 if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) 120 return; 121 122 dev_dbg(&psy->dev, "%s %d\n", __func__, online.intval); 123 124 if (online.intval) 125 led_trigger_event(psy->online_trig, LED_FULL); 126 else 127 led_trigger_event(psy->online_trig, LED_OFF); 128 } 129 130 static int power_supply_create_gen_triggers(struct power_supply *psy) 131 { 132 psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online", 133 psy->desc->name); 134 if (!psy->online_trig_name) 135 return -ENOMEM; 136 137 led_trigger_register_simple(psy->online_trig_name, &psy->online_trig); 138 139 return 0; 140 } 141 142 static void power_supply_remove_gen_triggers(struct power_supply *psy) 143 { 144 led_trigger_unregister_simple(psy->online_trig); 145 kfree(psy->online_trig_name); 146 } 147 148 /* Choice what triggers to create&update. */ 149 150 void power_supply_update_leds(struct power_supply *psy) 151 { 152 if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY) 153 power_supply_update_bat_leds(psy); 154 else 155 power_supply_update_gen_leds(psy); 156 } 157 158 int power_supply_create_triggers(struct power_supply *psy) 159 { 160 if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY) 161 return power_supply_create_bat_triggers(psy); 162 return power_supply_create_gen_triggers(psy); 163 } 164 165 void power_supply_remove_triggers(struct power_supply *psy) 166 { 167 if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY) 168 power_supply_remove_bat_triggers(psy); 169 else 170 power_supply_remove_gen_triggers(psy); 171 } 172