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