Root/
1 | /* |
2 | * Universal power supply monitor 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/module.h> |
14 | #include <linux/types.h> |
15 | #include <linux/init.h> |
16 | #include <linux/device.h> |
17 | #include <linux/err.h> |
18 | #include <linux/power_supply.h> |
19 | #include "power_supply.h" |
20 | |
21 | /* exported for the APM Power driver, APM emulation */ |
22 | struct class *power_supply_class; |
23 | EXPORT_SYMBOL_GPL(power_supply_class); |
24 | |
25 | static int __power_supply_changed_work(struct device *dev, void *data) |
26 | { |
27 | struct power_supply *psy = (struct power_supply *)data; |
28 | struct power_supply *pst = dev_get_drvdata(dev); |
29 | int i; |
30 | |
31 | for (i = 0; i < psy->num_supplicants; i++) |
32 | if (!strcmp(psy->supplied_to[i], pst->name)) { |
33 | if (pst->external_power_changed) |
34 | pst->external_power_changed(pst); |
35 | } |
36 | return 0; |
37 | } |
38 | |
39 | static void power_supply_changed_work(struct work_struct *work) |
40 | { |
41 | struct power_supply *psy = container_of(work, struct power_supply, |
42 | changed_work); |
43 | |
44 | dev_dbg(psy->dev, "%s\n", __func__); |
45 | |
46 | class_for_each_device(power_supply_class, NULL, psy, |
47 | __power_supply_changed_work); |
48 | |
49 | power_supply_update_leds(psy); |
50 | |
51 | kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); |
52 | } |
53 | |
54 | void power_supply_changed(struct power_supply *psy) |
55 | { |
56 | dev_dbg(psy->dev, "%s\n", __func__); |
57 | |
58 | schedule_work(&psy->changed_work); |
59 | } |
60 | EXPORT_SYMBOL_GPL(power_supply_changed); |
61 | |
62 | static int __power_supply_am_i_supplied(struct device *dev, void *data) |
63 | { |
64 | union power_supply_propval ret = {0,}; |
65 | struct power_supply *psy = (struct power_supply *)data; |
66 | struct power_supply *epsy = dev_get_drvdata(dev); |
67 | int i; |
68 | |
69 | for (i = 0; i < epsy->num_supplicants; i++) { |
70 | if (!strcmp(epsy->supplied_to[i], psy->name)) { |
71 | if (epsy->get_property(epsy, |
72 | POWER_SUPPLY_PROP_ONLINE, &ret)) |
73 | continue; |
74 | if (ret.intval) |
75 | return ret.intval; |
76 | } |
77 | } |
78 | return 0; |
79 | } |
80 | |
81 | int power_supply_am_i_supplied(struct power_supply *psy) |
82 | { |
83 | int error; |
84 | |
85 | error = class_for_each_device(power_supply_class, NULL, psy, |
86 | __power_supply_am_i_supplied); |
87 | |
88 | dev_dbg(psy->dev, "%s %d\n", __func__, error); |
89 | |
90 | return error; |
91 | } |
92 | EXPORT_SYMBOL_GPL(power_supply_am_i_supplied); |
93 | |
94 | static int __power_supply_is_system_supplied(struct device *dev, void *data) |
95 | { |
96 | union power_supply_propval ret = {0,}; |
97 | struct power_supply *psy = dev_get_drvdata(dev); |
98 | |
99 | if (psy->type != POWER_SUPPLY_TYPE_BATTERY) { |
100 | if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret)) |
101 | return 0; |
102 | if (ret.intval) |
103 | return ret.intval; |
104 | } |
105 | return 0; |
106 | } |
107 | |
108 | int power_supply_is_system_supplied(void) |
109 | { |
110 | int error; |
111 | |
112 | error = class_for_each_device(power_supply_class, NULL, NULL, |
113 | __power_supply_is_system_supplied); |
114 | |
115 | return error; |
116 | } |
117 | EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); |
118 | |
119 | int power_supply_set_battery_charged(struct power_supply *psy) |
120 | { |
121 | if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) { |
122 | psy->set_charged(psy); |
123 | return 0; |
124 | } |
125 | |
126 | return -EINVAL; |
127 | } |
128 | EXPORT_SYMBOL_GPL(power_supply_set_battery_charged); |
129 | |
130 | static int power_supply_match_device_by_name(struct device *dev, void *data) |
131 | { |
132 | const char *name = data; |
133 | struct power_supply *psy = dev_get_drvdata(dev); |
134 | |
135 | return strcmp(psy->name, name) == 0; |
136 | } |
137 | |
138 | struct power_supply *power_supply_get_by_name(char *name) |
139 | { |
140 | struct device *dev = class_find_device(power_supply_class, NULL, name, |
141 | power_supply_match_device_by_name); |
142 | |
143 | return dev ? dev_get_drvdata(dev) : NULL; |
144 | } |
145 | EXPORT_SYMBOL_GPL(power_supply_get_by_name); |
146 | |
147 | int power_supply_register(struct device *parent, struct power_supply *psy) |
148 | { |
149 | int rc = 0; |
150 | |
151 | psy->dev = device_create(power_supply_class, parent, 0, psy, |
152 | "%s", psy->name); |
153 | if (IS_ERR(psy->dev)) { |
154 | rc = PTR_ERR(psy->dev); |
155 | goto dev_create_failed; |
156 | } |
157 | |
158 | INIT_WORK(&psy->changed_work, power_supply_changed_work); |
159 | |
160 | rc = power_supply_create_attrs(psy); |
161 | if (rc) |
162 | goto create_attrs_failed; |
163 | |
164 | rc = power_supply_create_triggers(psy); |
165 | if (rc) |
166 | goto create_triggers_failed; |
167 | |
168 | power_supply_changed(psy); |
169 | |
170 | goto success; |
171 | |
172 | create_triggers_failed: |
173 | power_supply_remove_attrs(psy); |
174 | create_attrs_failed: |
175 | device_unregister(psy->dev); |
176 | dev_create_failed: |
177 | success: |
178 | return rc; |
179 | } |
180 | EXPORT_SYMBOL_GPL(power_supply_register); |
181 | |
182 | void power_supply_unregister(struct power_supply *psy) |
183 | { |
184 | flush_scheduled_work(); |
185 | power_supply_remove_triggers(psy); |
186 | power_supply_remove_attrs(psy); |
187 | device_unregister(psy->dev); |
188 | } |
189 | EXPORT_SYMBOL_GPL(power_supply_unregister); |
190 | |
191 | static int __init power_supply_class_init(void) |
192 | { |
193 | power_supply_class = class_create(THIS_MODULE, "power_supply"); |
194 | |
195 | if (IS_ERR(power_supply_class)) |
196 | return PTR_ERR(power_supply_class); |
197 | |
198 | power_supply_class->dev_uevent = power_supply_uevent; |
199 | |
200 | return 0; |
201 | } |
202 | |
203 | static void __exit power_supply_class_exit(void) |
204 | { |
205 | class_destroy(power_supply_class); |
206 | } |
207 | |
208 | subsys_initcall(power_supply_class_init); |
209 | module_exit(power_supply_class_exit); |
210 | |
211 | MODULE_DESCRIPTION("Universal power supply monitor class"); |
212 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, " |
213 | "Szabolcs Gyurko, " |
214 | "Anton Vorontsov <cbou@mail.ru>"); |
215 | MODULE_LICENSE("GPL"); |
216 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9