Blame view

drivers/power/power_supply_core.c 5.9 KB
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   *  Universal power supply monitor class
   *
   *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
   *  Copyright © 2004  Szabolcs Gyurko
   *  Copyright © 2003  Ian Molton <spyro@f2s.com>
   *
   *  Modified: 2004, Oct     Szabolcs Gyurko
   *
   *  You may use this code as per GPL version 2
   */
  
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/init.h>
5f487cd34   Anton Vorontsov   power_supply: Use...
16
  #include <linux/slab.h>
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
17
18
19
20
  #include <linux/device.h>
  #include <linux/err.h>
  #include <linux/power_supply.h>
  #include "power_supply.h"
ff3417e7e   Daniel Mack   power_supply: EXP...
21
  /* exported for the APM Power driver, APM emulation */
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
22
  struct class *power_supply_class;
ff3417e7e   Daniel Mack   power_supply: EXP...
23
  EXPORT_SYMBOL_GPL(power_supply_class);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
24

5f487cd34   Anton Vorontsov   power_supply: Use...
25
  static struct device_type power_supply_dev_type;
443cad920   Dave Young   power supply : us...
26
27
28
29
30
31
32
33
34
35
36
37
38
  static int __power_supply_changed_work(struct device *dev, void *data)
  {
  	struct power_supply *psy = (struct power_supply *)data;
  	struct power_supply *pst = dev_get_drvdata(dev);
  	int i;
  
  	for (i = 0; i < psy->num_supplicants; i++)
  		if (!strcmp(psy->supplied_to[i], pst->name)) {
  			if (pst->external_power_changed)
  				pst->external_power_changed(pst);
  		}
  	return 0;
  }
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
39
40
41
42
  static void power_supply_changed_work(struct work_struct *work)
  {
  	struct power_supply *psy = container_of(work, struct power_supply,
  						changed_work);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
43

0cddc0a90   Harvey Harrison   power: replace re...
44
45
  	dev_dbg(psy->dev, "%s
  ", __func__);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
46

93562b537   Greg Kroah-Hartman   Driver Core: add ...
47
  	class_for_each_device(power_supply_class, NULL, psy,
443cad920   Dave Young   power supply : us...
48
  			      __power_supply_changed_work);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
49
50
51
52
  
  	power_supply_update_leds(psy);
  
  	kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
53
54
55
56
  }
  
  void power_supply_changed(struct power_supply *psy)
  {
0cddc0a90   Harvey Harrison   power: replace re...
57
58
  	dev_dbg(psy->dev, "%s
  ", __func__);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
59
60
  
  	schedule_work(&psy->changed_work);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
61
  }
ff3417e7e   Daniel Mack   power_supply: EXP...
62
  EXPORT_SYMBOL_GPL(power_supply_changed);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
63

443cad920   Dave Young   power supply : us...
64
  static int __power_supply_am_i_supplied(struct device *dev, void *data)
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
65
66
  {
  	union power_supply_propval ret = {0,};
443cad920   Dave Young   power supply : us...
67
68
69
70
71
72
73
74
75
76
77
  	struct power_supply *psy = (struct power_supply *)data;
  	struct power_supply *epsy = dev_get_drvdata(dev);
  	int i;
  
  	for (i = 0; i < epsy->num_supplicants; i++) {
  		if (!strcmp(epsy->supplied_to[i], psy->name)) {
  			if (epsy->get_property(epsy,
  				  POWER_SUPPLY_PROP_ONLINE, &ret))
  				continue;
  			if (ret.intval)
  				return ret.intval;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
78
79
  		}
  	}
443cad920   Dave Young   power supply : us...
80
81
82
83
84
85
  	return 0;
  }
  
  int power_supply_am_i_supplied(struct power_supply *psy)
  {
  	int error;
93562b537   Greg Kroah-Hartman   Driver Core: add ...
86
  	error = class_for_each_device(power_supply_class, NULL, psy,
443cad920   Dave Young   power supply : us...
87
  				      __power_supply_am_i_supplied);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
88

0cddc0a90   Harvey Harrison   power: replace re...
89
90
  	dev_dbg(psy->dev, "%s %d
  ", __func__, error);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
91

443cad920   Dave Young   power supply : us...
92
  	return error;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
93
  }
ff3417e7e   Daniel Mack   power_supply: EXP...
94
  EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
95

942ed1619   Matthew Garrett   power_supply: Add...
96
97
98
99
  static int __power_supply_is_system_supplied(struct device *dev, void *data)
  {
  	union power_supply_propval ret = {0,};
  	struct power_supply *psy = dev_get_drvdata(dev);
2530daa18   Jean Delvare   power_supply: Ass...
100
  	unsigned int *count = data;
942ed1619   Matthew Garrett   power_supply: Add...
101

2530daa18   Jean Delvare   power_supply: Ass...
102
  	(*count)++;
942ed1619   Matthew Garrett   power_supply: Add...
103
104
105
106
107
108
109
110
111
112
113
114
  	if (psy->type != POWER_SUPPLY_TYPE_BATTERY) {
  		if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
  			return 0;
  		if (ret.intval)
  			return ret.intval;
  	}
  	return 0;
  }
  
  int power_supply_is_system_supplied(void)
  {
  	int error;
2530daa18   Jean Delvare   power_supply: Ass...
115
  	unsigned int count = 0;
942ed1619   Matthew Garrett   power_supply: Add...
116

2530daa18   Jean Delvare   power_supply: Ass...
117
  	error = class_for_each_device(power_supply_class, NULL, &count,
942ed1619   Matthew Garrett   power_supply: Add...
118
  				      __power_supply_is_system_supplied);
2530daa18   Jean Delvare   power_supply: Ass...
119
120
121
122
123
124
  	/*
  	 * If no power class device was found at all, most probably we are
  	 * running on a desktop system, so assume we are on mains power.
  	 */
  	if (count == 0)
  		return 1;
942ed1619   Matthew Garrett   power_supply: Add...
125
126
  	return error;
  }
ff3417e7e   Daniel Mack   power_supply: EXP...
127
  EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
942ed1619   Matthew Garrett   power_supply: Add...
128

e5f5ccb64   Daniel Mack   power_supply: get...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  int power_supply_set_battery_charged(struct power_supply *psy)
  {
  	if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) {
  		psy->set_charged(psy);
  		return 0;
  	}
  
  	return -EINVAL;
  }
  EXPORT_SYMBOL_GPL(power_supply_set_battery_charged);
  
  static int power_supply_match_device_by_name(struct device *dev, void *data)
  {
  	const char *name = data;
  	struct power_supply *psy = dev_get_drvdata(dev);
  
  	return strcmp(psy->name, name) == 0;
  }
  
  struct power_supply *power_supply_get_by_name(char *name)
  {
  	struct device *dev = class_find_device(power_supply_class, NULL, name,
  					power_supply_match_device_by_name);
  
  	return dev ? dev_get_drvdata(dev) : NULL;
  }
  EXPORT_SYMBOL_GPL(power_supply_get_by_name);
835166519   Jeremy Fitzhardinge   power_supply: all...
156
157
  int power_supply_powers(struct power_supply *psy, struct device *dev)
  {
93278d151   Anton Vorontsov   power_supply: Dro...
158
  	return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers");
835166519   Jeremy Fitzhardinge   power_supply: all...
159
160
  }
  EXPORT_SYMBOL_GPL(power_supply_powers);
5f487cd34   Anton Vorontsov   power_supply: Use...
161
162
163
164
165
166
  static void power_supply_dev_release(struct device *dev)
  {
  	pr_debug("device: '%s': %s
  ", dev_name(dev), __func__);
  	kfree(dev);
  }
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
167
168
  int power_supply_register(struct device *parent, struct power_supply *psy)
  {
5f487cd34   Anton Vorontsov   power_supply: Use...
169
170
  	struct device *dev;
  	int rc;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
171

5f487cd34   Anton Vorontsov   power_supply: Use...
172
173
174
  	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  	if (!dev)
  		return -ENOMEM;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
175

5f487cd34   Anton Vorontsov   power_supply: Use...
176
  	device_initialize(dev);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
177

5f487cd34   Anton Vorontsov   power_supply: Use...
178
179
180
181
182
183
  	dev->class = power_supply_class;
  	dev->type = &power_supply_dev_type;
  	dev->parent = parent;
  	dev->release = power_supply_dev_release;
  	dev_set_drvdata(dev, psy);
  	psy->dev = dev;
977746725   Lars-Peter Clausen   power_supply: Ini...
184
  	INIT_WORK(&psy->changed_work, power_supply_changed_work);
5f487cd34   Anton Vorontsov   power_supply: Use...
185
186
187
188
189
  	rc = kobject_set_name(&dev->kobj, "%s", psy->name);
  	if (rc)
  		goto kobject_set_name_failed;
  
  	rc = device_add(dev);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
190
  	if (rc)
5f487cd34   Anton Vorontsov   power_supply: Use...
191
  		goto device_add_failed;
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
192
193
194
195
196
197
198
199
200
  	rc = power_supply_create_triggers(psy);
  	if (rc)
  		goto create_triggers_failed;
  
  	power_supply_changed(psy);
  
  	goto success;
  
  create_triggers_failed:
3a2dbd611   Vasiliy Kulikov   power_supply: Fix...
201
  	device_del(dev);
5f487cd34   Anton Vorontsov   power_supply: Use...
202
203
  kobject_set_name_failed:
  device_add_failed:
3a2dbd611   Vasiliy Kulikov   power_supply: Fix...
204
  	put_device(dev);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
205
206
207
  success:
  	return rc;
  }
ff3417e7e   Daniel Mack   power_supply: EXP...
208
  EXPORT_SYMBOL_GPL(power_supply_register);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
209
210
211
  
  void power_supply_unregister(struct power_supply *psy)
  {
bc51e7ff5   Tejun Heo   power_supply: Don...
212
  	cancel_work_sync(&psy->changed_work);
835166519   Jeremy Fitzhardinge   power_supply: all...
213
  	sysfs_remove_link(&psy->dev->kobj, "powers");
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
214
  	power_supply_remove_triggers(psy);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
215
  	device_unregister(psy->dev);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
216
  }
ff3417e7e   Daniel Mack   power_supply: EXP...
217
  EXPORT_SYMBOL_GPL(power_supply_unregister);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
218
219
220
221
222
223
224
225
226
  
  static int __init power_supply_class_init(void)
  {
  	power_supply_class = class_create(THIS_MODULE, "power_supply");
  
  	if (IS_ERR(power_supply_class))
  		return PTR_ERR(power_supply_class);
  
  	power_supply_class->dev_uevent = power_supply_uevent;
5f487cd34   Anton Vorontsov   power_supply: Use...
227
  	power_supply_init_attrs(&power_supply_dev_type);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
228
229
230
231
232
233
234
  
  	return 0;
  }
  
  static void __exit power_supply_class_exit(void)
  {
  	class_destroy(power_supply_class);
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
235
  }
4a11b59d8   Anton Vorontsov   [BATTERY] Univers...
236
237
238
239
240
241
242
243
  subsys_initcall(power_supply_class_init);
  module_exit(power_supply_class_exit);
  
  MODULE_DESCRIPTION("Universal power supply monitor class");
  MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
  	      "Szabolcs Gyurko, "
  	      "Anton Vorontsov <cbou@mail.ru>");
  MODULE_LICENSE("GPL");