diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-24 11:00:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-24 11:00:13 -0400 |
commit | 15953654cc312429740fd58fb37a5a3d63a54376 (patch) | |
tree | bbb6bf8d4ea943545e29ce896848182c4f206298 /drivers | |
parent | c3ed9ea4ab460080dea9449c709be9316c670c72 (diff) | |
parent | 24af3202459d9a25643009b1ab8ab5ff04d94b49 (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/Kconfig | 15 | ||||
-rw-r--r-- | drivers/power/Makefile | 2 | ||||
-rw-r--r-- | drivers/power/ds2760_battery.c | 64 | ||||
-rw-r--r-- | drivers/power/ds2782_battery.c | 194 | ||||
-rw-r--r-- | drivers/power/pda_power.c | 10 | ||||
-rw-r--r-- | drivers/power/power_supply.h | 7 | ||||
-rw-r--r-- | drivers/power/power_supply_core.c | 48 | ||||
-rw-r--r-- | drivers/power/power_supply_sysfs.c | 145 | ||||
-rw-r--r-- | drivers/power/test_power.c | 163 | ||||
-rw-r--r-- | drivers/power/tosa_battery.c | 4 | ||||
-rw-r--r-- | drivers/power/wm831x_power.c | 33 | ||||
-rw-r--r-- | drivers/power/wm97xx_battery.c | 3 | ||||
-rw-r--r-- | drivers/power/z2_battery.c | 328 |
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 | ||
60 | config TEST_POWER | ||
61 | tristate "Test power driver" | ||
62 | help | ||
63 | This driver is used for testing. It's safe to say M here. | ||
64 | |||
60 | config BATTERY_DS2760 | 65 | config 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 | ||
67 | config BATTERY_DS2782 | 72 | config 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 | ||
74 | config BATTERY_PMU | 79 | config 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 | ||
133 | config 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 | |||
128 | config CHARGER_PCF50633 | 139 | config 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 | |||
20 | obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o | 20 | obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o |
21 | obj-$(CONFIG_WM831X_POWER) += wm831x_power.o | 21 | obj-$(CONFIG_WM831X_POWER) += wm831x_power.o |
22 | obj-$(CONFIG_WM8350_POWER) += wm8350_power.o | 22 | obj-$(CONFIG_WM8350_POWER) += wm8350_power.o |
23 | obj-$(CONFIG_TEST_POWER) += test_power.o | ||
23 | 24 | ||
24 | obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o | 25 | obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o |
25 | obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o | 26 | obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o |
@@ -31,4 +32,5 @@ obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o | |||
31 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o | 32 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o |
32 | obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o | 33 | obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o |
33 | obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o | 34 | obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o |
35 | obj-$(CONFIG_BATTERY_Z2) += z2_battery.o | ||
34 | obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o | 36 | obj-$(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 | ||
307 | static 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 | |||
307 | static void ds2760_battery_work(struct work_struct *work) | 329 | static 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 | ||
451 | static 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 | |||
475 | static 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 | |||
429 | static enum power_supply_property ds2760_battery_props[] = { | 490 | static 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 | |||
43 | struct ds278x_info; | ||
44 | |||
45 | struct 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 | ||
38 | struct ds2782_info { | 54 | struct 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 | ||
44 | static DEFINE_IDR(battery_id); | 62 | static DEFINE_IDR(battery_id); |
45 | static DEFINE_MUTEX(battery_lock); | 63 | static DEFINE_MUTEX(battery_lock); |
46 | 64 | ||
47 | static inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val) | 65 | static 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 | ||
61 | static inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb, | 79 | static 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 | ||
76 | static int ds2782_get_temp(struct ds2782_info *info, int *temp) | 94 | static 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 | ||
94 | static int ds2782_get_current(struct ds2782_info *info, int *current_uA) | 112 | static 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 | ||
123 | static int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA) | 141 | static 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 | ||
139 | static int ds2782_get_capacity(struct ds2782_info *info, int *capacity) | 157 | static 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 | ||
151 | static int ds2782_get_status(struct ds2782_info *info, int *status) | 169 | static 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 | |||
181 | static 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 | |||
197 | static 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 | |||
210 | static 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, ¤t_uA); | 216 | err = info->ops->get_current(info, ¤t_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 | ||
177 | static int ds2782_battery_get_property(struct power_supply *psy, | 236 | static 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 | ||
212 | static enum power_supply_property ds2782_battery_props[] = { | 271 | static 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 | ||
220 | static void ds2782_power_supply_init(struct power_supply *battery) | 279 | static 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 | ||
229 | static int ds2782_battery_remove(struct i2c_client *client) | 288 | static 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 | ||
246 | static int ds2782_battery_probe(struct i2c_client *client, | 303 | enum ds278x_num_id { |
304 | DS2782 = 0, | ||
305 | DS2786, | ||
306 | }; | ||
307 | |||
308 | static 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 | |||
321 | static 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, | |||
290 | fail_register: | 380 | fail_register: |
291 | kfree(info->battery.name); | 381 | kfree(info->battery.name); |
292 | fail_name: | 382 | fail_name: |
293 | i2c_set_clientdata(client, info); | ||
294 | kfree(info); | 383 | kfree(info); |
295 | fail_info: | 384 | fail_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 | ||
303 | static const struct i2c_device_id ds2782_id[] = { | 392 | static const struct i2c_device_id ds278x_id[] = { |
304 | {"ds2782", 0}, | 393 | {"ds2782", DS2782}, |
394 | {"ds2786", DS2786}, | ||
305 | {}, | 395 | {}, |
306 | }; | 396 | }; |
307 | 397 | ||
308 | static struct i2c_driver ds2782_battery_driver = { | 398 | static 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 | ||
317 | static int __init ds2782_init(void) | 407 | static 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 | } |
321 | module_init(ds2782_init); | 411 | module_init(ds278x_init); |
322 | 412 | ||
323 | static void __exit ds2782_exit(void) | 413 | static void __exit ds278x_exit(void) |
324 | { | 414 | { |
325 | i2c_del_driver(&ds2782_battery_driver); | 415 | i2c_del_driver(&ds278x_battery_driver); |
326 | } | 416 | } |
327 | module_exit(ds2782_exit); | 417 | module_exit(ds278x_exit); |
328 | 418 | ||
329 | MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); | 419 | MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); |
330 | MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver"); | 420 | MODULE_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 | ||
405 | static int pda_power_suspend(struct platform_device *pdev, pm_message_t state) | 405 | static 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 | ||
15 | extern int power_supply_create_attrs(struct power_supply *psy); | 15 | extern void power_supply_init_attrs(struct device_type *dev_type); |
16 | extern void power_supply_remove_attrs(struct power_supply *psy); | ||
17 | extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); | 16 | extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env); |
18 | 17 | ||
19 | #else | 18 | #else |
20 | 19 | ||
21 | static inline int power_supply_create_attrs(struct power_supply *psy) | 20 | static inline void power_supply_init_attrs(struct device_type *dev_type) {} |
22 | { return 0; } | ||
23 | static 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 @@ | |||
22 | struct class *power_supply_class; | 23 | struct class *power_supply_class; |
23 | EXPORT_SYMBOL_GPL(power_supply_class); | 24 | EXPORT_SYMBOL_GPL(power_supply_class); |
24 | 25 | ||
26 | static struct device_type power_supply_dev_type; | ||
27 | |||
25 | static int __power_supply_changed_work(struct device *dev, void *data) | 28 | static 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 | } |
145 | EXPORT_SYMBOL_GPL(power_supply_get_by_name); | 148 | EXPORT_SYMBOL_GPL(power_supply_get_by_name); |
146 | 149 | ||
150 | static 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 | |||
147 | int power_supply_register(struct device *parent, struct power_supply *psy) | 156 | int 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 | ||
172 | create_triggers_failed: | 192 | create_triggers_failed: |
173 | power_supply_remove_attrs(psy); | ||
174 | create_attrs_failed: | ||
175 | device_unregister(psy->dev); | 193 | device_unregister(psy->dev); |
176 | dev_create_failed: | 194 | kobject_set_name_failed: |
195 | device_add_failed: | ||
196 | kfree(dev); | ||
177 | success: | 197 | success: |
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 | } |
189 | EXPORT_SYMBOL_GPL(power_supply_unregister); | 208 | EXPORT_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 | ||
39 | static struct device_attribute power_supply_attrs[]; | 39 | static struct device_attribute power_supply_attrs[]; |
@@ -41,6 +41,9 @@ static struct device_attribute power_supply_attrs[]; | |||
41 | static ssize_t power_supply_show_property(struct device *dev, | 41 | static 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 | ||
102 | static 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_* */ |
95 | static struct device_attribute power_supply_attrs[] = { | 126 | static 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 | ||
141 | static ssize_t power_supply_show_static_attrs(struct device *dev, | 173 | static 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" }; | 176 | static 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 | ||
150 | static 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 | ||
154 | int 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 | |||
175 | dynamics_failed: | ||
176 | while (j--) | ||
177 | device_remove_file(psy->dev, | ||
178 | &power_supply_attrs[psy->properties[j]]); | ||
179 | statics_failed: | ||
180 | while (i--) | ||
181 | device_remove_file(psy->dev, &power_supply_static_attrs[i]); | ||
182 | succeed: | ||
183 | return rc; | ||
184 | } | 199 | } |
185 | 200 | ||
186 | void power_supply_remove_attrs(struct power_supply *psy) | 201 | static struct attribute_group power_supply_attr_group = { |
202 | .attrs = __power_supply_attrs, | ||
203 | .is_visible = power_supply_attr_is_visible, | ||
204 | }; | ||
205 | |||
206 | static const struct attribute_group *power_supply_attr_groups[] = { | ||
207 | &power_supply_attr_group, | ||
208 | NULL, | ||
209 | }; | ||
210 | |||
211 | void 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 | ||
198 | static char *kstruprdup(const char *str, gfp_t gfp) | 221 | static 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 | |||
18 | static int test_power_ac_online = 1; | ||
19 | static int test_power_battery_status = POWER_SUPPLY_STATUS_CHARGING; | ||
20 | |||
21 | static 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 | |||
35 | static 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 | |||
79 | static enum power_supply_property test_power_ac_props[] = { | ||
80 | POWER_SUPPLY_PROP_ONLINE, | ||
81 | }; | ||
82 | |||
83 | static 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 | |||
99 | static char *test_power_ac_supplied_to[] = { | ||
100 | "test_battery", | ||
101 | }; | ||
102 | |||
103 | static 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 | |||
121 | static 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; | ||
136 | failed: | ||
137 | while (--i >= 0) | ||
138 | power_supply_unregister(&test_power_supplies[i]); | ||
139 | return ret; | ||
140 | } | ||
141 | module_init(test_power_init); | ||
142 | |||
143 | static 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 | } | ||
159 | module_exit(test_power_exit); | ||
160 | |||
161 | MODULE_DESCRIPTION("Power supply driver for testing"); | ||
162 | MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); | ||
163 | MODULE_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) | |||
575 | err_bat_irq: | 575 | err_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); |
582 | err_syslo: | 582 | err_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); |
585 | err_usb: | 585 | err_usb: |
586 | power_supply_unregister(usb); | 586 | power_supply_unregister(usb); |
587 | err_battery: | 587 | err_battery: |
@@ -596,19 +596,18 @@ err_kmalloc: | |||
596 | static __devexit int wm831x_power_remove(struct platform_device *pdev) | 596 | static __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 */ | ||
312 | void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data); | ||
313 | |||
311 | void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data) | 314 | void 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 | |||
29 | struct 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 | |||
38 | static 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 | |||
49 | static 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 | |||
92 | static 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 | |||
99 | static 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 | |||
123 | static 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 | |||
130 | static 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 | |||
137 | static 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 | |||
187 | static 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 | |||
245 | err4: | ||
246 | kfree(charger->batt_ps.properties); | ||
247 | err3: | ||
248 | if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) | ||
249 | free_irq(gpio_to_irq(info->charge_gpio), charger); | ||
250 | err2: | ||
251 | if (info->charge_gpio >= 0 && gpio_is_valid(info->charge_gpio)) | ||
252 | gpio_free(info->charge_gpio); | ||
253 | err: | ||
254 | kfree(charger); | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static 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 | ||
278 | static int z2_batt_suspend(struct i2c_client *client, pm_message_t state) | ||
279 | { | ||
280 | flush_scheduled_work(); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static 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 | |||
296 | static const struct i2c_device_id z2_batt_id[] = { | ||
297 | { "aer915", 0 }, | ||
298 | { } | ||
299 | }; | ||
300 | |||
301 | static 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 | |||
313 | static int __init z2_batt_init(void) | ||
314 | { | ||
315 | return i2c_add_driver(&z2_batt_driver); | ||
316 | } | ||
317 | |||
318 | static void __exit z2_batt_exit(void) | ||
319 | { | ||
320 | i2c_del_driver(&z2_batt_driver); | ||
321 | } | ||
322 | |||
323 | module_init(z2_batt_init); | ||
324 | module_exit(z2_batt_exit); | ||
325 | |||
326 | MODULE_LICENSE("GPL"); | ||
327 | MODULE_AUTHOR("Peter Edwards <sweetlilmre@gmail.com>"); | ||
328 | MODULE_DESCRIPTION("Zipit Z2 battery driver"); | ||