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