GNU Linux-libre 4.19.295-gnu1
[releases.git] / drivers / power / supply / power_supply_leds.c
1 /*
2  *  LEDs triggers for power supply class
3  *
4  *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
5  *  Copyright © 2004  Szabolcs Gyurko
6  *  Copyright © 2003  Ian Molton <spyro@f2s.com>
7  *
8  *  Modified: 2004, Oct     Szabolcs Gyurko
9  *
10  *  You may use this code as per GPL version 2
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/device.h>
15 #include <linux/power_supply.h>
16 #include <linux/slab.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 }