2 * Universal power supply monitor class
4 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
5 * Copyright © 2004 Szabolcs Gyurko
6 * Copyright © 2003 Ian Molton <spyro@f2s.com>
8 * Modified: 2004, Oct Szabolcs Gyurko
10 * You may use this code as per GPL version 2
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/init.h>
16 #include <linux/slab.h>
17 #include <linux/device.h>
18 #include <linux/err.h>
19 #include <linux/power_supply.h>
20 #include <linux/thermal.h>
21 #include "power_supply.h"
23 /* exported for the APM Power driver, APM emulation */
24 struct class *power_supply_class
;
25 EXPORT_SYMBOL_GPL(power_supply_class
);
27 static struct device_type power_supply_dev_type
;
29 static int __power_supply_changed_work(struct device
*dev
, void *data
)
31 struct power_supply
*psy
= (struct power_supply
*)data
;
32 struct power_supply
*pst
= dev_get_drvdata(dev
);
35 for (i
= 0; i
< psy
->num_supplicants
; i
++)
36 if (!strcmp(psy
->supplied_to
[i
], pst
->name
)) {
37 if (pst
->external_power_changed
)
38 pst
->external_power_changed(pst
);
43 static void power_supply_changed_work(struct work_struct
*work
)
45 struct power_supply
*psy
= container_of(work
, struct power_supply
,
48 dev_dbg(psy
->dev
, "%s\n", __func__
);
50 class_for_each_device(power_supply_class
, NULL
, psy
,
51 __power_supply_changed_work
);
53 power_supply_update_leds(psy
);
55 kobject_uevent(&psy
->dev
->kobj
, KOBJ_CHANGE
);
58 void power_supply_changed(struct power_supply
*psy
)
60 dev_dbg(psy
->dev
, "%s\n", __func__
);
62 schedule_work(&psy
->changed_work
);
64 EXPORT_SYMBOL_GPL(power_supply_changed
);
66 static int __power_supply_am_i_supplied(struct device
*dev
, void *data
)
68 union power_supply_propval ret
= {0,};
69 struct power_supply
*psy
= (struct power_supply
*)data
;
70 struct power_supply
*epsy
= dev_get_drvdata(dev
);
73 for (i
= 0; i
< epsy
->num_supplicants
; i
++) {
74 if (!strcmp(epsy
->supplied_to
[i
], psy
->name
)) {
75 if (epsy
->get_property(epsy
,
76 POWER_SUPPLY_PROP_ONLINE
, &ret
))
85 int power_supply_am_i_supplied(struct power_supply
*psy
)
89 error
= class_for_each_device(power_supply_class
, NULL
, psy
,
90 __power_supply_am_i_supplied
);
92 dev_dbg(psy
->dev
, "%s %d\n", __func__
, error
);
96 EXPORT_SYMBOL_GPL(power_supply_am_i_supplied
);
98 static int __power_supply_is_system_supplied(struct device
*dev
, void *data
)
100 union power_supply_propval ret
= {0,};
101 struct power_supply
*psy
= dev_get_drvdata(dev
);
102 unsigned int *count
= data
;
105 if (psy
->type
!= POWER_SUPPLY_TYPE_BATTERY
) {
106 if (psy
->get_property(psy
, POWER_SUPPLY_PROP_ONLINE
, &ret
))
114 int power_supply_is_system_supplied(void)
117 unsigned int count
= 0;
119 error
= class_for_each_device(power_supply_class
, NULL
, &count
,
120 __power_supply_is_system_supplied
);
123 * If no power class device was found at all, most probably we are
124 * running on a desktop system, so assume we are on mains power.
131 EXPORT_SYMBOL_GPL(power_supply_is_system_supplied
);
133 int power_supply_set_battery_charged(struct power_supply
*psy
)
135 if (psy
->type
== POWER_SUPPLY_TYPE_BATTERY
&& psy
->set_charged
) {
136 psy
->set_charged(psy
);
142 EXPORT_SYMBOL_GPL(power_supply_set_battery_charged
);
144 static int power_supply_match_device_by_name(struct device
*dev
, void *data
)
146 const char *name
= data
;
147 struct power_supply
*psy
= dev_get_drvdata(dev
);
149 return strcmp(psy
->name
, name
) == 0;
152 struct power_supply
*power_supply_get_by_name(char *name
)
154 struct device
*dev
= class_find_device(power_supply_class
, NULL
, name
,
155 power_supply_match_device_by_name
);
157 return dev
? dev_get_drvdata(dev
) : NULL
;
159 EXPORT_SYMBOL_GPL(power_supply_get_by_name
);
161 int power_supply_powers(struct power_supply
*psy
, struct device
*dev
)
163 return sysfs_create_link(&psy
->dev
->kobj
, &dev
->kobj
, "powers");
165 EXPORT_SYMBOL_GPL(power_supply_powers
);
167 static void power_supply_dev_release(struct device
*dev
)
169 pr_debug("device: '%s': %s\n", dev_name(dev
), __func__
);
173 #ifdef CONFIG_THERMAL
174 static int power_supply_read_temp(struct thermal_zone_device
*tzd
,
177 struct power_supply
*psy
;
178 union power_supply_propval val
;
181 WARN_ON(tzd
== NULL
);
183 ret
= psy
->get_property(psy
, POWER_SUPPLY_PROP_TEMP
, &val
);
185 /* Convert tenths of degree Celsius to milli degree Celsius. */
187 *temp
= val
.intval
* 100;
192 static struct thermal_zone_device_ops psy_tzd_ops
= {
193 .get_temp
= power_supply_read_temp
,
196 static int psy_register_thermal(struct power_supply
*psy
)
200 /* Register battery zone device psy reports temperature */
201 for (i
= 0; i
< psy
->num_properties
; i
++) {
202 if (psy
->properties
[i
] == POWER_SUPPLY_PROP_TEMP
) {
203 psy
->tzd
= thermal_zone_device_register(psy
->name
, 0, 0,
204 psy
, &psy_tzd_ops
, 0, 0, 0, 0);
205 if (IS_ERR(psy
->tzd
))
206 return PTR_ERR(psy
->tzd
);
213 static void psy_unregister_thermal(struct power_supply
*psy
)
215 if (IS_ERR_OR_NULL(psy
->tzd
))
217 thermal_zone_device_unregister(psy
->tzd
);
220 static int psy_register_thermal(struct power_supply
*psy
)
225 static void psy_unregister_thermal(struct power_supply
*psy
)
230 int power_supply_register(struct device
*parent
, struct power_supply
*psy
)
235 dev
= kzalloc(sizeof(*dev
), GFP_KERNEL
);
239 device_initialize(dev
);
241 dev
->class = power_supply_class
;
242 dev
->type
= &power_supply_dev_type
;
243 dev
->parent
= parent
;
244 dev
->release
= power_supply_dev_release
;
245 dev_set_drvdata(dev
, psy
);
248 INIT_WORK(&psy
->changed_work
, power_supply_changed_work
);
250 rc
= kobject_set_name(&dev
->kobj
, "%s", psy
->name
);
252 goto kobject_set_name_failed
;
254 rc
= device_add(dev
);
256 goto device_add_failed
;
258 rc
= psy_register_thermal(psy
);
260 goto register_thermal_failed
;
262 rc
= power_supply_create_triggers(psy
);
264 goto create_triggers_failed
;
266 power_supply_changed(psy
);
270 create_triggers_failed
:
271 psy_unregister_thermal(psy
);
272 register_thermal_failed
:
274 kobject_set_name_failed
:
280 EXPORT_SYMBOL_GPL(power_supply_register
);
282 void power_supply_unregister(struct power_supply
*psy
)
284 cancel_work_sync(&psy
->changed_work
);
285 sysfs_remove_link(&psy
->dev
->kobj
, "powers");
286 power_supply_remove_triggers(psy
);
287 psy_unregister_thermal(psy
);
288 device_unregister(psy
->dev
);
290 EXPORT_SYMBOL_GPL(power_supply_unregister
);
292 static int __init
power_supply_class_init(void)
294 power_supply_class
= class_create(THIS_MODULE
, "power_supply");
296 if (IS_ERR(power_supply_class
))
297 return PTR_ERR(power_supply_class
);
299 power_supply_class
->dev_uevent
= power_supply_uevent
;
300 power_supply_init_attrs(&power_supply_dev_type
);
305 static void __exit
power_supply_class_exit(void)
307 class_destroy(power_supply_class
);
310 subsys_initcall(power_supply_class_init
);
311 module_exit(power_supply_class_exit
);
313 MODULE_DESCRIPTION("Universal power supply monitor class");
314 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
316 "Anton Vorontsov <cbou@mail.ru>");
317 MODULE_LICENSE("GPL");