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 led_trigger_event(psy->charging_blink_full_solid_trig, 39 LED_FULL); 40 break; 41 case POWER_SUPPLY_STATUS_CHARGING: 42 led_trigger_event(psy->charging_full_trig, LED_FULL); 43 led_trigger_event(psy->charging_trig, LED_FULL); 44 led_trigger_event(psy->full_trig, LED_OFF); 45 led_trigger_blink(psy->charging_blink_full_solid_trig, 46 &delay_on, &delay_off); 47 break; 48 default: 49 led_trigger_event(psy->charging_full_trig, LED_OFF); 50 led_trigger_event(psy->charging_trig, LED_OFF); 51 led_trigger_event(psy->full_trig, LED_OFF); 52 led_trigger_event(psy->charging_blink_full_solid_trig, 53 LED_OFF); 54 break; 55 } 56 } 57 58 static int power_supply_create_bat_triggers(struct power_supply *psy) 59 { 60 psy->charging_full_trig_name = kasprintf(GFP_KERNEL, 61 "%s-charging-or-full", psy->desc->name); 62 if (!psy->charging_full_trig_name) 63 goto charging_full_failed; 64 65 psy->charging_trig_name = kasprintf(GFP_KERNEL, 66 "%s-charging", psy->desc->name); 67 if (!psy->charging_trig_name) 68 goto charging_failed; 69 70 psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->desc->name); 71 if (!psy->full_trig_name) 72 goto full_failed; 73 74 psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL, 75 "%s-charging-blink-full-solid", psy->desc->name); 76 if (!psy->charging_blink_full_solid_trig_name) 77 goto charging_blink_full_solid_failed; 78 79 led_trigger_register_simple(psy->charging_full_trig_name, 80 &psy->charging_full_trig); 81 led_trigger_register_simple(psy->charging_trig_name, 82 &psy->charging_trig); 83 led_trigger_register_simple(psy->full_trig_name, 84 &psy->full_trig); 85 led_trigger_register_simple(psy->charging_blink_full_solid_trig_name, 86 &psy->charging_blink_full_solid_trig); 87 88 return 0; 89 90 charging_blink_full_solid_failed: 91 kfree(psy->full_trig_name); 92 full_failed: 93 kfree(psy->charging_trig_name); 94 charging_failed: 95 kfree(psy->charging_full_trig_name); 96 charging_full_failed: 97 return -ENOMEM; 98 } 99 100 static void power_supply_remove_bat_triggers(struct power_supply *psy) 101 { 102 led_trigger_unregister_simple(psy->charging_full_trig); 103 led_trigger_unregister_simple(psy->charging_trig); 104 led_trigger_unregister_simple(psy->full_trig); 105 led_trigger_unregister_simple(psy->charging_blink_full_solid_trig); 106 kfree(psy->charging_blink_full_solid_trig_name); 107 kfree(psy->full_trig_name); 108 kfree(psy->charging_trig_name); 109 kfree(psy->charging_full_trig_name); 110 } 111 112 /* Generated power specific LEDs triggers. */ 113 114 static void power_supply_update_gen_leds(struct power_supply *psy) 115 { 116 union power_supply_propval online; 117 118 if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) 119 return; 120 121 dev_dbg(&psy->dev, "%s %d\n", __func__, online.intval); 122 123 if (online.intval) 124 led_trigger_event(psy->online_trig, LED_FULL); 125 else 126 led_trigger_event(psy->online_trig, LED_OFF); 127 } 128 129 static int power_supply_create_gen_triggers(struct power_supply *psy) 130 { 131 psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online", 132 psy->desc->name); 133 if (!psy->online_trig_name) 134 return -ENOMEM; 135 136 led_trigger_register_simple(psy->online_trig_name, &psy->online_trig); 137 138 return 0; 139 } 140 141 static void power_supply_remove_gen_triggers(struct power_supply *psy) 142 { 143 led_trigger_unregister_simple(psy->online_trig); 144 kfree(psy->online_trig_name); 145 } 146 147 /* Choice what triggers to create&update. */ 148 149 void power_supply_update_leds(struct power_supply *psy) 150 { 151 if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY) 152 power_supply_update_bat_leds(psy); 153 else 154 power_supply_update_gen_leds(psy); 155 } 156 157 int power_supply_create_triggers(struct power_supply *psy) 158 { 159 if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY) 160 return power_supply_create_bat_triggers(psy); 161 return power_supply_create_gen_triggers(psy); 162 } 163 164 void power_supply_remove_triggers(struct power_supply *psy) 165 { 166 if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY) 167 power_supply_remove_bat_triggers(psy); 168 else 169 power_supply_remove_gen_triggers(psy); 170 } 171