aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-24 11:00:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-24 11:00:13 -0400
commit15953654cc312429740fd58fb37a5a3d63a54376 (patch)
treebbb6bf8d4ea943545e29ce896848182c4f206298 /drivers
parentc3ed9ea4ab460080dea9449c709be9316c670c72 (diff)
parent24af3202459d9a25643009b1ab8ab5ff04d94b49 (diff)
Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6: ds2760_battery: Document ABI change ds2760_battery: Make charge_now and charge_full writeable power_supply: Add support for writeable properties power_supply: Use attribute groups power_supply: Add test_power driver tosa_battery: Fix build error due to direct driver_data usage wm97xx_battery: Quieten sparse warning (bat_set_pdata not declared) ds2782_battery: Get rid of magic numbers in driver_data ds2782_battery: Add support for ds2786 battery gas gauge pda_power: Add function callbacks for suspend and resume wm831x_power: Use genirq Driver for Zipit Z2 battery chip ds2782_battery: Fix clientdata on removal
Diffstat (limited to 'drivers')
-rw-r--r--drivers/power/Kconfig15
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/ds2760_battery.c64
-rw-r--r--drivers/power/ds2782_battery.c194
-rw-r--r--drivers/power/pda_power.c10
-rw-r--r--drivers/power/power_supply.h7
-rw-r--r--drivers/power/power_supply_core.c48
-rw-r--r--drivers/power/power_supply_sysfs.c145
-rw-r--r--drivers/power/test_power.c163
-rw-r--r--drivers/power/tosa_battery.c4
-rw-r--r--drivers/power/wm831x_power.c33
-rw-r--r--drivers/power/wm97xx_battery.c3
-rw-r--r--drivers/power/z2_battery.c328
13 files changed, 848 insertions, 168 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index faaa9b4d0d07..8e9ba177d817 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -57,6 +57,11 @@ config WM8350_POWER
57 Say Y here to enable support for the power management unit 57 Say Y here to enable support for the power management unit
58 provided by the Wolfson Microelectronics WM8350 PMIC. 58 provided by the Wolfson Microelectronics WM8350 PMIC.
59 59
60config TEST_POWER
61 tristate "Test power driver"
62 help
63 This driver is used for testing. It's safe to say M here.
64
60config BATTERY_DS2760 65config BATTERY_DS2760
61 tristate "DS2760 battery driver (HP iPAQ & others)" 66 tristate "DS2760 battery driver (HP iPAQ & others)"
62 select W1 67 select W1
@@ -65,10 +70,10 @@ config BATTERY_DS2760
65 Say Y here to enable support for batteries with ds2760 chip. 70 Say Y here to enable support for batteries with ds2760 chip.
66 71
67config BATTERY_DS2782 72config BATTERY_DS2782
68 tristate "DS2782 standalone gas-gauge" 73 tristate "DS2782/DS2786 standalone gas-gauge"
69 depends on I2C 74 depends on I2C
70 help 75 help
71 Say Y here to enable support for the DS2782 standalone battery 76 Say Y here to enable support for the DS2782/DS2786 standalone battery
72 gas-gauge. 77 gas-gauge.
73 78
74config BATTERY_PMU 79config BATTERY_PMU
@@ -125,6 +130,12 @@ config BATTERY_MAX17040
125 in handheld and portable equipment. The MAX17040 is configured 130 in handheld and portable equipment. The MAX17040 is configured
126 to operate with a single lithium cell 131 to operate with a single lithium cell
127 132
133config BATTERY_Z2
134 tristate "Z2 battery driver"
135 depends on I2C && MACH_ZIPIT2
136 help
137 Say Y to include support for the battery on the Zipit Z2.
138
128config CHARGER_PCF50633 139config CHARGER_PCF50633
129 tristate "NXP PCF50633 MBC" 140 tristate "NXP PCF50633 MBC"
130 depends on MFD_PCF50633 141 depends on MFD_PCF50633
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index a2ba7c85c97a..00050809a6c7 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
20obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o 20obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
21obj-$(CONFIG_WM831X_POWER) += wm831x_power.o 21obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
22obj-$(CONFIG_WM8350_POWER) += wm8350_power.o 22obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
23obj-$(CONFIG_TEST_POWER) += test_power.o
23 24
24obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o 25obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
25obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o 26obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
@@ -31,4 +32,5 @@ obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
31obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o 32obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
32obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o 33obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
33obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o 34obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
35obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
34obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o 36obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index 3bf8d1f622e3..4d3b27228a2e 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -304,6 +304,28 @@ static void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di,
304 w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); 304 w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1);
305} 305}
306 306
307static void ds2760_battery_write_active_full(struct ds2760_device_info *di,
308 int active_full)
309{
310 unsigned char tmp[2] = {
311 active_full >> 8,
312 active_full & 0xff
313 };
314
315 if (tmp[0] == di->raw[DS2760_ACTIVE_FULL] &&
316 tmp[1] == di->raw[DS2760_ACTIVE_FULL + 1])
317 return;
318
319 w1_ds2760_write(di->w1_dev, tmp, DS2760_ACTIVE_FULL, sizeof(tmp));
320 w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK0);
321 w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK0);
322
323 /* Write to the di->raw[] buffer directly - the DS2760_ACTIVE_FULL
324 * values won't be read back by ds2760_battery_read_status() */
325 di->raw[DS2760_ACTIVE_FULL] = tmp[0];
326 di->raw[DS2760_ACTIVE_FULL + 1] = tmp[1];
327}
328
307static void ds2760_battery_work(struct work_struct *work) 329static void ds2760_battery_work(struct work_struct *work)
308{ 330{
309 struct ds2760_device_info *di = container_of(work, 331 struct ds2760_device_info *di = container_of(work,
@@ -426,6 +448,45 @@ static int ds2760_battery_get_property(struct power_supply *psy,
426 return 0; 448 return 0;
427} 449}
428 450
451static int ds2760_battery_set_property(struct power_supply *psy,
452 enum power_supply_property psp,
453 const union power_supply_propval *val)
454{
455 struct ds2760_device_info *di = to_ds2760_device_info(psy);
456
457 switch (psp) {
458 case POWER_SUPPLY_PROP_CHARGE_FULL:
459 /* the interface counts in uAh, convert the value */
460 ds2760_battery_write_active_full(di, val->intval / 1000L);
461 break;
462
463 case POWER_SUPPLY_PROP_CHARGE_NOW:
464 /* ds2760_battery_set_current_accum() does the conversion */
465 ds2760_battery_set_current_accum(di, val->intval);
466 break;
467
468 default:
469 return -EPERM;
470 }
471
472 return 0;
473}
474
475static int ds2760_battery_property_is_writeable(struct power_supply *psy,
476 enum power_supply_property psp)
477{
478 switch (psp) {
479 case POWER_SUPPLY_PROP_CHARGE_FULL:
480 case POWER_SUPPLY_PROP_CHARGE_NOW:
481 return 1;
482
483 default:
484 break;
485 }
486
487 return 0;
488}
489
429static enum power_supply_property ds2760_battery_props[] = { 490static enum power_supply_property ds2760_battery_props[] = {
430 POWER_SUPPLY_PROP_STATUS, 491 POWER_SUPPLY_PROP_STATUS,
431 POWER_SUPPLY_PROP_VOLTAGE_NOW, 492 POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -460,6 +521,9 @@ static int ds2760_battery_probe(struct platform_device *pdev)
460 di->bat.properties = ds2760_battery_props; 521 di->bat.properties = ds2760_battery_props;
461 di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props); 522 di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props);
462 di->bat.get_property = ds2760_battery_get_property; 523 di->bat.get_property = ds2760_battery_get_property;
524 di->bat.set_property = ds2760_battery_set_property;
525 di->bat.property_is_writeable =
526 ds2760_battery_property_is_writeable;
463 di->bat.set_charged = ds2760_battery_set_charged; 527 di->bat.set_charged = ds2760_battery_set_charged;
464 di->bat.external_power_changed = 528 di->bat.external_power_changed =
465 ds2760_battery_external_power_changed; 529 ds2760_battery_external_power_changed;
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
index 99c89976a902..d762a0cbc6af 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/ds2782_battery.c
@@ -5,6 +5,8 @@
5 * 5 *
6 * Author: Ryan Mallon <ryan@bluewatersys.com> 6 * Author: Ryan Mallon <ryan@bluewatersys.com>
7 * 7 *
8 * DS2786 added by Yulia Vilensky <vilensky@compulab.co.il>
9 *
8 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 11 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
@@ -20,12 +22,13 @@
20#include <linux/idr.h> 22#include <linux/idr.h>
21#include <linux/power_supply.h> 23#include <linux/power_supply.h>
22#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/ds2782_battery.h>
23 26
24#define DS2782_REG_RARC 0x06 /* Remaining active relative capacity */ 27#define DS2782_REG_RARC 0x06 /* Remaining active relative capacity */
25 28
26#define DS2782_REG_VOLT_MSB 0x0c 29#define DS278x_REG_VOLT_MSB 0x0c
27#define DS2782_REG_TEMP_MSB 0x0a 30#define DS278x_REG_TEMP_MSB 0x0a
28#define DS2782_REG_CURRENT_MSB 0x0e 31#define DS278x_REG_CURRENT_MSB 0x0e
29 32
30/* EEPROM Block */ 33/* EEPROM Block */
31#define DS2782_REG_RSNSP 0x69 /* Sense resistor value */ 34#define DS2782_REG_RSNSP 0x69 /* Sense resistor value */
@@ -33,18 +36,33 @@
33/* Current unit measurement in uA for a 1 milli-ohm sense resistor */ 36/* Current unit measurement in uA for a 1 milli-ohm sense resistor */
34#define DS2782_CURRENT_UNITS 1563 37#define DS2782_CURRENT_UNITS 1563
35 38
36#define to_ds2782_info(x) container_of(x, struct ds2782_info, battery) 39#define DS2786_REG_RARC 0x02 /* Remaining active relative capacity */
40
41#define DS2786_CURRENT_UNITS 25
42
43struct ds278x_info;
44
45struct ds278x_battery_ops {
46 int (*get_current)(struct ds278x_info *info, int *current_uA);
47 int (*get_voltage)(struct ds278x_info *info, int *voltage_uA);
48 int (*get_capacity)(struct ds278x_info *info, int *capacity_uA);
49
50};
51
52#define to_ds278x_info(x) container_of(x, struct ds278x_info, battery)
37 53
38struct ds2782_info { 54struct ds278x_info {
39 struct i2c_client *client; 55 struct i2c_client *client;
40 struct power_supply battery; 56 struct power_supply battery;
57 struct ds278x_battery_ops *ops;
41 int id; 58 int id;
59 int rsns;
42}; 60};
43 61
44static DEFINE_IDR(battery_id); 62static DEFINE_IDR(battery_id);
45static DEFINE_MUTEX(battery_lock); 63static DEFINE_MUTEX(battery_lock);
46 64
47static inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val) 65static inline int ds278x_read_reg(struct ds278x_info *info, int reg, u8 *val)
48{ 66{
49 int ret; 67 int ret;
50 68
@@ -58,7 +76,7 @@ static inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val)
58 return 0; 76 return 0;
59} 77}
60 78
61static inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb, 79static inline int ds278x_read_reg16(struct ds278x_info *info, int reg_msb,
62 s16 *val) 80 s16 *val)
63{ 81{
64 int ret; 82 int ret;
@@ -73,7 +91,7 @@ static inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb,
73 return 0; 91 return 0;
74} 92}
75 93
76static int ds2782_get_temp(struct ds2782_info *info, int *temp) 94static int ds278x_get_temp(struct ds278x_info *info, int *temp)
77{ 95{
78 s16 raw; 96 s16 raw;
79 int err; 97 int err;
@@ -84,14 +102,14 @@ static int ds2782_get_temp(struct ds2782_info *info, int *temp)
84 * celsius. The temperature value is stored as a 10 bit number, plus 102 * celsius. The temperature value is stored as a 10 bit number, plus
85 * sign in the upper bits of a 16 bit register. 103 * sign in the upper bits of a 16 bit register.
86 */ 104 */
87 err = ds2782_read_reg16(info, DS2782_REG_TEMP_MSB, &raw); 105 err = ds278x_read_reg16(info, DS278x_REG_TEMP_MSB, &raw);
88 if (err) 106 if (err)
89 return err; 107 return err;
90 *temp = ((raw / 32) * 125) / 100; 108 *temp = ((raw / 32) * 125) / 100;
91 return 0; 109 return 0;
92} 110}
93 111
94static int ds2782_get_current(struct ds2782_info *info, int *current_uA) 112static int ds2782_get_current(struct ds278x_info *info, int *current_uA)
95{ 113{
96 int sense_res; 114 int sense_res;
97 int err; 115 int err;
@@ -102,7 +120,7 @@ static int ds2782_get_current(struct ds2782_info *info, int *current_uA)
102 * The units of measurement for current are dependent on the value of 120 * The units of measurement for current are dependent on the value of
103 * the sense resistor. 121 * the sense resistor.
104 */ 122 */
105 err = ds2782_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw); 123 err = ds278x_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw);
106 if (err) 124 if (err)
107 return err; 125 return err;
108 if (sense_res_raw == 0) { 126 if (sense_res_raw == 0) {
@@ -113,14 +131,14 @@ static int ds2782_get_current(struct ds2782_info *info, int *current_uA)
113 131
114 dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n", 132 dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n",
115 sense_res); 133 sense_res);
116 err = ds2782_read_reg16(info, DS2782_REG_CURRENT_MSB, &raw); 134 err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw);
117 if (err) 135 if (err)
118 return err; 136 return err;
119 *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res); 137 *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res);
120 return 0; 138 return 0;
121} 139}
122 140
123static int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA) 141static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA)
124{ 142{
125 s16 raw; 143 s16 raw;
126 int err; 144 int err;
@@ -129,36 +147,77 @@ static int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA)
129 * Voltage is measured in units of 4.88mV. The voltage is stored as 147 * Voltage is measured in units of 4.88mV. The voltage is stored as
130 * a 10-bit number plus sign, in the upper bits of a 16-bit register 148 * a 10-bit number plus sign, in the upper bits of a 16-bit register
131 */ 149 */
132 err = ds2782_read_reg16(info, DS2782_REG_VOLT_MSB, &raw); 150 err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
133 if (err) 151 if (err)
134 return err; 152 return err;
135 *voltage_uA = (raw / 32) * 4800; 153 *voltage_uA = (raw / 32) * 4800;
136 return 0; 154 return 0;
137} 155}
138 156
139static int ds2782_get_capacity(struct ds2782_info *info, int *capacity) 157static int ds2782_get_capacity(struct ds278x_info *info, int *capacity)
140{ 158{
141 int err; 159 int err;
142 u8 raw; 160 u8 raw;
143 161
144 err = ds2782_read_reg(info, DS2782_REG_RARC, &raw); 162 err = ds278x_read_reg(info, DS2782_REG_RARC, &raw);
145 if (err) 163 if (err)
146 return err; 164 return err;
147 *capacity = raw; 165 *capacity = raw;
148 return raw; 166 return raw;
149} 167}
150 168
151static int ds2782_get_status(struct ds2782_info *info, int *status) 169static int ds2786_get_current(struct ds278x_info *info, int *current_uA)
170{
171 int err;
172 s16 raw;
173
174 err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw);
175 if (err)
176 return err;
177 *current_uA = (raw / 16) * (DS2786_CURRENT_UNITS / info->rsns);
178 return 0;
179}
180
181static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA)
182{
183 s16 raw;
184 int err;
185
186 /*
187 * Voltage is measured in units of 1.22mV. The voltage is stored as
188 * a 10-bit number plus sign, in the upper bits of a 16-bit register
189 */
190 err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
191 if (err)
192 return err;
193 *voltage_uA = (raw / 8) * 1220;
194 return 0;
195}
196
197static int ds2786_get_capacity(struct ds278x_info *info, int *capacity)
198{
199 int err;
200 u8 raw;
201
202 err = ds278x_read_reg(info, DS2786_REG_RARC, &raw);
203 if (err)
204 return err;
205 /* Relative capacity is displayed with resolution 0.5 % */
206 *capacity = raw/2 ;
207 return 0;
208}
209
210static int ds278x_get_status(struct ds278x_info *info, int *status)
152{ 211{
153 int err; 212 int err;
154 int current_uA; 213 int current_uA;
155 int capacity; 214 int capacity;
156 215
157 err = ds2782_get_current(info, &current_uA); 216 err = info->ops->get_current(info, &current_uA);
158 if (err) 217 if (err)
159 return err; 218 return err;
160 219
161 err = ds2782_get_capacity(info, &capacity); 220 err = info->ops->get_capacity(info, &capacity);
162 if (err) 221 if (err)
163 return err; 222 return err;
164 223
@@ -174,32 +233,32 @@ static int ds2782_get_status(struct ds2782_info *info, int *status)
174 return 0; 233 return 0;
175} 234}
176 235
177static int ds2782_battery_get_property(struct power_supply *psy, 236static int ds278x_battery_get_property(struct power_supply *psy,
178 enum power_supply_property prop, 237 enum power_supply_property prop,
179 union power_supply_propval *val) 238 union power_supply_propval *val)
180{ 239{
181 struct ds2782_info *info = to_ds2782_info(psy); 240 struct ds278x_info *info = to_ds278x_info(psy);
182 int ret; 241 int ret;
183 242
184 switch (prop) { 243 switch (prop) {
185 case POWER_SUPPLY_PROP_STATUS: 244 case POWER_SUPPLY_PROP_STATUS:
186 ret = ds2782_get_status(info, &val->intval); 245 ret = ds278x_get_status(info, &val->intval);
187 break; 246 break;
188 247
189 case POWER_SUPPLY_PROP_CAPACITY: 248 case POWER_SUPPLY_PROP_CAPACITY:
190 ret = ds2782_get_capacity(info, &val->intval); 249 ret = info->ops->get_capacity(info, &val->intval);
191 break; 250 break;
192 251
193 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 252 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
194 ret = ds2782_get_voltage(info, &val->intval); 253 ret = info->ops->get_voltage(info, &val->intval);
195 break; 254 break;
196 255
197 case POWER_SUPPLY_PROP_CURRENT_NOW: 256 case POWER_SUPPLY_PROP_CURRENT_NOW:
198 ret = ds2782_get_current(info, &val->intval); 257 ret = info->ops->get_current(info, &val->intval);
199 break; 258 break;
200 259
201 case POWER_SUPPLY_PROP_TEMP: 260 case POWER_SUPPLY_PROP_TEMP:
202 ret = ds2782_get_temp(info, &val->intval); 261 ret = ds278x_get_temp(info, &val->intval);
203 break; 262 break;
204 263
205 default: 264 default:
@@ -209,7 +268,7 @@ static int ds2782_battery_get_property(struct power_supply *psy,
209 return ret; 268 return ret;
210} 269}
211 270
212static enum power_supply_property ds2782_battery_props[] = { 271static enum power_supply_property ds278x_battery_props[] = {
213 POWER_SUPPLY_PROP_STATUS, 272 POWER_SUPPLY_PROP_STATUS,
214 POWER_SUPPLY_PROP_CAPACITY, 273 POWER_SUPPLY_PROP_CAPACITY,
215 POWER_SUPPLY_PROP_VOLTAGE_NOW, 274 POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -217,18 +276,18 @@ static enum power_supply_property ds2782_battery_props[] = {
217 POWER_SUPPLY_PROP_TEMP, 276 POWER_SUPPLY_PROP_TEMP,
218}; 277};
219 278
220static void ds2782_power_supply_init(struct power_supply *battery) 279static void ds278x_power_supply_init(struct power_supply *battery)
221{ 280{
222 battery->type = POWER_SUPPLY_TYPE_BATTERY; 281 battery->type = POWER_SUPPLY_TYPE_BATTERY;
223 battery->properties = ds2782_battery_props; 282 battery->properties = ds278x_battery_props;
224 battery->num_properties = ARRAY_SIZE(ds2782_battery_props); 283 battery->num_properties = ARRAY_SIZE(ds278x_battery_props);
225 battery->get_property = ds2782_battery_get_property; 284 battery->get_property = ds278x_battery_get_property;
226 battery->external_power_changed = NULL; 285 battery->external_power_changed = NULL;
227} 286}
228 287
229static int ds2782_battery_remove(struct i2c_client *client) 288static int ds278x_battery_remove(struct i2c_client *client)
230{ 289{
231 struct ds2782_info *info = i2c_get_clientdata(client); 290 struct ds278x_info *info = i2c_get_clientdata(client);
232 291
233 power_supply_unregister(&info->battery); 292 power_supply_unregister(&info->battery);
234 kfree(info->battery.name); 293 kfree(info->battery.name);
@@ -237,19 +296,45 @@ static int ds2782_battery_remove(struct i2c_client *client)
237 idr_remove(&battery_id, info->id); 296 idr_remove(&battery_id, info->id);
238 mutex_unlock(&battery_lock); 297 mutex_unlock(&battery_lock);
239 298
240 i2c_set_clientdata(client, info);
241
242 kfree(info); 299 kfree(info);
243 return 0; 300 return 0;
244} 301}
245 302
246static int ds2782_battery_probe(struct i2c_client *client, 303enum ds278x_num_id {
304 DS2782 = 0,
305 DS2786,
306};
307
308static struct ds278x_battery_ops ds278x_ops[] = {
309 [DS2782] = {
310 .get_current = ds2782_get_current,
311 .get_voltage = ds2782_get_voltage,
312 .get_capacity = ds2782_get_capacity,
313 },
314 [DS2786] = {
315 .get_current = ds2786_get_current,
316 .get_voltage = ds2786_get_voltage,
317 .get_capacity = ds2786_get_capacity,
318 }
319};
320
321static int ds278x_battery_probe(struct i2c_client *client,
247 const struct i2c_device_id *id) 322 const struct i2c_device_id *id)
248{ 323{
249 struct ds2782_info *info; 324 struct ds278x_platform_data *pdata = client->dev.platform_data;
325 struct ds278x_info *info;
250 int ret; 326 int ret;
251 int num; 327 int num;
252 328
329 /*
330 * ds2786 should have the sense resistor value set
331 * in the platform data
332 */
333 if (id->driver_data == DS2786 && !pdata) {
334 dev_err(&client->dev, "missing platform data for ds2786\n");
335 return -EINVAL;
336 }
337
253 /* Get an ID for this battery */ 338 /* Get an ID for this battery */
254 ret = idr_pre_get(&battery_id, GFP_KERNEL); 339 ret = idr_pre_get(&battery_id, GFP_KERNEL);
255 if (ret == 0) { 340 if (ret == 0) {
@@ -269,15 +354,20 @@ static int ds2782_battery_probe(struct i2c_client *client,
269 goto fail_info; 354 goto fail_info;
270 } 355 }
271 356
272 info->battery.name = kasprintf(GFP_KERNEL, "ds2782-%d", num); 357 info->battery.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num);
273 if (!info->battery.name) { 358 if (!info->battery.name) {
274 ret = -ENOMEM; 359 ret = -ENOMEM;
275 goto fail_name; 360 goto fail_name;
276 } 361 }
277 362
363 if (id->driver_data == DS2786)
364 info->rsns = pdata->rsns;
365
278 i2c_set_clientdata(client, info); 366 i2c_set_clientdata(client, info);
279 info->client = client; 367 info->client = client;
280 ds2782_power_supply_init(&info->battery); 368 info->id = num;
369 info->ops = &ds278x_ops[id->driver_data];
370 ds278x_power_supply_init(&info->battery);
281 371
282 ret = power_supply_register(&client->dev, &info->battery); 372 ret = power_supply_register(&client->dev, &info->battery);
283 if (ret) { 373 if (ret) {
@@ -290,7 +380,6 @@ static int ds2782_battery_probe(struct i2c_client *client,
290fail_register: 380fail_register:
291 kfree(info->battery.name); 381 kfree(info->battery.name);
292fail_name: 382fail_name:
293 i2c_set_clientdata(client, info);
294 kfree(info); 383 kfree(info);
295fail_info: 384fail_info:
296 mutex_lock(&battery_lock); 385 mutex_lock(&battery_lock);
@@ -300,31 +389,32 @@ fail_id:
300 return ret; 389 return ret;
301} 390}
302 391
303static const struct i2c_device_id ds2782_id[] = { 392static const struct i2c_device_id ds278x_id[] = {
304 {"ds2782", 0}, 393 {"ds2782", DS2782},
394 {"ds2786", DS2786},
305 {}, 395 {},
306}; 396};
307 397
308static struct i2c_driver ds2782_battery_driver = { 398static struct i2c_driver ds278x_battery_driver = {
309 .driver = { 399 .driver = {
310 .name = "ds2782-battery", 400 .name = "ds2782-battery",
311 }, 401 },
312 .probe = ds2782_battery_probe, 402 .probe = ds278x_battery_probe,
313 .remove = ds2782_battery_remove, 403 .remove = ds278x_battery_remove,
314 .id_table = ds2782_id, 404 .id_table = ds278x_id,
315}; 405};
316 406
317static int __init ds2782_init(void) 407static int __init ds278x_init(void)
318{ 408{
319 return i2c_add_driver(&ds2782_battery_driver); 409 return i2c_add_driver(&ds278x_battery_driver);
320} 410}
321module_init(ds2782_init); 411module_init(ds278x_init);
322 412
323static void __exit ds2782_exit(void) 413static void __exit ds278x_exit(void)
324{ 414{
325 i2c_del_driver(&ds2782_battery_driver); 415 i2c_del_driver(&ds278x_battery_driver);
326} 416}
327module_exit(ds2782_exit); 417module_exit(ds278x_exit);
328 418
329MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); 419MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
330MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver"); 420MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver");
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index a232de6a5703..69f8aa3a6a4b 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -404,6 +404,13 @@ static int usb_wakeup_enabled;
404 404
405static int pda_power_suspend(struct platform_device *pdev, pm_message_t state) 405static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
406{ 406{
407 if (pdata->suspend) {
408 int ret = pdata->suspend(state);
409
410 if (ret)
411 return ret;
412 }
413
407 if (device_may_wakeup(&pdev->dev)) { 414 if (device_may_wakeup(&pdev->dev)) {
408 if (ac_irq) 415 if (ac_irq)
409 ac_wakeup_enabled = !enable_irq_wake(ac_irq->start); 416 ac_wakeup_enabled = !enable_irq_wake(ac_irq->start);
@@ -423,6 +430,9 @@ static int pda_power_resume(struct platform_device *pdev)
423 disable_irq_wake(ac_irq->start); 430 disable_irq_wake(ac_irq->start);
424 } 431 }
425 432
433 if (pdata->resume)
434 return pdata->resume();
435
426 return 0; 436 return 0;
427} 437}
428#else 438#else
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index f38ba482be75..018de2b26998 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -12,15 +12,12 @@
12 12
13#ifdef CONFIG_SYSFS 13#ifdef CONFIG_SYSFS
14 14
15extern int power_supply_create_attrs(struct power_supply *psy); 15extern void power_supply_init_attrs(struct device_type *dev_type);
16extern void power_supply_remove_attrs(struct power_supply *psy);
17extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); 16extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
18 17
19#else 18#else
20 19
21static inline int power_supply_create_attrs(struct power_supply *psy) 20static inline void power_supply_init_attrs(struct device_type *dev_type) {}
22{ return 0; }
23static inline void power_supply_remove_attrs(struct power_supply *psy) {}
24#define power_supply_uevent NULL 21#define power_supply_uevent NULL
25 22
26#endif /* CONFIG_SYSFS */ 23#endif /* CONFIG_SYSFS */
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index cce75b40b435..91606bb55318 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -13,6 +13,7 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/types.h> 14#include <linux/types.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/slab.h>
16#include <linux/device.h> 17#include <linux/device.h>
17#include <linux/err.h> 18#include <linux/err.h>
18#include <linux/power_supply.h> 19#include <linux/power_supply.h>
@@ -22,6 +23,8 @@
22struct class *power_supply_class; 23struct class *power_supply_class;
23EXPORT_SYMBOL_GPL(power_supply_class); 24EXPORT_SYMBOL_GPL(power_supply_class);
24 25
26static struct device_type power_supply_dev_type;
27
25static int __power_supply_changed_work(struct device *dev, void *data) 28static int __power_supply_changed_work(struct device *dev, void *data)
26{ 29{
27 struct power_supply *psy = (struct power_supply *)data; 30 struct power_supply *psy = (struct power_supply *)data;
@@ -144,22 +147,39 @@ struct power_supply *power_supply_get_by_name(char *name)
144} 147}
145EXPORT_SYMBOL_GPL(power_supply_get_by_name); 148EXPORT_SYMBOL_GPL(power_supply_get_by_name);
146 149
150static void power_supply_dev_release(struct device *dev)
151{
152 pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
153 kfree(dev);
154}
155
147int power_supply_register(struct device *parent, struct power_supply *psy) 156int power_supply_register(struct device *parent, struct power_supply *psy)
148{ 157{
149 int rc = 0; 158 struct device *dev;
159 int rc;
150 160
151 psy->dev = device_create(power_supply_class, parent, 0, psy, 161 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
152 "%s", psy->name); 162 if (!dev)
153 if (IS_ERR(psy->dev)) { 163 return -ENOMEM;
154 rc = PTR_ERR(psy->dev);
155 goto dev_create_failed;
156 }
157 164
158 INIT_WORK(&psy->changed_work, power_supply_changed_work); 165 device_initialize(dev);
159 166
160 rc = power_supply_create_attrs(psy); 167 dev->class = power_supply_class;
168 dev->type = &power_supply_dev_type;
169 dev->parent = parent;
170 dev->release = power_supply_dev_release;
171 dev_set_drvdata(dev, psy);
172 psy->dev = dev;
173
174 rc = kobject_set_name(&dev->kobj, "%s", psy->name);
175 if (rc)
176 goto kobject_set_name_failed;
177
178 rc = device_add(dev);
161 if (rc) 179 if (rc)
162 goto create_attrs_failed; 180 goto device_add_failed;
181
182 INIT_WORK(&psy->changed_work, power_supply_changed_work);
163 183
164 rc = power_supply_create_triggers(psy); 184 rc = power_supply_create_triggers(psy);
165 if (rc) 185 if (rc)
@@ -170,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
170 goto success; 190 goto success;
171 191
172create_triggers_failed: 192create_triggers_failed:
173 power_supply_remove_attrs(psy);
174create_attrs_failed:
175 device_unregister(psy->dev); 193 device_unregister(psy->dev);
176dev_create_failed: 194kobject_set_name_failed:
195device_add_failed:
196 kfree(dev);
177success: 197success:
178 return rc; 198 return rc;
179} 199}
@@ -183,7 +203,6 @@ void power_supply_unregister(struct power_supply *psy)
183{ 203{
184 flush_scheduled_work(); 204 flush_scheduled_work();
185 power_supply_remove_triggers(psy); 205 power_supply_remove_triggers(psy);
186 power_supply_remove_attrs(psy);
187 device_unregister(psy->dev); 206 device_unregister(psy->dev);
188} 207}
189EXPORT_SYMBOL_GPL(power_supply_unregister); 208EXPORT_SYMBOL_GPL(power_supply_unregister);
@@ -196,6 +215,7 @@ static int __init power_supply_class_init(void)
196 return PTR_ERR(power_supply_class); 215 return PTR_ERR(power_supply_class);
197 216
198 power_supply_class->dev_uevent = power_supply_uevent; 217 power_supply_class->dev_uevent = power_supply_uevent;
218 power_supply_init_attrs(&power_supply_dev_type);
199 219
200 return 0; 220 return 0;
201} 221}
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 5b6e352ac7c1..6a86cdfd79fa 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -31,9 +31,9 @@
31 31
32#define POWER_SUPPLY_ATTR(_name) \ 32#define POWER_SUPPLY_ATTR(_name) \
33{ \ 33{ \
34 .attr = { .name = #_name, .mode = 0444 }, \ 34 .attr = { .name = #_name }, \
35 .show = power_supply_show_property, \ 35 .show = power_supply_show_property, \
36 .store = NULL, \ 36 .store = power_supply_store_property, \
37} 37}
38 38
39static struct device_attribute power_supply_attrs[]; 39static struct device_attribute power_supply_attrs[];
@@ -41,6 +41,9 @@ static struct device_attribute power_supply_attrs[];
41static ssize_t power_supply_show_property(struct device *dev, 41static ssize_t power_supply_show_property(struct device *dev,
42 struct device_attribute *attr, 42 struct device_attribute *attr,
43 char *buf) { 43 char *buf) {
44 static char *type_text[] = {
45 "Battery", "UPS", "Mains", "USB"
46 };
44 static char *status_text[] = { 47 static char *status_text[] = {
45 "Unknown", "Charging", "Discharging", "Not charging", "Full" 48 "Unknown", "Charging", "Discharging", "Not charging", "Full"
46 }; 49 };
@@ -58,12 +61,15 @@ static ssize_t power_supply_show_property(struct device *dev,
58 static char *capacity_level_text[] = { 61 static char *capacity_level_text[] = {
59 "Unknown", "Critical", "Low", "Normal", "High", "Full" 62 "Unknown", "Critical", "Low", "Normal", "High", "Full"
60 }; 63 };
61 ssize_t ret; 64 ssize_t ret = 0;
62 struct power_supply *psy = dev_get_drvdata(dev); 65 struct power_supply *psy = dev_get_drvdata(dev);
63 const ptrdiff_t off = attr - power_supply_attrs; 66 const ptrdiff_t off = attr - power_supply_attrs;
64 union power_supply_propval value; 67 union power_supply_propval value;
65 68
66 ret = psy->get_property(psy, off, &value); 69 if (off == POWER_SUPPLY_PROP_TYPE)
70 value.intval = psy->type;
71 else
72 ret = psy->get_property(psy, off, &value);
67 73
68 if (ret < 0) { 74 if (ret < 0) {
69 if (ret == -ENODATA) 75 if (ret == -ENODATA)
@@ -85,12 +91,37 @@ static ssize_t power_supply_show_property(struct device *dev,
85 return sprintf(buf, "%s\n", technology_text[value.intval]); 91 return sprintf(buf, "%s\n", technology_text[value.intval]);
86 else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) 92 else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
87 return sprintf(buf, "%s\n", capacity_level_text[value.intval]); 93 return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
94 else if (off == POWER_SUPPLY_PROP_TYPE)
95 return sprintf(buf, "%s\n", type_text[value.intval]);
88 else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) 96 else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
89 return sprintf(buf, "%s\n", value.strval); 97 return sprintf(buf, "%s\n", value.strval);
90 98
91 return sprintf(buf, "%d\n", value.intval); 99 return sprintf(buf, "%d\n", value.intval);
92} 100}
93 101
102static ssize_t power_supply_store_property(struct device *dev,
103 struct device_attribute *attr,
104 const char *buf, size_t count) {
105 ssize_t ret;
106 struct power_supply *psy = dev_get_drvdata(dev);
107 const ptrdiff_t off = attr - power_supply_attrs;
108 union power_supply_propval value;
109 long long_val;
110
111 /* TODO: support other types than int */
112 ret = strict_strtol(buf, 10, &long_val);
113 if (ret < 0)
114 return ret;
115
116 value.intval = long_val;
117
118 ret = psy->set_property(psy, off, &value);
119 if (ret < 0)
120 return ret;
121
122 return count;
123}
124
94/* Must be in the same order as POWER_SUPPLY_PROP_* */ 125/* Must be in the same order as POWER_SUPPLY_PROP_* */
95static struct device_attribute power_supply_attrs[] = { 126static struct device_attribute power_supply_attrs[] = {
96 /* Properties of type `int' */ 127 /* Properties of type `int' */
@@ -132,67 +163,59 @@ static struct device_attribute power_supply_attrs[] = {
132 POWER_SUPPLY_ATTR(time_to_empty_avg), 163 POWER_SUPPLY_ATTR(time_to_empty_avg),
133 POWER_SUPPLY_ATTR(time_to_full_now), 164 POWER_SUPPLY_ATTR(time_to_full_now),
134 POWER_SUPPLY_ATTR(time_to_full_avg), 165 POWER_SUPPLY_ATTR(time_to_full_avg),
166 POWER_SUPPLY_ATTR(type),
135 /* Properties of type `const char *' */ 167 /* Properties of type `const char *' */
136 POWER_SUPPLY_ATTR(model_name), 168 POWER_SUPPLY_ATTR(model_name),
137 POWER_SUPPLY_ATTR(manufacturer), 169 POWER_SUPPLY_ATTR(manufacturer),
138 POWER_SUPPLY_ATTR(serial_number), 170 POWER_SUPPLY_ATTR(serial_number),
139}; 171};
140 172
141static ssize_t power_supply_show_static_attrs(struct device *dev, 173static struct attribute *
142 struct device_attribute *attr, 174__power_supply_attrs[ARRAY_SIZE(power_supply_attrs) + 1];
143 char *buf) { 175
144 static char *type_text[] = { "Battery", "UPS", "Mains", "USB" }; 176static mode_t power_supply_attr_is_visible(struct kobject *kobj,
177 struct attribute *attr,
178 int attrno)
179{
180 struct device *dev = container_of(kobj, struct device, kobj);
145 struct power_supply *psy = dev_get_drvdata(dev); 181 struct power_supply *psy = dev_get_drvdata(dev);
182 int i;
146 183
147 return sprintf(buf, "%s\n", type_text[psy->type]); 184 for (i = 0; i < psy->num_properties; i++) {
148} 185 int property = psy->properties[i];
149 186
150static struct device_attribute power_supply_static_attrs[] = { 187 if (property == attrno) {
151 __ATTR(type, 0444, power_supply_show_static_attrs, NULL), 188 mode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
152};
153 189
154int power_supply_create_attrs(struct power_supply *psy) 190 if (psy->property_is_writeable &&
155{ 191 psy->property_is_writeable(psy, property) > 0)
156 int rc = 0; 192 mode |= S_IWUSR;
157 int i, j;
158
159 for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) {
160 rc = device_create_file(psy->dev,
161 &power_supply_static_attrs[i]);
162 if (rc)
163 goto statics_failed;
164 }
165 193
166 for (j = 0; j < psy->num_properties; j++) { 194 return mode;
167 rc = device_create_file(psy->dev, 195 }
168 &power_supply_attrs[psy->properties[j]]);
169 if (rc)
170 goto dynamics_failed;
171 } 196 }
172 197
173 goto succeed; 198 return 0;
174
175dynamics_failed:
176 while (j--)
177 device_remove_file(psy->dev,
178 &power_supply_attrs[psy->properties[j]]);
179statics_failed:
180 while (i--)
181 device_remove_file(psy->dev, &power_supply_static_attrs[i]);
182succeed:
183 return rc;
184} 199}
185 200
186void power_supply_remove_attrs(struct power_supply *psy) 201static struct attribute_group power_supply_attr_group = {
202 .attrs = __power_supply_attrs,
203 .is_visible = power_supply_attr_is_visible,
204};
205
206static const struct attribute_group *power_supply_attr_groups[] = {
207 &power_supply_attr_group,
208 NULL,
209};
210
211void power_supply_init_attrs(struct device_type *dev_type)
187{ 212{
188 int i; 213 int i;
189 214
190 for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) 215 dev_type->groups = power_supply_attr_groups;
191 device_remove_file(psy->dev, &power_supply_static_attrs[i]);
192 216
193 for (i = 0; i < psy->num_properties; i++) 217 for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++)
194 device_remove_file(psy->dev, 218 __power_supply_attrs[i] = &power_supply_attrs[i].attr;
195 &power_supply_attrs[psy->properties[i]]);
196} 219}
197 220
198static char *kstruprdup(const char *str, gfp_t gfp) 221static char *kstruprdup(const char *str, gfp_t gfp)
@@ -236,36 +259,6 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
236 if (!prop_buf) 259 if (!prop_buf)
237 return -ENOMEM; 260 return -ENOMEM;
238 261
239 for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {
240 struct device_attribute *attr;
241 char *line;
242
243 attr = &power_supply_static_attrs[j];
244
245 ret = power_supply_show_static_attrs(dev, attr, prop_buf);
246 if (ret < 0)
247 goto out;
248
249 line = strchr(prop_buf, '\n');
250 if (line)
251 *line = 0;
252
253 attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
254 if (!attrname) {
255 ret = -ENOMEM;
256 goto out;
257 }
258
259 dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
260
261 ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
262 kfree(attrname);
263 if (ret)
264 goto out;
265 }
266
267 dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);
268
269 for (j = 0; j < psy->num_properties; j++) { 262 for (j = 0; j < psy->num_properties; j++) {
270 struct device_attribute *attr; 263 struct device_attribute *attr;
271 char *line; 264 char *line;
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c
new file mode 100644
index 000000000000..0cd9f67d33e5
--- /dev/null
+++ b/drivers/power/test_power.c
@@ -0,0 +1,163 @@
1/*
2 * Power supply driver for testing.
3 *
4 * Copyright 2010 Anton Vorontsov <cbouatmailru@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/power_supply.h>
14#include <linux/errno.h>
15#include <linux/delay.h>
16#include <linux/vermagic.h>
17
18static int test_power_ac_online = 1;
19static int test_power_battery_status = POWER_SUPPLY_STATUS_CHARGING;
20
21static int test_power_get_ac_property(struct power_supply *psy,
22 enum power_supply_property psp,
23 union power_supply_propval *val)
24{
25 switch (psp) {
26 case POWER_SUPPLY_PROP_ONLINE:
27 val->intval = test_power_ac_online;
28 break;
29 default:
30 return -EINVAL;
31 }
32 return 0;
33}
34
35static int test_power_get_battery_property(struct power_supply *psy,
36 enum power_supply_property psp,
37 union power_supply_propval *val)
38{
39 switch (psp) {
40 case POWER_SUPPLY_PROP_MODEL_NAME:
41 val->strval = "Test battery";
42 break;
43 case POWER_SUPPLY_PROP_MANUFACTURER:
44 val->strval = "Linux";
45 break;
46 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
47 val->strval = UTS_RELEASE;
48 break;
49 case POWER_SUPPLY_PROP_STATUS:
50 val->intval = test_power_battery_status;
51 break;
52 case POWER_SUPPLY_PROP_CHARGE_TYPE:
53 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
54 break;
55 case POWER_SUPPLY_PROP_HEALTH:
56 val->intval = POWER_SUPPLY_HEALTH_GOOD;
57 break;
58 case POWER_SUPPLY_PROP_TECHNOLOGY:
59 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
60 break;
61 case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
62 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
63 break;
64 case POWER_SUPPLY_PROP_CAPACITY:
65 val->intval = 50;
66 break;
67 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
68 case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
69 val->intval = 3600;
70 break;
71 default:
72 pr_info("%s: some properties deliberately report errors.\n",
73 __func__);
74 return -EINVAL;
75 }
76 return 0;
77}
78
79static enum power_supply_property test_power_ac_props[] = {
80 POWER_SUPPLY_PROP_ONLINE,
81};
82
83static enum power_supply_property test_power_battery_props[] = {
84 POWER_SUPPLY_PROP_STATUS,
85 POWER_SUPPLY_PROP_CHARGE_TYPE,
86 POWER_SUPPLY_PROP_HEALTH,
87 POWER_SUPPLY_PROP_TECHNOLOGY,
88 POWER_SUPPLY_PROP_CHARGE_FULL,
89 POWER_SUPPLY_PROP_CHARGE_EMPTY,
90 POWER_SUPPLY_PROP_CAPACITY,
91 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
92 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
93 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
94 POWER_SUPPLY_PROP_MODEL_NAME,
95 POWER_SUPPLY_PROP_MANUFACTURER,
96 POWER_SUPPLY_PROP_SERIAL_NUMBER,
97};
98
99static char *test_power_ac_supplied_to[] = {
100 "test_battery",
101};
102
103static struct power_supply test_power_supplies[] = {
104 {
105 .name = "test_ac",
106 .type = POWER_SUPPLY_TYPE_MAINS,
107 .supplied_to = test_power_ac_supplied_to,
108 .num_supplicants = ARRAY_SIZE(test_power_ac_supplied_to),
109 .properties = test_power_ac_props,
110 .num_properties = ARRAY_SIZE(test_power_ac_props),
111 .get_property = test_power_get_ac_property,
112 }, {
113 .name = "test_battery",
114 .type = POWER_SUPPLY_TYPE_BATTERY,
115 .properties = test_power_battery_props,
116 .num_properties = ARRAY_SIZE(test_power_battery_props),
117 .get_property = test_power_get_battery_property,
118 },
119};
120
121static int __init test_power_init(void)
122{
123 int i;
124 int ret;
125
126 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) {
127 ret = power_supply_register(NULL, &test_power_supplies[i]);
128 if (ret) {
129 pr_err("%s: failed to register %s\n", __func__,
130 test_power_supplies[i].name);
131 goto failed;
132 }
133 }
134
135 return 0;
136failed:
137 while (--i >= 0)
138 power_supply_unregister(&test_power_supplies[i]);
139 return ret;
140}
141module_init(test_power_init);
142
143static void __exit test_power_exit(void)
144{
145 int i;
146
147 /* Let's see how we handle changes... */
148 test_power_ac_online = 0;
149 test_power_battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
150 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
151 power_supply_changed(&test_power_supplies[i]);
152 pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n",
153 __func__);
154 ssleep(10);
155
156 for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
157 power_supply_unregister(&test_power_supplies[i]);
158}
159module_exit(test_power_exit);
160
161MODULE_DESCRIPTION("Power supply driver for testing");
162MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
163MODULE_LICENSE("GPL");
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
index 2eab35aab311..ee04936b2db5 100644
--- a/drivers/power/tosa_battery.c
+++ b/drivers/power/tosa_battery.c
@@ -61,7 +61,7 @@ static unsigned long tosa_read_bat(struct tosa_bat *bat)
61 mutex_lock(&bat_lock); 61 mutex_lock(&bat_lock);
62 gpio_set_value(bat->gpio_bat, 1); 62 gpio_set_value(bat->gpio_bat, 1);
63 msleep(5); 63 msleep(5);
64 value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, 64 value = wm97xx_read_aux_adc(dev_get_drvdata(bat->psy.dev->parent),
65 bat->adc_bat); 65 bat->adc_bat);
66 gpio_set_value(bat->gpio_bat, 0); 66 gpio_set_value(bat->gpio_bat, 0);
67 mutex_unlock(&bat_lock); 67 mutex_unlock(&bat_lock);
@@ -81,7 +81,7 @@ static unsigned long tosa_read_temp(struct tosa_bat *bat)
81 mutex_lock(&bat_lock); 81 mutex_lock(&bat_lock);
82 gpio_set_value(bat->gpio_temp, 1); 82 gpio_set_value(bat->gpio_temp, 1);
83 msleep(5); 83 msleep(5);
84 value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, 84 value = wm97xx_read_aux_adc(dev_get_drvdata(bat->psy.dev->parent),
85 bat->adc_temp); 85 bat->adc_temp);
86 gpio_set_value(bat->gpio_temp, 0); 86 gpio_set_value(bat->gpio_temp, 0);
87 mutex_unlock(&bat_lock); 87 mutex_unlock(&bat_lock);
diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c
index 875c4d0f776b..fbcc36dae470 100644
--- a/drivers/power/wm831x_power.c
+++ b/drivers/power/wm831x_power.c
@@ -537,9 +537,9 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
537 goto err_battery; 537 goto err_battery;
538 538
539 irq = platform_get_irq_byname(pdev, "SYSLO"); 539 irq = platform_get_irq_byname(pdev, "SYSLO");
540 ret = wm831x_request_irq(wm831x, irq, wm831x_syslo_irq, 540 ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq,
541 IRQF_TRIGGER_RISING, "SYSLO", 541 IRQF_TRIGGER_RISING, "System power low",
542 power); 542 power);
543 if (ret != 0) { 543 if (ret != 0) {
544 dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n", 544 dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
545 irq, ret); 545 irq, ret);
@@ -547,9 +547,9 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
547 } 547 }
548 548
549 irq = platform_get_irq_byname(pdev, "PWR SRC"); 549 irq = platform_get_irq_byname(pdev, "PWR SRC");
550 ret = wm831x_request_irq(wm831x, irq, wm831x_pwr_src_irq, 550 ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq,
551 IRQF_TRIGGER_RISING, "Power source", 551 IRQF_TRIGGER_RISING, "Power source",
552 power); 552 power);
553 if (ret != 0) { 553 if (ret != 0) {
554 dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n", 554 dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n",
555 irq, ret); 555 irq, ret);
@@ -558,10 +558,10 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
558 558
559 for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { 559 for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
560 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]); 560 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
561 ret = wm831x_request_irq(wm831x, irq, wm831x_bat_irq, 561 ret = request_threaded_irq(irq, NULL, wm831x_bat_irq,
562 IRQF_TRIGGER_RISING, 562 IRQF_TRIGGER_RISING,
563 wm831x_bat_irqs[i], 563 wm831x_bat_irqs[i],
564 power); 564 power);
565 if (ret != 0) { 565 if (ret != 0) {
566 dev_err(&pdev->dev, 566 dev_err(&pdev->dev,
567 "Failed to request %s IRQ %d: %d\n", 567 "Failed to request %s IRQ %d: %d\n",
@@ -575,13 +575,13 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
575err_bat_irq: 575err_bat_irq:
576 for (; i >= 0; i--) { 576 for (; i >= 0; i--) {
577 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]); 577 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
578 wm831x_free_irq(wm831x, irq, power); 578 free_irq(irq, power);
579 } 579 }
580 irq = platform_get_irq_byname(pdev, "PWR SRC"); 580 irq = platform_get_irq_byname(pdev, "PWR SRC");
581 wm831x_free_irq(wm831x, irq, power); 581 free_irq(irq, power);
582err_syslo: 582err_syslo:
583 irq = platform_get_irq_byname(pdev, "SYSLO"); 583 irq = platform_get_irq_byname(pdev, "SYSLO");
584 wm831x_free_irq(wm831x, irq, power); 584 free_irq(irq, power);
585err_usb: 585err_usb:
586 power_supply_unregister(usb); 586 power_supply_unregister(usb);
587err_battery: 587err_battery:
@@ -596,19 +596,18 @@ err_kmalloc:
596static __devexit int wm831x_power_remove(struct platform_device *pdev) 596static __devexit int wm831x_power_remove(struct platform_device *pdev)
597{ 597{
598 struct wm831x_power *wm831x_power = platform_get_drvdata(pdev); 598 struct wm831x_power *wm831x_power = platform_get_drvdata(pdev);
599 struct wm831x *wm831x = wm831x_power->wm831x;
600 int irq, i; 599 int irq, i;
601 600
602 for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { 601 for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {
603 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]); 602 irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
604 wm831x_free_irq(wm831x, irq, wm831x_power); 603 free_irq(irq, wm831x_power);
605 } 604 }
606 605
607 irq = platform_get_irq_byname(pdev, "PWR SRC"); 606 irq = platform_get_irq_byname(pdev, "PWR SRC");
608 wm831x_free_irq(wm831x, irq, wm831x_power); 607 free_irq(irq, wm831x_power);
609 608
610 irq = platform_get_irq_byname(pdev, "SYSLO"); 609 irq = platform_get_irq_byname(pdev, "SYSLO");
611 wm831x_free_irq(wm831x, irq, wm831x_power); 610 free_irq(irq, wm831x_power);
612 611
613 power_supply_unregister(&wm831x_power->battery); 612 power_supply_unregister(&wm831x_power->battery);
614 power_supply_unregister(&wm831x_power->wall); 613 power_supply_unregister(&wm831x_power->wall);
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c
index 94c70650aafc..4e8afce0c818 100644
--- a/drivers/power/wm97xx_battery.c
+++ b/drivers/power/wm97xx_battery.c
@@ -308,6 +308,9 @@ static void __exit wm97xx_bat_exit(void)
308 platform_driver_unregister(&wm97xx_bat_driver); 308 platform_driver_unregister(&wm97xx_bat_driver);
309} 309}
310 310
311/* The interface is deprecated, as well as linux/wm97xx_batt.h */
312void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data);
313
311void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data) 314void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data)
312{ 315{
313 gpdata = data; 316 gpdata = data;
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c
new file mode 100644
index 000000000000..9cca465436e3
--- /dev/null
+++ b/drivers/power/z2_battery.c
@@ -0,0 +1,328 @@
1/*
2 * Battery measurement code for Zipit Z2
3 *
4 * Copyright (C) 2009 Peter Edwards <sweetlilmre@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/power_supply.h>
17#include <linux/i2c.h>
18#include <linux/spinlock.h>
19#include <linux/interrupt.h>
20#include <linux/gpio.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <asm/irq.h>
24#include <asm/mach/irq.h>
25#include <linux/z2_battery.h>
26
27#define Z2_DEFAULT_NAME "Z2"
28
29struct z2_charger {
30 struct z2_battery_info *info;
31 int bat_status;
32 struct i2c_client *client;
33 struct power_supply batt_ps;
34 struct mutex work_lock;
35 struct work_struct bat_work;
36};
37
38static unsigned long z2_read_bat(struct z2_charger *charger)
39{
40 int data;
41 data = i2c_smbus_read_byte_data(charger->client,
42 charger->info->batt_I2C_reg);
43 if (data < 0)
44 return 0;
45
46 return data * charger->info->batt_mult / charger->info->batt_div;
47}
48
49static int z2_batt_get_property(struct power_supply *batt_ps,
50 enum power_supply_property psp,
51 union power_supply_propval *val)
52{
53 struct z2_charger *charger = container_of(batt_ps, struct z2_charger,
54 batt_ps);
55 struct z2_battery_info *info = charger->info;
56
57 switch (psp) {
58 case POWER_SUPPLY_PROP_STATUS:
59 val->intval = charger->bat_status;
60 break;
61 case POWER_SUPPLY_PROP_TECHNOLOGY:
62 val->intval = info->batt_tech;
63 break;
64 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
65 if (info->batt_I2C_reg >= 0)
66 val->intval = z2_read_bat(charger);
67 else
68 return -EINVAL;
69 break;
70 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
71 if (info->max_voltage >= 0)
72 val->intval = info->max_voltage;
73 else
74 return -EINVAL;
75 break;
76 case POWER_SUPPLY_PROP_VOLTAGE_MIN:
77 if (info->min_voltage >= 0)
78 val->intval = info->min_voltage;
79 else
80 return -EINVAL;
81 break;
82 case POWER_SUPPLY_PROP_PRESENT:
83 val->intval = 1;
84 break;
85 default:
86 return -EINVAL;
87 }
88
89 return 0;
90}
91
92static void z2_batt_ext_power_changed(struct power_supply *batt_ps)
93{
94 struct z2_charger *charger = container_of(batt_ps, struct z2_charger,
95 batt_ps);
96 schedule_work(&charger->bat_work);
97}
98
99static void z2_batt_update(struct z2_charger *charger)
100{
101 int old_status = charger->bat_status;
102 struct z2_battery_info *info;
103
104 info = charger->info;
105
106 mutex_lock(&charger->work_lock);
107
108 charger->bat_status = (info->charge_gpio >= 0) ?
109 (gpio_get_value(info->charge_gpio) ?
110 POWER_SUPPLY_STATUS_CHARGING :
111 POWER_SUPPLY_STATUS_DISCHARGING) :
112 POWER_SUPPLY_STATUS_UNKNOWN;
113
114 if (old_status != charger->bat_status) {
115 pr_debug("%s: %i -> %i\n", charger->batt_ps.name, old_status,
116 charger->bat_status);
117 power_supply_changed(&charger->batt_ps);
118 }
119
120 mutex_unlock(&charger->work_lock);
121}
122
123static void z2_batt_work(struct work_struct *work)
124{
125 struct z2_charger *charger;
126 charger = container_of(work, struct z2_charger, bat_work);
127 z2_batt_update(charger);
128}
129
130static irqreturn_t z2_charge_switch_irq(int irq, void *devid)
131{
132 struct z2_charger *charger = devid;
133 schedule_work(&charger->bat_work);
134 return IRQ_HANDLED;
135}
136
137static int z2_batt_ps_init(struct z2_charger *charger, int props)
138{
139 int i = 0;
140 enum power_supply_property *prop;
141 struct z2_battery_info *info = charger->info;
142
143 if (info->batt_tech >= 0)
144 props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */
145 if (info->batt_I2C_reg >= 0)
146 props++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */
147 if (info->max_voltage >= 0)
148 props++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */
149 if (info->min_voltage >= 0)
150 props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */
151
152 prop = kzalloc(props * sizeof(*prop), GFP_KERNEL);
153 if (!prop)
154 return -ENOMEM;
155
156 prop[i++] = POWER_SUPPLY_PROP_PRESENT;
157 if (info->charge_gpio >= 0)
158 prop[i++] = POWER_SUPPLY_PROP_STATUS;
159 if (info->batt_tech >= 0)
160 prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY;
161 if (info->batt_I2C_reg >= 0)
162 prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
163 if (info->max_voltage >= 0)
164 prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MAX;
165 if (info->min_voltage >= 0)
166 prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MIN;
167
168 if (!info->batt_name) {
169 dev_info(&charger->client->dev,
170 "Please consider setting proper battery "
171 "name in platform definition file, falling "
172 "back to name \" Z2_DEFAULT_NAME \"\n");
173 charger->batt_ps.name = Z2_DEFAULT_NAME;
174 } else
175 charger->batt_ps.name = info->batt_name;
176
177 charger->batt_ps.properties = prop;
178 charger->batt_ps.num_properties = props;
179 charger->batt_ps.type = POWER_SUPPLY_TYPE_BATTERY;
180 charger->batt_ps.get_property = z2_batt_get_property;
181 charger->batt_ps.external_power_changed = z2_batt_ext_power_changed;
182 charger->batt_ps.use_for_apm = 1;
183
184 return 0;
185}
186
187static int __devinit z2_batt_probe(struct i2c_client *client,
188 const struct i2c_device_id *id)
189{
190 int ret = 0;
191 int props = 1; /* POWER_SUPPLY_PROP_PRESENT */
192 struct z2_charger *charger;
193 struct z2_battery_info *info = client->dev.platform_data;
194
195 if (info == NULL) {
196 dev_err(&client->dev,
197 "Please set platform device platform_data"
198 " to a valid z2_battery_info pointer!\n");
199 return -EINVAL;
200 }
201
202 charger = kzalloc(sizeof(*charger), GFP_KERNEL);
203 if (charger == NULL)
204 return -ENOMEM;
205
206 charger->bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
207 charger->info = info;
208 charger->client = client;
209 i2c_set_clientdata(client, charger);
210
211 mutex_init(&charger->work_lock);
212
213 if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) {
214 ret = gpio_request(info->charge_gpio, "BATT CHRG");
215 if (ret)
216 goto err;
217
218 ret = gpio_direction_input(info->charge_gpio);
219 if (ret)
220 goto err2;
221
222 set_irq_type(gpio_to_irq(info->charge_gpio),
223 IRQ_TYPE_EDGE_BOTH);
224 ret = request_irq(gpio_to_irq(info->charge_gpio),
225 z2_charge_switch_irq, IRQF_DISABLED,
226 "AC Detect", charger);
227 if (ret)
228 goto err3;
229 }
230
231 ret = z2_batt_ps_init(charger, props);
232 if (ret)
233 goto err3;
234
235 INIT_WORK(&charger->bat_work, z2_batt_work);
236
237 ret = power_supply_register(&client->dev, &charger->batt_ps);
238 if (ret)
239 goto err4;
240
241 schedule_work(&charger->bat_work);
242
243 return 0;
244
245err4:
246 kfree(charger->batt_ps.properties);
247err3:
248 if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio))
249 free_irq(gpio_to_irq(info->charge_gpio), charger);
250err2:
251 if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio))
252 gpio_free(info->charge_gpio);
253err:
254 kfree(charger);
255 return ret;
256}
257
258static int __devexit z2_batt_remove(struct i2c_client *client)
259{
260 struct z2_charger *charger = i2c_get_clientdata(client);
261 struct z2_battery_info *info = charger->info;
262
263 flush_scheduled_work();
264 power_supply_unregister(&charger->batt_ps);
265
266 kfree(charger->batt_ps.properties);
267 if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) {
268 free_irq(gpio_to_irq(info->charge_gpio), charger);
269 gpio_free(info->charge_gpio);
270 }
271
272 kfree(charger);
273
274 return 0;
275}
276
277#ifdef CONFIG_PM
278static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
279{
280 flush_scheduled_work();
281 return 0;
282}
283
284static int z2_batt_resume(struct i2c_client *client)
285{
286 struct z2_charger *charger = i2c_get_clientdata(client);
287
288 schedule_work(&charger->bat_work);
289 return 0;
290}
291#else
292#define z2_batt_suspend NULL
293#define z2_batt_resume NULL
294#endif
295
296static const struct i2c_device_id z2_batt_id[] = {
297 { "aer915", 0 },
298 { }
299};
300
301static struct i2c_driver z2_batt_driver = {
302 .driver = {
303 .name = "z2-battery",
304 .owner = THIS_MODULE,
305 },
306 .probe = z2_batt_probe,
307 .remove = z2_batt_remove,
308 .suspend = z2_batt_suspend,
309 .resume = z2_batt_resume,
310 .id_table = z2_batt_id,
311};
312
313static int __init z2_batt_init(void)
314{
315 return i2c_add_driver(&z2_batt_driver);
316}
317
318static void __exit z2_batt_exit(void)
319{
320 i2c_del_driver(&z2_batt_driver);
321}
322
323module_init(z2_batt_init);
324module_exit(z2_batt_exit);
325
326MODULE_LICENSE("GPL");
327MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>");
328MODULE_DESCRIPTION("Zipit Z2 battery driver");