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