diff options
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/Kconfig | 16 | ||||
-rw-r--r-- | drivers/power/Makefile | 2 | ||||
-rw-r--r-- | drivers/power/bq27x00_battery.c | 11 | ||||
-rw-r--r-- | drivers/power/ds2760_battery.c | 6 | ||||
-rw-r--r-- | drivers/power/ds2780_battery.c | 853 | ||||
-rw-r--r-- | drivers/power/gpio-charger.c | 15 | ||||
-rw-r--r-- | drivers/power/isp1704_charger.c | 22 | ||||
-rw-r--r-- | drivers/power/max8903_charger.c | 391 | ||||
-rw-r--r-- | drivers/power/test_power.c | 276 | ||||
-rw-r--r-- | drivers/power/z2_battery.c | 20 |
10 files changed, 1590 insertions, 22 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 52a462fc6b84..e57b50b38565 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
@@ -68,6 +68,13 @@ config BATTERY_DS2760 | |||
68 | help | 68 | help |
69 | Say Y here to enable support for batteries with ds2760 chip. | 69 | Say Y here to enable support for batteries with ds2760 chip. |
70 | 70 | ||
71 | config BATTERY_DS2780 | ||
72 | tristate "DS2780 battery driver" | ||
73 | select W1 | ||
74 | select W1_SLAVE_DS2780 | ||
75 | help | ||
76 | Say Y here to enable support for batteries with ds2780 chip. | ||
77 | |||
71 | config BATTERY_DS2782 | 78 | config BATTERY_DS2782 |
72 | tristate "DS2782/DS2786 standalone gas-gauge" | 79 | tristate "DS2782/DS2786 standalone gas-gauge" |
73 | depends on I2C | 80 | depends on I2C |
@@ -203,6 +210,15 @@ config CHARGER_ISP1704 | |||
203 | Say Y to enable support for USB Charger Detection with | 210 | Say Y to enable support for USB Charger Detection with |
204 | ISP1707/ISP1704 USB transceivers. | 211 | ISP1707/ISP1704 USB transceivers. |
205 | 212 | ||
213 | config CHARGER_MAX8903 | ||
214 | tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power" | ||
215 | depends on GENERIC_HARDIRQS | ||
216 | help | ||
217 | Say Y to enable support for the MAX8903 DC-DC charger and sysfs. | ||
218 | The driver supports controlling charger-enable and current-limit | ||
219 | pins based on the status of charger connections with interrupt | ||
220 | handlers. | ||
221 | |||
206 | config CHARGER_TWL4030 | 222 | config CHARGER_TWL4030 |
207 | tristate "OMAP TWL4030 BCI charger driver" | 223 | tristate "OMAP TWL4030 BCI charger driver" |
208 | depends on TWL4030_CORE | 224 | depends on TWL4030_CORE |
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 8385bfae8728..009a90fa8ac9 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
@@ -15,6 +15,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o | |||
15 | obj-$(CONFIG_TEST_POWER) += test_power.o | 15 | obj-$(CONFIG_TEST_POWER) += test_power.o |
16 | 16 | ||
17 | obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o | 17 | obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o |
18 | obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o | ||
18 | obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o | 19 | obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o |
19 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o | 20 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o |
20 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | 21 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o |
@@ -32,5 +33,6 @@ obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o | |||
32 | obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o | 33 | obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o |
33 | obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o | 34 | obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o |
34 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o | 35 | obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o |
36 | obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o | ||
35 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o | 37 | obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o |
36 | obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o | 38 | obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o |
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 59e68dbd028b..bb16f5b7e167 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> | 4 | * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> |
5 | * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it> | 5 | * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it> |
6 | * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de> | 6 | * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de> |
7 | * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com> | ||
7 | * | 8 | * |
8 | * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. | 9 | * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. |
9 | * | 10 | * |
@@ -76,7 +77,7 @@ struct bq27x00_reg_cache { | |||
76 | int time_to_empty_avg; | 77 | int time_to_empty_avg; |
77 | int time_to_full; | 78 | int time_to_full; |
78 | int charge_full; | 79 | int charge_full; |
79 | int charge_counter; | 80 | int cycle_count; |
80 | int capacity; | 81 | int capacity; |
81 | int flags; | 82 | int flags; |
82 | 83 | ||
@@ -115,7 +116,7 @@ static enum power_supply_property bq27x00_battery_props[] = { | |||
115 | POWER_SUPPLY_PROP_CHARGE_FULL, | 116 | POWER_SUPPLY_PROP_CHARGE_FULL, |
116 | POWER_SUPPLY_PROP_CHARGE_NOW, | 117 | POWER_SUPPLY_PROP_CHARGE_NOW, |
117 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | 118 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, |
118 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | 119 | POWER_SUPPLY_PROP_CYCLE_COUNT, |
119 | POWER_SUPPLY_PROP_ENERGY_NOW, | 120 | POWER_SUPPLY_PROP_ENERGY_NOW, |
120 | }; | 121 | }; |
121 | 122 | ||
@@ -267,7 +268,7 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
267 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | 268 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); |
268 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | 269 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); |
269 | cache.charge_full = bq27x00_battery_read_lmd(di); | 270 | cache.charge_full = bq27x00_battery_read_lmd(di); |
270 | cache.charge_counter = bq27x00_battery_read_cyct(di); | 271 | cache.cycle_count = bq27x00_battery_read_cyct(di); |
271 | 272 | ||
272 | if (!is_bq27500) | 273 | if (!is_bq27500) |
273 | cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); | 274 | cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); |
@@ -496,8 +497,8 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
496 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | 497 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: |
497 | ret = bq27x00_simple_value(di->charge_design_full, val); | 498 | ret = bq27x00_simple_value(di->charge_design_full, val); |
498 | break; | 499 | break; |
499 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | 500 | case POWER_SUPPLY_PROP_CYCLE_COUNT: |
500 | ret = bq27x00_simple_value(di->cache.charge_counter, val); | 501 | ret = bq27x00_simple_value(di->cache.cycle_count, val); |
501 | break; | 502 | break; |
502 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 503 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
503 | ret = bq27x00_battery_energy(di, val); | 504 | ret = bq27x00_battery_energy(di, val); |
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index e534290f3256..f2c9cc33c0f9 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c | |||
@@ -86,7 +86,11 @@ static int rated_capacities[] = { | |||
86 | 920, /* NEC */ | 86 | 920, /* NEC */ |
87 | 1440, /* Samsung */ | 87 | 1440, /* Samsung */ |
88 | 1440, /* BYD */ | 88 | 1440, /* BYD */ |
89 | #ifdef CONFIG_MACH_H4700 | ||
90 | 1800, /* HP iPAQ hx4700 3.7V 1800mAh (359113-001) */ | ||
91 | #else | ||
89 | 1440, /* Lishen */ | 92 | 1440, /* Lishen */ |
93 | #endif | ||
90 | 1440, /* NEC */ | 94 | 1440, /* NEC */ |
91 | 2880, /* Samsung */ | 95 | 2880, /* Samsung */ |
92 | 2880, /* BYD */ | 96 | 2880, /* BYD */ |
@@ -186,7 +190,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di) | |||
186 | 190 | ||
187 | scale[0] = di->full_active_uAh; | 191 | scale[0] = di->full_active_uAh; |
188 | for (i = 1; i < 5; i++) | 192 | for (i = 1; i < 5; i++) |
189 | scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i]; | 193 | scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 1 + i]; |
190 | 194 | ||
191 | di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10); | 195 | di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10); |
192 | di->full_active_uAh *= 1000; /* convert to µAh */ | 196 | di->full_active_uAh *= 1000; /* convert to µAh */ |
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c new file mode 100644 index 000000000000..1fefe82e12e3 --- /dev/null +++ b/drivers/power/ds2780_battery.c | |||
@@ -0,0 +1,853 @@ | |||
1 | /* | ||
2 | * 1-wire client/driver for the Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC | ||
3 | * | ||
4 | * Copyright (C) 2010 Indesign, LLC | ||
5 | * | ||
6 | * Author: Clifton Barnes <cabarnes@indesign-llc.com> | ||
7 | * | ||
8 | * Based on ds2760_battery and ds2782_battery drivers | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/param.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/power_supply.h> | ||
22 | #include <linux/idr.h> | ||
23 | |||
24 | #include "../w1/w1.h" | ||
25 | #include "../w1/slaves/w1_ds2780.h" | ||
26 | |||
27 | /* Current unit measurement in uA for a 1 milli-ohm sense resistor */ | ||
28 | #define DS2780_CURRENT_UNITS 1563 | ||
29 | /* Charge unit measurement in uAh for a 1 milli-ohm sense resistor */ | ||
30 | #define DS2780_CHARGE_UNITS 6250 | ||
31 | /* Number of bytes in user EEPROM space */ | ||
32 | #define DS2780_USER_EEPROM_SIZE (DS2780_EEPROM_BLOCK0_END - \ | ||
33 | DS2780_EEPROM_BLOCK0_START + 1) | ||
34 | /* Number of bytes in parameter EEPROM space */ | ||
35 | #define DS2780_PARAM_EEPROM_SIZE (DS2780_EEPROM_BLOCK1_END - \ | ||
36 | DS2780_EEPROM_BLOCK1_START + 1) | ||
37 | |||
38 | struct ds2780_device_info { | ||
39 | struct device *dev; | ||
40 | struct power_supply bat; | ||
41 | struct device *w1_dev; | ||
42 | }; | ||
43 | |||
44 | enum current_types { | ||
45 | CURRENT_NOW, | ||
46 | CURRENT_AVG, | ||
47 | }; | ||
48 | |||
49 | static const char model[] = "DS2780"; | ||
50 | static const char manufacturer[] = "Maxim/Dallas"; | ||
51 | |||
52 | static inline struct ds2780_device_info *to_ds2780_device_info( | ||
53 | struct power_supply *psy) | ||
54 | { | ||
55 | return container_of(psy, struct ds2780_device_info, bat); | ||
56 | } | ||
57 | |||
58 | static inline struct power_supply *to_power_supply(struct device *dev) | ||
59 | { | ||
60 | return dev_get_drvdata(dev); | ||
61 | } | ||
62 | |||
63 | static inline int ds2780_read8(struct device *dev, u8 *val, int addr) | ||
64 | { | ||
65 | return w1_ds2780_io(dev, val, addr, sizeof(u8), 0); | ||
66 | } | ||
67 | |||
68 | static int ds2780_read16(struct device *dev, s16 *val, int addr) | ||
69 | { | ||
70 | int ret; | ||
71 | u8 raw[2]; | ||
72 | |||
73 | ret = w1_ds2780_io(dev, raw, addr, sizeof(u8) * 2, 0); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | |||
77 | *val = (raw[0] << 8) | raw[1]; | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static inline int ds2780_read_block(struct device *dev, u8 *val, int addr, | ||
83 | size_t count) | ||
84 | { | ||
85 | return w1_ds2780_io(dev, val, addr, count, 0); | ||
86 | } | ||
87 | |||
88 | static inline int ds2780_write(struct device *dev, u8 *val, int addr, | ||
89 | size_t count) | ||
90 | { | ||
91 | return w1_ds2780_io(dev, val, addr, count, 1); | ||
92 | } | ||
93 | |||
94 | static inline int ds2780_store_eeprom(struct device *dev, int addr) | ||
95 | { | ||
96 | return w1_ds2780_eeprom_cmd(dev, addr, W1_DS2780_COPY_DATA); | ||
97 | } | ||
98 | |||
99 | static inline int ds2780_recall_eeprom(struct device *dev, int addr) | ||
100 | { | ||
101 | return w1_ds2780_eeprom_cmd(dev, addr, W1_DS2780_RECALL_DATA); | ||
102 | } | ||
103 | |||
104 | static int ds2780_save_eeprom(struct ds2780_device_info *dev_info, int reg) | ||
105 | { | ||
106 | int ret; | ||
107 | |||
108 | ret = ds2780_store_eeprom(dev_info->w1_dev, reg); | ||
109 | if (ret < 0) | ||
110 | return ret; | ||
111 | |||
112 | ret = ds2780_recall_eeprom(dev_info->w1_dev, reg); | ||
113 | if (ret < 0) | ||
114 | return ret; | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | /* Set sense resistor value in mhos */ | ||
120 | static int ds2780_set_sense_register(struct ds2780_device_info *dev_info, | ||
121 | u8 conductance) | ||
122 | { | ||
123 | int ret; | ||
124 | |||
125 | ret = ds2780_write(dev_info->w1_dev, &conductance, | ||
126 | DS2780_RSNSP_REG, sizeof(u8)); | ||
127 | if (ret < 0) | ||
128 | return ret; | ||
129 | |||
130 | return ds2780_save_eeprom(dev_info, DS2780_RSNSP_REG); | ||
131 | } | ||
132 | |||
133 | /* Get RSGAIN value from 0 to 1.999 in steps of 0.001 */ | ||
134 | static int ds2780_get_rsgain_register(struct ds2780_device_info *dev_info, | ||
135 | u16 *rsgain) | ||
136 | { | ||
137 | return ds2780_read16(dev_info->w1_dev, rsgain, DS2780_RSGAIN_MSB_REG); | ||
138 | } | ||
139 | |||
140 | /* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */ | ||
141 | static int ds2780_set_rsgain_register(struct ds2780_device_info *dev_info, | ||
142 | u16 rsgain) | ||
143 | { | ||
144 | int ret; | ||
145 | u8 raw[] = {rsgain >> 8, rsgain & 0xFF}; | ||
146 | |||
147 | ret = ds2780_write(dev_info->w1_dev, raw, | ||
148 | DS2780_RSGAIN_MSB_REG, sizeof(u8) * 2); | ||
149 | if (ret < 0) | ||
150 | return ret; | ||
151 | |||
152 | return ds2780_save_eeprom(dev_info, DS2780_RSGAIN_MSB_REG); | ||
153 | } | ||
154 | |||
155 | static int ds2780_get_voltage(struct ds2780_device_info *dev_info, | ||
156 | int *voltage_uV) | ||
157 | { | ||
158 | int ret; | ||
159 | s16 voltage_raw; | ||
160 | |||
161 | /* | ||
162 | * The voltage value is located in 10 bits across the voltage MSB | ||
163 | * and LSB registers in two's compliment form | ||
164 | * Sign bit of the voltage value is in bit 7 of the voltage MSB register | ||
165 | * Bits 9 - 3 of the voltage value are in bits 6 - 0 of the | ||
166 | * voltage MSB register | ||
167 | * Bits 2 - 0 of the voltage value are in bits 7 - 5 of the | ||
168 | * voltage LSB register | ||
169 | */ | ||
170 | ret = ds2780_read16(dev_info->w1_dev, &voltage_raw, | ||
171 | DS2780_VOLT_MSB_REG); | ||
172 | if (ret < 0) | ||
173 | return ret; | ||
174 | |||
175 | /* | ||
176 | * DS2780 reports voltage in units of 4.88mV, but the battery class | ||
177 | * reports in units of uV, so convert by multiplying by 4880. | ||
178 | */ | ||
179 | *voltage_uV = (voltage_raw / 32) * 4880; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int ds2780_get_temperature(struct ds2780_device_info *dev_info, | ||
184 | int *temperature) | ||
185 | { | ||
186 | int ret; | ||
187 | s16 temperature_raw; | ||
188 | |||
189 | /* | ||
190 | * The temperature value is located in 10 bits across the temperature | ||
191 | * MSB and LSB registers in two's compliment form | ||
192 | * Sign bit of the temperature value is in bit 7 of the temperature | ||
193 | * MSB register | ||
194 | * Bits 9 - 3 of the temperature value are in bits 6 - 0 of the | ||
195 | * temperature MSB register | ||
196 | * Bits 2 - 0 of the temperature value are in bits 7 - 5 of the | ||
197 | * temperature LSB register | ||
198 | */ | ||
199 | ret = ds2780_read16(dev_info->w1_dev, &temperature_raw, | ||
200 | DS2780_TEMP_MSB_REG); | ||
201 | if (ret < 0) | ||
202 | return ret; | ||
203 | |||
204 | /* | ||
205 | * Temperature is measured in units of 0.125 degrees celcius, the | ||
206 | * power_supply class measures temperature in tenths of degrees | ||
207 | * celsius. The temperature value is stored as a 10 bit number, plus | ||
208 | * sign in the upper bits of a 16 bit register. | ||
209 | */ | ||
210 | *temperature = ((temperature_raw / 32) * 125) / 100; | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int ds2780_get_current(struct ds2780_device_info *dev_info, | ||
215 | enum current_types type, int *current_uA) | ||
216 | { | ||
217 | int ret, sense_res; | ||
218 | s16 current_raw; | ||
219 | u8 sense_res_raw, reg_msb; | ||
220 | |||
221 | /* | ||
222 | * The units of measurement for current are dependent on the value of | ||
223 | * the sense resistor. | ||
224 | */ | ||
225 | ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG); | ||
226 | if (ret < 0) | ||
227 | return ret; | ||
228 | |||
229 | if (sense_res_raw == 0) { | ||
230 | dev_err(dev_info->dev, "sense resistor value is 0\n"); | ||
231 | return -ENXIO; | ||
232 | } | ||
233 | sense_res = 1000 / sense_res_raw; | ||
234 | |||
235 | if (type == CURRENT_NOW) | ||
236 | reg_msb = DS2780_CURRENT_MSB_REG; | ||
237 | else if (type == CURRENT_AVG) | ||
238 | reg_msb = DS2780_IAVG_MSB_REG; | ||
239 | else | ||
240 | return -EINVAL; | ||
241 | |||
242 | /* | ||
243 | * The current value is located in 16 bits across the current MSB | ||
244 | * and LSB registers in two's compliment form | ||
245 | * Sign bit of the current value is in bit 7 of the current MSB register | ||
246 | * Bits 14 - 8 of the current value are in bits 6 - 0 of the current | ||
247 | * MSB register | ||
248 | * Bits 7 - 0 of the current value are in bits 7 - 0 of the current | ||
249 | * LSB register | ||
250 | */ | ||
251 | ret = ds2780_read16(dev_info->w1_dev, ¤t_raw, reg_msb); | ||
252 | if (ret < 0) | ||
253 | return ret; | ||
254 | |||
255 | *current_uA = current_raw * (DS2780_CURRENT_UNITS / sense_res); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info, | ||
260 | int *accumulated_current) | ||
261 | { | ||
262 | int ret, sense_res; | ||
263 | s16 current_raw; | ||
264 | u8 sense_res_raw; | ||
265 | |||
266 | /* | ||
267 | * The units of measurement for accumulated current are dependent on | ||
268 | * the value of the sense resistor. | ||
269 | */ | ||
270 | ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG); | ||
271 | if (ret < 0) | ||
272 | return ret; | ||
273 | |||
274 | if (sense_res_raw == 0) { | ||
275 | dev_err(dev_info->dev, "sense resistor value is 0\n"); | ||
276 | return -ENXIO; | ||
277 | } | ||
278 | sense_res = 1000 / sense_res_raw; | ||
279 | |||
280 | /* | ||
281 | * The ACR value is located in 16 bits across the ACR MSB and | ||
282 | * LSB registers | ||
283 | * Bits 15 - 8 of the ACR value are in bits 7 - 0 of the ACR | ||
284 | * MSB register | ||
285 | * Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR | ||
286 | * LSB register | ||
287 | */ | ||
288 | ret = ds2780_read16(dev_info->w1_dev, ¤t_raw, DS2780_ACR_MSB_REG); | ||
289 | if (ret < 0) | ||
290 | return ret; | ||
291 | |||
292 | *accumulated_current = current_raw * (DS2780_CHARGE_UNITS / sense_res); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int ds2780_get_capacity(struct ds2780_device_info *dev_info, | ||
297 | int *capacity) | ||
298 | { | ||
299 | int ret; | ||
300 | u8 raw; | ||
301 | |||
302 | ret = ds2780_read8(dev_info->w1_dev, &raw, DS2780_RARC_REG); | ||
303 | if (ret < 0) | ||
304 | return ret; | ||
305 | |||
306 | *capacity = raw; | ||
307 | return raw; | ||
308 | } | ||
309 | |||
310 | static int ds2780_get_status(struct ds2780_device_info *dev_info, int *status) | ||
311 | { | ||
312 | int ret, current_uA, capacity; | ||
313 | |||
314 | ret = ds2780_get_current(dev_info, CURRENT_NOW, ¤t_uA); | ||
315 | if (ret < 0) | ||
316 | return ret; | ||
317 | |||
318 | ret = ds2780_get_capacity(dev_info, &capacity); | ||
319 | if (ret < 0) | ||
320 | return ret; | ||
321 | |||
322 | if (capacity == 100) | ||
323 | *status = POWER_SUPPLY_STATUS_FULL; | ||
324 | else if (current_uA == 0) | ||
325 | *status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
326 | else if (current_uA < 0) | ||
327 | *status = POWER_SUPPLY_STATUS_DISCHARGING; | ||
328 | else | ||
329 | *status = POWER_SUPPLY_STATUS_CHARGING; | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int ds2780_get_charge_now(struct ds2780_device_info *dev_info, | ||
335 | int *charge_now) | ||
336 | { | ||
337 | int ret; | ||
338 | u16 charge_raw; | ||
339 | |||
340 | /* | ||
341 | * The RAAC value is located in 16 bits across the RAAC MSB and | ||
342 | * LSB registers | ||
343 | * Bits 15 - 8 of the RAAC value are in bits 7 - 0 of the RAAC | ||
344 | * MSB register | ||
345 | * Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC | ||
346 | * LSB register | ||
347 | */ | ||
348 | ret = ds2780_read16(dev_info->w1_dev, &charge_raw, DS2780_RAAC_MSB_REG); | ||
349 | if (ret < 0) | ||
350 | return ret; | ||
351 | |||
352 | *charge_now = charge_raw * 1600; | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int ds2780_get_control_register(struct ds2780_device_info *dev_info, | ||
357 | u8 *control_reg) | ||
358 | { | ||
359 | return ds2780_read8(dev_info->w1_dev, control_reg, DS2780_CONTROL_REG); | ||
360 | } | ||
361 | |||
362 | static int ds2780_set_control_register(struct ds2780_device_info *dev_info, | ||
363 | u8 control_reg) | ||
364 | { | ||
365 | int ret; | ||
366 | |||
367 | ret = ds2780_write(dev_info->w1_dev, &control_reg, | ||
368 | DS2780_CONTROL_REG, sizeof(u8)); | ||
369 | if (ret < 0) | ||
370 | return ret; | ||
371 | |||
372 | return ds2780_save_eeprom(dev_info, DS2780_CONTROL_REG); | ||
373 | } | ||
374 | |||
375 | static int ds2780_battery_get_property(struct power_supply *psy, | ||
376 | enum power_supply_property psp, | ||
377 | union power_supply_propval *val) | ||
378 | { | ||
379 | int ret = 0; | ||
380 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
381 | |||
382 | switch (psp) { | ||
383 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
384 | ret = ds2780_get_voltage(dev_info, &val->intval); | ||
385 | break; | ||
386 | |||
387 | case POWER_SUPPLY_PROP_TEMP: | ||
388 | ret = ds2780_get_temperature(dev_info, &val->intval); | ||
389 | break; | ||
390 | |||
391 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
392 | val->strval = model; | ||
393 | break; | ||
394 | |||
395 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
396 | val->strval = manufacturer; | ||
397 | break; | ||
398 | |||
399 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
400 | ret = ds2780_get_current(dev_info, CURRENT_NOW, &val->intval); | ||
401 | break; | ||
402 | |||
403 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
404 | ret = ds2780_get_current(dev_info, CURRENT_AVG, &val->intval); | ||
405 | break; | ||
406 | |||
407 | case POWER_SUPPLY_PROP_STATUS: | ||
408 | ret = ds2780_get_status(dev_info, &val->intval); | ||
409 | break; | ||
410 | |||
411 | case POWER_SUPPLY_PROP_CAPACITY: | ||
412 | ret = ds2780_get_capacity(dev_info, &val->intval); | ||
413 | break; | ||
414 | |||
415 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | ||
416 | ret = ds2780_get_accumulated_current(dev_info, &val->intval); | ||
417 | break; | ||
418 | |||
419 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
420 | ret = ds2780_get_charge_now(dev_info, &val->intval); | ||
421 | break; | ||
422 | |||
423 | default: | ||
424 | ret = -EINVAL; | ||
425 | } | ||
426 | |||
427 | return ret; | ||
428 | } | ||
429 | |||
430 | static enum power_supply_property ds2780_battery_props[] = { | ||
431 | POWER_SUPPLY_PROP_STATUS, | ||
432 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
433 | POWER_SUPPLY_PROP_TEMP, | ||
434 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
435 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
436 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
437 | POWER_SUPPLY_PROP_CURRENT_AVG, | ||
438 | POWER_SUPPLY_PROP_CAPACITY, | ||
439 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | ||
440 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
441 | }; | ||
442 | |||
443 | static ssize_t ds2780_get_pmod_enabled(struct device *dev, | ||
444 | struct device_attribute *attr, | ||
445 | char *buf) | ||
446 | { | ||
447 | int ret; | ||
448 | u8 control_reg; | ||
449 | struct power_supply *psy = to_power_supply(dev); | ||
450 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
451 | |||
452 | /* Get power mode */ | ||
453 | ret = ds2780_get_control_register(dev_info, &control_reg); | ||
454 | if (ret < 0) | ||
455 | return ret; | ||
456 | |||
457 | return sprintf(buf, "%d\n", | ||
458 | !!(control_reg & DS2780_CONTROL_REG_PMOD)); | ||
459 | } | ||
460 | |||
461 | static ssize_t ds2780_set_pmod_enabled(struct device *dev, | ||
462 | struct device_attribute *attr, | ||
463 | const char *buf, | ||
464 | size_t count) | ||
465 | { | ||
466 | int ret; | ||
467 | u8 control_reg, new_setting; | ||
468 | struct power_supply *psy = to_power_supply(dev); | ||
469 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
470 | |||
471 | /* Set power mode */ | ||
472 | ret = ds2780_get_control_register(dev_info, &control_reg); | ||
473 | if (ret < 0) | ||
474 | return ret; | ||
475 | |||
476 | ret = kstrtou8(buf, 0, &new_setting); | ||
477 | if (ret < 0) | ||
478 | return ret; | ||
479 | |||
480 | if ((new_setting != 0) && (new_setting != 1)) { | ||
481 | dev_err(dev_info->dev, "Invalid pmod setting (0 or 1)\n"); | ||
482 | return -EINVAL; | ||
483 | } | ||
484 | |||
485 | if (new_setting) | ||
486 | control_reg |= DS2780_CONTROL_REG_PMOD; | ||
487 | else | ||
488 | control_reg &= ~DS2780_CONTROL_REG_PMOD; | ||
489 | |||
490 | ret = ds2780_set_control_register(dev_info, control_reg); | ||
491 | if (ret < 0) | ||
492 | return ret; | ||
493 | |||
494 | return count; | ||
495 | } | ||
496 | |||
497 | static ssize_t ds2780_get_sense_resistor_value(struct device *dev, | ||
498 | struct device_attribute *attr, | ||
499 | char *buf) | ||
500 | { | ||
501 | int ret; | ||
502 | u8 sense_resistor; | ||
503 | struct power_supply *psy = to_power_supply(dev); | ||
504 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
505 | |||
506 | ret = ds2780_read8(dev_info->w1_dev, &sense_resistor, DS2780_RSNSP_REG); | ||
507 | if (ret < 0) | ||
508 | return ret; | ||
509 | |||
510 | ret = sprintf(buf, "%d\n", sense_resistor); | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | static ssize_t ds2780_set_sense_resistor_value(struct device *dev, | ||
515 | struct device_attribute *attr, | ||
516 | const char *buf, | ||
517 | size_t count) | ||
518 | { | ||
519 | int ret; | ||
520 | u8 new_setting; | ||
521 | struct power_supply *psy = to_power_supply(dev); | ||
522 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
523 | |||
524 | ret = kstrtou8(buf, 0, &new_setting); | ||
525 | if (ret < 0) | ||
526 | return ret; | ||
527 | |||
528 | ret = ds2780_set_sense_register(dev_info, new_setting); | ||
529 | if (ret < 0) | ||
530 | return ret; | ||
531 | |||
532 | return count; | ||
533 | } | ||
534 | |||
535 | static ssize_t ds2780_get_rsgain_setting(struct device *dev, | ||
536 | struct device_attribute *attr, | ||
537 | char *buf) | ||
538 | { | ||
539 | int ret; | ||
540 | u16 rsgain; | ||
541 | struct power_supply *psy = to_power_supply(dev); | ||
542 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
543 | |||
544 | ret = ds2780_get_rsgain_register(dev_info, &rsgain); | ||
545 | if (ret < 0) | ||
546 | return ret; | ||
547 | |||
548 | return sprintf(buf, "%d\n", rsgain); | ||
549 | } | ||
550 | |||
551 | static ssize_t ds2780_set_rsgain_setting(struct device *dev, | ||
552 | struct device_attribute *attr, | ||
553 | const char *buf, | ||
554 | size_t count) | ||
555 | { | ||
556 | int ret; | ||
557 | u16 new_setting; | ||
558 | struct power_supply *psy = to_power_supply(dev); | ||
559 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
560 | |||
561 | ret = kstrtou16(buf, 0, &new_setting); | ||
562 | if (ret < 0) | ||
563 | return ret; | ||
564 | |||
565 | /* Gain can only be from 0 to 1.999 in steps of .001 */ | ||
566 | if (new_setting > 1999) { | ||
567 | dev_err(dev_info->dev, "Invalid rsgain setting (0 - 1999)\n"); | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | |||
571 | ret = ds2780_set_rsgain_register(dev_info, new_setting); | ||
572 | if (ret < 0) | ||
573 | return ret; | ||
574 | |||
575 | return count; | ||
576 | } | ||
577 | |||
578 | static ssize_t ds2780_get_pio_pin(struct device *dev, | ||
579 | struct device_attribute *attr, | ||
580 | char *buf) | ||
581 | { | ||
582 | int ret; | ||
583 | u8 sfr; | ||
584 | struct power_supply *psy = to_power_supply(dev); | ||
585 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
586 | |||
587 | ret = ds2780_read8(dev_info->w1_dev, &sfr, DS2780_SFR_REG); | ||
588 | if (ret < 0) | ||
589 | return ret; | ||
590 | |||
591 | ret = sprintf(buf, "%d\n", sfr & DS2780_SFR_REG_PIOSC); | ||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | static ssize_t ds2780_set_pio_pin(struct device *dev, | ||
596 | struct device_attribute *attr, | ||
597 | const char *buf, | ||
598 | size_t count) | ||
599 | { | ||
600 | int ret; | ||
601 | u8 new_setting; | ||
602 | struct power_supply *psy = to_power_supply(dev); | ||
603 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
604 | |||
605 | ret = kstrtou8(buf, 0, &new_setting); | ||
606 | if (ret < 0) | ||
607 | return ret; | ||
608 | |||
609 | if ((new_setting != 0) && (new_setting != 1)) { | ||
610 | dev_err(dev_info->dev, "Invalid pio_pin setting (0 or 1)\n"); | ||
611 | return -EINVAL; | ||
612 | } | ||
613 | |||
614 | ret = ds2780_write(dev_info->w1_dev, &new_setting, | ||
615 | DS2780_SFR_REG, sizeof(u8)); | ||
616 | if (ret < 0) | ||
617 | return ret; | ||
618 | |||
619 | return count; | ||
620 | } | ||
621 | |||
622 | static ssize_t ds2780_read_param_eeprom_bin(struct file *filp, | ||
623 | struct kobject *kobj, | ||
624 | struct bin_attribute *bin_attr, | ||
625 | char *buf, loff_t off, size_t count) | ||
626 | { | ||
627 | struct device *dev = container_of(kobj, struct device, kobj); | ||
628 | struct power_supply *psy = to_power_supply(dev); | ||
629 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
630 | |||
631 | count = min_t(loff_t, count, | ||
632 | DS2780_EEPROM_BLOCK1_END - | ||
633 | DS2780_EEPROM_BLOCK1_START + 1 - off); | ||
634 | |||
635 | return ds2780_read_block(dev_info->w1_dev, buf, | ||
636 | DS2780_EEPROM_BLOCK1_START + off, count); | ||
637 | } | ||
638 | |||
639 | static ssize_t ds2780_write_param_eeprom_bin(struct file *filp, | ||
640 | struct kobject *kobj, | ||
641 | struct bin_attribute *bin_attr, | ||
642 | char *buf, loff_t off, size_t count) | ||
643 | { | ||
644 | struct device *dev = container_of(kobj, struct device, kobj); | ||
645 | struct power_supply *psy = to_power_supply(dev); | ||
646 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
647 | int ret; | ||
648 | |||
649 | count = min_t(loff_t, count, | ||
650 | DS2780_EEPROM_BLOCK1_END - | ||
651 | DS2780_EEPROM_BLOCK1_START + 1 - off); | ||
652 | |||
653 | ret = ds2780_write(dev_info->w1_dev, buf, | ||
654 | DS2780_EEPROM_BLOCK1_START + off, count); | ||
655 | if (ret < 0) | ||
656 | return ret; | ||
657 | |||
658 | ret = ds2780_save_eeprom(dev_info, DS2780_EEPROM_BLOCK1_START); | ||
659 | if (ret < 0) | ||
660 | return ret; | ||
661 | |||
662 | return count; | ||
663 | } | ||
664 | |||
665 | static struct bin_attribute ds2780_param_eeprom_bin_attr = { | ||
666 | .attr = { | ||
667 | .name = "param_eeprom", | ||
668 | .mode = S_IRUGO | S_IWUSR, | ||
669 | }, | ||
670 | .size = DS2780_EEPROM_BLOCK1_END - DS2780_EEPROM_BLOCK1_START + 1, | ||
671 | .read = ds2780_read_param_eeprom_bin, | ||
672 | .write = ds2780_write_param_eeprom_bin, | ||
673 | }; | ||
674 | |||
675 | static ssize_t ds2780_read_user_eeprom_bin(struct file *filp, | ||
676 | struct kobject *kobj, | ||
677 | struct bin_attribute *bin_attr, | ||
678 | char *buf, loff_t off, size_t count) | ||
679 | { | ||
680 | struct device *dev = container_of(kobj, struct device, kobj); | ||
681 | struct power_supply *psy = to_power_supply(dev); | ||
682 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
683 | |||
684 | count = min_t(loff_t, count, | ||
685 | DS2780_EEPROM_BLOCK0_END - | ||
686 | DS2780_EEPROM_BLOCK0_START + 1 - off); | ||
687 | |||
688 | return ds2780_read_block(dev_info->w1_dev, buf, | ||
689 | DS2780_EEPROM_BLOCK0_START + off, count); | ||
690 | |||
691 | } | ||
692 | |||
693 | static ssize_t ds2780_write_user_eeprom_bin(struct file *filp, | ||
694 | struct kobject *kobj, | ||
695 | struct bin_attribute *bin_attr, | ||
696 | char *buf, loff_t off, size_t count) | ||
697 | { | ||
698 | struct device *dev = container_of(kobj, struct device, kobj); | ||
699 | struct power_supply *psy = to_power_supply(dev); | ||
700 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); | ||
701 | int ret; | ||
702 | |||
703 | count = min_t(loff_t, count, | ||
704 | DS2780_EEPROM_BLOCK0_END - | ||
705 | DS2780_EEPROM_BLOCK0_START + 1 - off); | ||
706 | |||
707 | ret = ds2780_write(dev_info->w1_dev, buf, | ||
708 | DS2780_EEPROM_BLOCK0_START + off, count); | ||
709 | if (ret < 0) | ||
710 | return ret; | ||
711 | |||
712 | ret = ds2780_save_eeprom(dev_info, DS2780_EEPROM_BLOCK0_START); | ||
713 | if (ret < 0) | ||
714 | return ret; | ||
715 | |||
716 | return count; | ||
717 | } | ||
718 | |||
719 | static struct bin_attribute ds2780_user_eeprom_bin_attr = { | ||
720 | .attr = { | ||
721 | .name = "user_eeprom", | ||
722 | .mode = S_IRUGO | S_IWUSR, | ||
723 | }, | ||
724 | .size = DS2780_EEPROM_BLOCK0_END - DS2780_EEPROM_BLOCK0_START + 1, | ||
725 | .read = ds2780_read_user_eeprom_bin, | ||
726 | .write = ds2780_write_user_eeprom_bin, | ||
727 | }; | ||
728 | |||
729 | static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2780_get_pmod_enabled, | ||
730 | ds2780_set_pmod_enabled); | ||
731 | static DEVICE_ATTR(sense_resistor_value, S_IRUGO | S_IWUSR, | ||
732 | ds2780_get_sense_resistor_value, ds2780_set_sense_resistor_value); | ||
733 | static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2780_get_rsgain_setting, | ||
734 | ds2780_set_rsgain_setting); | ||
735 | static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2780_get_pio_pin, | ||
736 | ds2780_set_pio_pin); | ||
737 | |||
738 | |||
739 | static struct attribute *ds2780_attributes[] = { | ||
740 | &dev_attr_pmod_enabled.attr, | ||
741 | &dev_attr_sense_resistor_value.attr, | ||
742 | &dev_attr_rsgain_setting.attr, | ||
743 | &dev_attr_pio_pin.attr, | ||
744 | NULL | ||
745 | }; | ||
746 | |||
747 | static const struct attribute_group ds2780_attr_group = { | ||
748 | .attrs = ds2780_attributes, | ||
749 | }; | ||
750 | |||
751 | static int __devinit ds2780_battery_probe(struct platform_device *pdev) | ||
752 | { | ||
753 | int ret = 0; | ||
754 | struct ds2780_device_info *dev_info; | ||
755 | |||
756 | dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); | ||
757 | if (!dev_info) { | ||
758 | ret = -ENOMEM; | ||
759 | goto fail; | ||
760 | } | ||
761 | |||
762 | platform_set_drvdata(pdev, dev_info); | ||
763 | |||
764 | dev_info->dev = &pdev->dev; | ||
765 | dev_info->w1_dev = pdev->dev.parent; | ||
766 | dev_info->bat.name = dev_name(&pdev->dev); | ||
767 | dev_info->bat.type = POWER_SUPPLY_TYPE_BATTERY; | ||
768 | dev_info->bat.properties = ds2780_battery_props; | ||
769 | dev_info->bat.num_properties = ARRAY_SIZE(ds2780_battery_props); | ||
770 | dev_info->bat.get_property = ds2780_battery_get_property; | ||
771 | |||
772 | ret = power_supply_register(&pdev->dev, &dev_info->bat); | ||
773 | if (ret) { | ||
774 | dev_err(dev_info->dev, "failed to register battery\n"); | ||
775 | goto fail_free_info; | ||
776 | } | ||
777 | |||
778 | ret = sysfs_create_group(&dev_info->bat.dev->kobj, &ds2780_attr_group); | ||
779 | if (ret) { | ||
780 | dev_err(dev_info->dev, "failed to create sysfs group\n"); | ||
781 | goto fail_unregister; | ||
782 | } | ||
783 | |||
784 | ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj, | ||
785 | &ds2780_param_eeprom_bin_attr); | ||
786 | if (ret) { | ||
787 | dev_err(dev_info->dev, | ||
788 | "failed to create param eeprom bin file"); | ||
789 | goto fail_remove_group; | ||
790 | } | ||
791 | |||
792 | ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj, | ||
793 | &ds2780_user_eeprom_bin_attr); | ||
794 | if (ret) { | ||
795 | dev_err(dev_info->dev, | ||
796 | "failed to create user eeprom bin file"); | ||
797 | goto fail_remove_bin_file; | ||
798 | } | ||
799 | |||
800 | return 0; | ||
801 | |||
802 | fail_remove_bin_file: | ||
803 | sysfs_remove_bin_file(&dev_info->bat.dev->kobj, | ||
804 | &ds2780_param_eeprom_bin_attr); | ||
805 | fail_remove_group: | ||
806 | sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group); | ||
807 | fail_unregister: | ||
808 | power_supply_unregister(&dev_info->bat); | ||
809 | fail_free_info: | ||
810 | kfree(dev_info); | ||
811 | fail: | ||
812 | return ret; | ||
813 | } | ||
814 | |||
815 | static int __devexit ds2780_battery_remove(struct platform_device *pdev) | ||
816 | { | ||
817 | struct ds2780_device_info *dev_info = platform_get_drvdata(pdev); | ||
818 | |||
819 | /* remove attributes */ | ||
820 | sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group); | ||
821 | |||
822 | power_supply_unregister(&dev_info->bat); | ||
823 | |||
824 | kfree(dev_info); | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | MODULE_ALIAS("platform:ds2780-battery"); | ||
829 | |||
830 | static struct platform_driver ds2780_battery_driver = { | ||
831 | .driver = { | ||
832 | .name = "ds2780-battery", | ||
833 | }, | ||
834 | .probe = ds2780_battery_probe, | ||
835 | .remove = ds2780_battery_remove, | ||
836 | }; | ||
837 | |||
838 | static int __init ds2780_battery_init(void) | ||
839 | { | ||
840 | return platform_driver_register(&ds2780_battery_driver); | ||
841 | } | ||
842 | |||
843 | static void __exit ds2780_battery_exit(void) | ||
844 | { | ||
845 | platform_driver_unregister(&ds2780_battery_driver); | ||
846 | } | ||
847 | |||
848 | module_init(ds2780_battery_init); | ||
849 | module_exit(ds2780_battery_exit); | ||
850 | |||
851 | MODULE_LICENSE("GPL"); | ||
852 | MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>"); | ||
853 | MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver"); | ||
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index 25b88ac1d44c..718f2c537827 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c | |||
@@ -161,12 +161,27 @@ static int __devexit gpio_charger_remove(struct platform_device *pdev) | |||
161 | return 0; | 161 | return 0; |
162 | } | 162 | } |
163 | 163 | ||
164 | #ifdef CONFIG_PM_SLEEP | ||
165 | static int gpio_charger_resume(struct device *dev) | ||
166 | { | ||
167 | struct platform_device *pdev = to_platform_device(dev); | ||
168 | struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); | ||
169 | |||
170 | power_supply_changed(&gpio_charger->charger); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | #endif | ||
175 | |||
176 | static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, NULL, gpio_charger_resume); | ||
177 | |||
164 | static struct platform_driver gpio_charger_driver = { | 178 | static struct platform_driver gpio_charger_driver = { |
165 | .probe = gpio_charger_probe, | 179 | .probe = gpio_charger_probe, |
166 | .remove = __devexit_p(gpio_charger_remove), | 180 | .remove = __devexit_p(gpio_charger_remove), |
167 | .driver = { | 181 | .driver = { |
168 | .name = "gpio-charger", | 182 | .name = "gpio-charger", |
169 | .owner = THIS_MODULE, | 183 | .owner = THIS_MODULE, |
184 | .pm = &gpio_charger_pm_ops, | ||
170 | }, | 185 | }, |
171 | }; | 186 | }; |
172 | 187 | ||
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 2ad9b14a5ce3..f6d72b402a8e 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/usb/ulpi.h> | 33 | #include <linux/usb/ulpi.h> |
34 | #include <linux/usb/ch9.h> | 34 | #include <linux/usb/ch9.h> |
35 | #include <linux/usb/gadget.h> | 35 | #include <linux/usb/gadget.h> |
36 | #include <linux/power/isp1704_charger.h> | ||
36 | 37 | ||
37 | /* Vendor specific Power Control register */ | 38 | /* Vendor specific Power Control register */ |
38 | #define ISP1704_PWR_CTRL 0x3d | 39 | #define ISP1704_PWR_CTRL 0x3d |
@@ -71,6 +72,18 @@ struct isp1704_charger { | |||
71 | }; | 72 | }; |
72 | 73 | ||
73 | /* | 74 | /* |
75 | * Disable/enable the power from the isp1704 if a function for it | ||
76 | * has been provided with platform data. | ||
77 | */ | ||
78 | static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on) | ||
79 | { | ||
80 | struct isp1704_charger_data *board = isp->dev->platform_data; | ||
81 | |||
82 | if (board->set_power) | ||
83 | board->set_power(on); | ||
84 | } | ||
85 | |||
86 | /* | ||
74 | * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB | 87 | * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB |
75 | * chargers). | 88 | * chargers). |
76 | * | 89 | * |
@@ -222,6 +235,9 @@ static void isp1704_charger_work(struct work_struct *data) | |||
222 | 235 | ||
223 | mutex_lock(&lock); | 236 | mutex_lock(&lock); |
224 | 237 | ||
238 | if (event != USB_EVENT_NONE) | ||
239 | isp1704_charger_set_power(isp, 1); | ||
240 | |||
225 | switch (event) { | 241 | switch (event) { |
226 | case USB_EVENT_VBUS: | 242 | case USB_EVENT_VBUS: |
227 | isp->online = true; | 243 | isp->online = true; |
@@ -269,6 +285,8 @@ static void isp1704_charger_work(struct work_struct *data) | |||
269 | */ | 285 | */ |
270 | if (isp->otg->gadget) | 286 | if (isp->otg->gadget) |
271 | usb_gadget_disconnect(isp->otg->gadget); | 287 | usb_gadget_disconnect(isp->otg->gadget); |
288 | |||
289 | isp1704_charger_set_power(isp, 0); | ||
272 | break; | 290 | break; |
273 | case USB_EVENT_ENUMERATED: | 291 | case USB_EVENT_ENUMERATED: |
274 | if (isp->present) | 292 | if (isp->present) |
@@ -394,6 +412,8 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev) | |||
394 | isp->dev = &pdev->dev; | 412 | isp->dev = &pdev->dev; |
395 | platform_set_drvdata(pdev, isp); | 413 | platform_set_drvdata(pdev, isp); |
396 | 414 | ||
415 | isp1704_charger_set_power(isp, 1); | ||
416 | |||
397 | ret = isp1704_test_ulpi(isp); | 417 | ret = isp1704_test_ulpi(isp); |
398 | if (ret < 0) | 418 | if (ret < 0) |
399 | goto fail1; | 419 | goto fail1; |
@@ -434,6 +454,7 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev) | |||
434 | 454 | ||
435 | /* Detect charger if VBUS is valid (the cable was already plugged). */ | 455 | /* Detect charger if VBUS is valid (the cable was already plugged). */ |
436 | ret = otg_io_read(isp->otg, ULPI_USB_INT_STS); | 456 | ret = otg_io_read(isp->otg, ULPI_USB_INT_STS); |
457 | isp1704_charger_set_power(isp, 0); | ||
437 | if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) { | 458 | if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) { |
438 | isp->event = USB_EVENT_VBUS; | 459 | isp->event = USB_EVENT_VBUS; |
439 | schedule_work(&isp->work); | 460 | schedule_work(&isp->work); |
@@ -459,6 +480,7 @@ static int __devexit isp1704_charger_remove(struct platform_device *pdev) | |||
459 | otg_unregister_notifier(isp->otg, &isp->nb); | 480 | otg_unregister_notifier(isp->otg, &isp->nb); |
460 | power_supply_unregister(&isp->psy); | 481 | power_supply_unregister(&isp->psy); |
461 | otg_put_transceiver(isp->otg); | 482 | otg_put_transceiver(isp->otg); |
483 | isp1704_charger_set_power(isp, 0); | ||
462 | kfree(isp); | 484 | kfree(isp); |
463 | 485 | ||
464 | return 0; | 486 | return 0; |
diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c new file mode 100644 index 000000000000..33ff0e37809e --- /dev/null +++ b/drivers/power/max8903_charger.c | |||
@@ -0,0 +1,391 @@ | |||
1 | /* | ||
2 | * max8903_charger.c - Maxim 8903 USB/Adapter Charger Driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics | ||
5 | * MyungJoo Ham <myungjoo.ham@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/gpio.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/power_supply.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/power/max8903_charger.h> | ||
29 | |||
30 | struct max8903_data { | ||
31 | struct max8903_pdata *pdata; | ||
32 | struct device *dev; | ||
33 | struct power_supply psy; | ||
34 | bool fault; | ||
35 | bool usb_in; | ||
36 | bool ta_in; | ||
37 | }; | ||
38 | |||
39 | static enum power_supply_property max8903_charger_props[] = { | ||
40 | POWER_SUPPLY_PROP_STATUS, /* Charger status output */ | ||
41 | POWER_SUPPLY_PROP_ONLINE, /* External power source */ | ||
42 | POWER_SUPPLY_PROP_HEALTH, /* Fault or OK */ | ||
43 | }; | ||
44 | |||
45 | static int max8903_get_property(struct power_supply *psy, | ||
46 | enum power_supply_property psp, | ||
47 | union power_supply_propval *val) | ||
48 | { | ||
49 | struct max8903_data *data = container_of(psy, | ||
50 | struct max8903_data, psy); | ||
51 | |||
52 | switch (psp) { | ||
53 | case POWER_SUPPLY_PROP_STATUS: | ||
54 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | ||
55 | if (data->pdata->chg) { | ||
56 | if (gpio_get_value(data->pdata->chg) == 0) | ||
57 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
58 | else if (data->usb_in || data->ta_in) | ||
59 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
60 | else | ||
61 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
62 | } | ||
63 | break; | ||
64 | case POWER_SUPPLY_PROP_ONLINE: | ||
65 | val->intval = 0; | ||
66 | if (data->usb_in || data->ta_in) | ||
67 | val->intval = 1; | ||
68 | break; | ||
69 | case POWER_SUPPLY_PROP_HEALTH: | ||
70 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | ||
71 | if (data->fault) | ||
72 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; | ||
73 | break; | ||
74 | default: | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static irqreturn_t max8903_dcin(int irq, void *_data) | ||
81 | { | ||
82 | struct max8903_data *data = _data; | ||
83 | struct max8903_pdata *pdata = data->pdata; | ||
84 | bool ta_in; | ||
85 | enum power_supply_type old_type; | ||
86 | |||
87 | ta_in = gpio_get_value(pdata->dok) ? false : true; | ||
88 | |||
89 | if (ta_in == data->ta_in) | ||
90 | return IRQ_HANDLED; | ||
91 | |||
92 | data->ta_in = ta_in; | ||
93 | |||
94 | /* Set Current-Limit-Mode 1:DC 0:USB */ | ||
95 | if (pdata->dcm) | ||
96 | gpio_set_value(pdata->dcm, ta_in ? 1 : 0); | ||
97 | |||
98 | /* Charger Enable / Disable (cen is negated) */ | ||
99 | if (pdata->cen) | ||
100 | gpio_set_value(pdata->cen, ta_in ? 0 : | ||
101 | (data->usb_in ? 0 : 1)); | ||
102 | |||
103 | dev_dbg(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ? | ||
104 | "Connected" : "Disconnected"); | ||
105 | |||
106 | old_type = data->psy.type; | ||
107 | |||
108 | if (data->ta_in) | ||
109 | data->psy.type = POWER_SUPPLY_TYPE_MAINS; | ||
110 | else if (data->usb_in) | ||
111 | data->psy.type = POWER_SUPPLY_TYPE_USB; | ||
112 | else | ||
113 | data->psy.type = POWER_SUPPLY_TYPE_BATTERY; | ||
114 | |||
115 | if (old_type != data->psy.type) | ||
116 | power_supply_changed(&data->psy); | ||
117 | |||
118 | return IRQ_HANDLED; | ||
119 | } | ||
120 | |||
121 | static irqreturn_t max8903_usbin(int irq, void *_data) | ||
122 | { | ||
123 | struct max8903_data *data = _data; | ||
124 | struct max8903_pdata *pdata = data->pdata; | ||
125 | bool usb_in; | ||
126 | enum power_supply_type old_type; | ||
127 | |||
128 | usb_in = gpio_get_value(pdata->uok) ? false : true; | ||
129 | |||
130 | if (usb_in == data->usb_in) | ||
131 | return IRQ_HANDLED; | ||
132 | |||
133 | data->usb_in = usb_in; | ||
134 | |||
135 | /* Do not touch Current-Limit-Mode */ | ||
136 | |||
137 | /* Charger Enable / Disable (cen is negated) */ | ||
138 | if (pdata->cen) | ||
139 | gpio_set_value(pdata->cen, usb_in ? 0 : | ||
140 | (data->ta_in ? 0 : 1)); | ||
141 | |||
142 | dev_dbg(data->dev, "USB Charger %s.\n", usb_in ? | ||
143 | "Connected" : "Disconnected"); | ||
144 | |||
145 | old_type = data->psy.type; | ||
146 | |||
147 | if (data->ta_in) | ||
148 | data->psy.type = POWER_SUPPLY_TYPE_MAINS; | ||
149 | else if (data->usb_in) | ||
150 | data->psy.type = POWER_SUPPLY_TYPE_USB; | ||
151 | else | ||
152 | data->psy.type = POWER_SUPPLY_TYPE_BATTERY; | ||
153 | |||
154 | if (old_type != data->psy.type) | ||
155 | power_supply_changed(&data->psy); | ||
156 | |||
157 | return IRQ_HANDLED; | ||
158 | } | ||
159 | |||
160 | static irqreturn_t max8903_fault(int irq, void *_data) | ||
161 | { | ||
162 | struct max8903_data *data = _data; | ||
163 | struct max8903_pdata *pdata = data->pdata; | ||
164 | bool fault; | ||
165 | |||
166 | fault = gpio_get_value(pdata->flt) ? false : true; | ||
167 | |||
168 | if (fault == data->fault) | ||
169 | return IRQ_HANDLED; | ||
170 | |||
171 | data->fault = fault; | ||
172 | |||
173 | if (fault) | ||
174 | dev_err(data->dev, "Charger suffers a fault and stops.\n"); | ||
175 | else | ||
176 | dev_err(data->dev, "Charger recovered from a fault.\n"); | ||
177 | |||
178 | return IRQ_HANDLED; | ||
179 | } | ||
180 | |||
181 | static __devinit int max8903_probe(struct platform_device *pdev) | ||
182 | { | ||
183 | struct max8903_data *data; | ||
184 | struct device *dev = &pdev->dev; | ||
185 | struct max8903_pdata *pdata = pdev->dev.platform_data; | ||
186 | int ret = 0; | ||
187 | int gpio; | ||
188 | int ta_in = 0; | ||
189 | int usb_in = 0; | ||
190 | |||
191 | data = kzalloc(sizeof(struct max8903_data), GFP_KERNEL); | ||
192 | if (data == NULL) { | ||
193 | dev_err(dev, "Cannot allocate memory.\n"); | ||
194 | return -ENOMEM; | ||
195 | } | ||
196 | data->pdata = pdata; | ||
197 | data->dev = dev; | ||
198 | platform_set_drvdata(pdev, data); | ||
199 | |||
200 | if (pdata->dc_valid == false && pdata->usb_valid == false) { | ||
201 | dev_err(dev, "No valid power sources.\n"); | ||
202 | ret = -EINVAL; | ||
203 | goto err; | ||
204 | } | ||
205 | |||
206 | if (pdata->dc_valid) { | ||
207 | if (pdata->dok && gpio_is_valid(pdata->dok) && | ||
208 | pdata->dcm && gpio_is_valid(pdata->dcm)) { | ||
209 | gpio = pdata->dok; /* PULL_UPed Interrupt */ | ||
210 | ta_in = gpio_get_value(gpio) ? 0 : 1; | ||
211 | |||
212 | gpio = pdata->dcm; /* Output */ | ||
213 | gpio_set_value(gpio, ta_in); | ||
214 | } else { | ||
215 | dev_err(dev, "When DC is wired, DOK and DCM should" | ||
216 | " be wired as well.\n"); | ||
217 | ret = -EINVAL; | ||
218 | goto err; | ||
219 | } | ||
220 | } else { | ||
221 | if (pdata->dcm) { | ||
222 | if (gpio_is_valid(pdata->dcm)) | ||
223 | gpio_set_value(pdata->dcm, 0); | ||
224 | else { | ||
225 | dev_err(dev, "Invalid pin: dcm.\n"); | ||
226 | ret = -EINVAL; | ||
227 | goto err; | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
232 | if (pdata->usb_valid) { | ||
233 | if (pdata->uok && gpio_is_valid(pdata->uok)) { | ||
234 | gpio = pdata->uok; | ||
235 | usb_in = gpio_get_value(gpio) ? 0 : 1; | ||
236 | } else { | ||
237 | dev_err(dev, "When USB is wired, UOK should be wired." | ||
238 | "as well.\n"); | ||
239 | ret = -EINVAL; | ||
240 | goto err; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | if (pdata->cen) { | ||
245 | if (gpio_is_valid(pdata->cen)) { | ||
246 | gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1); | ||
247 | } else { | ||
248 | dev_err(dev, "Invalid pin: cen.\n"); | ||
249 | ret = -EINVAL; | ||
250 | goto err; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | if (pdata->chg) { | ||
255 | if (!gpio_is_valid(pdata->chg)) { | ||
256 | dev_err(dev, "Invalid pin: chg.\n"); | ||
257 | ret = -EINVAL; | ||
258 | goto err; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | if (pdata->flt) { | ||
263 | if (!gpio_is_valid(pdata->flt)) { | ||
264 | dev_err(dev, "Invalid pin: flt.\n"); | ||
265 | ret = -EINVAL; | ||
266 | goto err; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | if (pdata->usus) { | ||
271 | if (!gpio_is_valid(pdata->usus)) { | ||
272 | dev_err(dev, "Invalid pin: usus.\n"); | ||
273 | ret = -EINVAL; | ||
274 | goto err; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | data->fault = false; | ||
279 | data->ta_in = ta_in; | ||
280 | data->usb_in = usb_in; | ||
281 | |||
282 | data->psy.name = "max8903_charger"; | ||
283 | data->psy.type = (ta_in) ? POWER_SUPPLY_TYPE_MAINS : | ||
284 | ((usb_in) ? POWER_SUPPLY_TYPE_USB : | ||
285 | POWER_SUPPLY_TYPE_BATTERY); | ||
286 | data->psy.get_property = max8903_get_property; | ||
287 | data->psy.properties = max8903_charger_props; | ||
288 | data->psy.num_properties = ARRAY_SIZE(max8903_charger_props); | ||
289 | |||
290 | ret = power_supply_register(dev, &data->psy); | ||
291 | if (ret) { | ||
292 | dev_err(dev, "failed: power supply register.\n"); | ||
293 | goto err; | ||
294 | } | ||
295 | |||
296 | if (pdata->dc_valid) { | ||
297 | ret = request_threaded_irq(gpio_to_irq(pdata->dok), | ||
298 | NULL, max8903_dcin, | ||
299 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | ||
300 | "MAX8903 DC IN", data); | ||
301 | if (ret) { | ||
302 | dev_err(dev, "Cannot request irq %d for DC (%d)\n", | ||
303 | gpio_to_irq(pdata->dok), ret); | ||
304 | goto err_psy; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | if (pdata->usb_valid) { | ||
309 | ret = request_threaded_irq(gpio_to_irq(pdata->uok), | ||
310 | NULL, max8903_usbin, | ||
311 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | ||
312 | "MAX8903 USB IN", data); | ||
313 | if (ret) { | ||
314 | dev_err(dev, "Cannot request irq %d for USB (%d)\n", | ||
315 | gpio_to_irq(pdata->uok), ret); | ||
316 | goto err_dc_irq; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | if (pdata->flt) { | ||
321 | ret = request_threaded_irq(gpio_to_irq(pdata->flt), | ||
322 | NULL, max8903_fault, | ||
323 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | ||
324 | "MAX8903 Fault", data); | ||
325 | if (ret) { | ||
326 | dev_err(dev, "Cannot request irq %d for Fault (%d)\n", | ||
327 | gpio_to_irq(pdata->flt), ret); | ||
328 | goto err_usb_irq; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | return 0; | ||
333 | |||
334 | err_usb_irq: | ||
335 | if (pdata->usb_valid) | ||
336 | free_irq(gpio_to_irq(pdata->uok), data); | ||
337 | err_dc_irq: | ||
338 | if (pdata->dc_valid) | ||
339 | free_irq(gpio_to_irq(pdata->dok), data); | ||
340 | err_psy: | ||
341 | power_supply_unregister(&data->psy); | ||
342 | err: | ||
343 | kfree(data); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | static __devexit int max8903_remove(struct platform_device *pdev) | ||
348 | { | ||
349 | struct max8903_data *data = platform_get_drvdata(pdev); | ||
350 | |||
351 | if (data) { | ||
352 | struct max8903_pdata *pdata = data->pdata; | ||
353 | |||
354 | if (pdata->flt) | ||
355 | free_irq(gpio_to_irq(pdata->flt), data); | ||
356 | if (pdata->usb_valid) | ||
357 | free_irq(gpio_to_irq(pdata->uok), data); | ||
358 | if (pdata->dc_valid) | ||
359 | free_irq(gpio_to_irq(pdata->dok), data); | ||
360 | power_supply_unregister(&data->psy); | ||
361 | kfree(data); | ||
362 | } | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static struct platform_driver max8903_driver = { | ||
368 | .probe = max8903_probe, | ||
369 | .remove = __devexit_p(max8903_remove), | ||
370 | .driver = { | ||
371 | .name = "max8903-charger", | ||
372 | .owner = THIS_MODULE, | ||
373 | }, | ||
374 | }; | ||
375 | |||
376 | static int __init max8903_init(void) | ||
377 | { | ||
378 | return platform_driver_register(&max8903_driver); | ||
379 | } | ||
380 | module_init(max8903_init); | ||
381 | |||
382 | static void __exit max8903_exit(void) | ||
383 | { | ||
384 | platform_driver_unregister(&max8903_driver); | ||
385 | } | ||
386 | module_exit(max8903_exit); | ||
387 | |||
388 | MODULE_LICENSE("GPL"); | ||
389 | MODULE_DESCRIPTION("MAX8903 Charger Driver"); | ||
390 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | ||
391 | MODULE_ALIAS("max8903-charger"); | ||
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c index 0cd9f67d33e5..b527c93bf2f3 100644 --- a/drivers/power/test_power.c +++ b/drivers/power/test_power.c | |||
@@ -3,6 +3,12 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2010 Anton Vorontsov <cbouatmailru@gmail.com> | 4 | * Copyright 2010 Anton Vorontsov <cbouatmailru@gmail.com> |
5 | * | 5 | * |
6 | * Dynamic module parameter code from the Virtual Battery Driver | ||
7 | * Copyright (C) 2008 Pylone, Inc. | ||
8 | * By: Masashi YOKOTA <yokota@pylone.jp> | ||
9 | * Originally found here: | ||
10 | * http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz2 | ||
11 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | 12 | * 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 | 13 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
@@ -15,8 +21,12 @@ | |||
15 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
16 | #include <linux/vermagic.h> | 22 | #include <linux/vermagic.h> |
17 | 23 | ||
18 | static int test_power_ac_online = 1; | 24 | static int ac_online = 1; |
19 | static int test_power_battery_status = POWER_SUPPLY_STATUS_CHARGING; | 25 | static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING; |
26 | static int battery_health = POWER_SUPPLY_HEALTH_GOOD; | ||
27 | static int battery_present = 1; /* true */ | ||
28 | static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; | ||
29 | static int battery_capacity = 50; | ||
20 | 30 | ||
21 | static int test_power_get_ac_property(struct power_supply *psy, | 31 | static int test_power_get_ac_property(struct power_supply *psy, |
22 | enum power_supply_property psp, | 32 | enum power_supply_property psp, |
@@ -24,7 +34,7 @@ static int test_power_get_ac_property(struct power_supply *psy, | |||
24 | { | 34 | { |
25 | switch (psp) { | 35 | switch (psp) { |
26 | case POWER_SUPPLY_PROP_ONLINE: | 36 | case POWER_SUPPLY_PROP_ONLINE: |
27 | val->intval = test_power_ac_online; | 37 | val->intval = ac_online; |
28 | break; | 38 | break; |
29 | default: | 39 | default: |
30 | return -EINVAL; | 40 | return -EINVAL; |
@@ -47,22 +57,30 @@ static int test_power_get_battery_property(struct power_supply *psy, | |||
47 | val->strval = UTS_RELEASE; | 57 | val->strval = UTS_RELEASE; |
48 | break; | 58 | break; |
49 | case POWER_SUPPLY_PROP_STATUS: | 59 | case POWER_SUPPLY_PROP_STATUS: |
50 | val->intval = test_power_battery_status; | 60 | val->intval = battery_status; |
51 | break; | 61 | break; |
52 | case POWER_SUPPLY_PROP_CHARGE_TYPE: | 62 | case POWER_SUPPLY_PROP_CHARGE_TYPE: |
53 | val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; | 63 | val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; |
54 | break; | 64 | break; |
55 | case POWER_SUPPLY_PROP_HEALTH: | 65 | case POWER_SUPPLY_PROP_HEALTH: |
56 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | 66 | val->intval = battery_health; |
67 | break; | ||
68 | case POWER_SUPPLY_PROP_PRESENT: | ||
69 | val->intval = battery_present; | ||
57 | break; | 70 | break; |
58 | case POWER_SUPPLY_PROP_TECHNOLOGY: | 71 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
59 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | 72 | val->intval = battery_technology; |
60 | break; | 73 | break; |
61 | case POWER_SUPPLY_PROP_CAPACITY_LEVEL: | 74 | case POWER_SUPPLY_PROP_CAPACITY_LEVEL: |
62 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; | 75 | val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; |
63 | break; | 76 | break; |
64 | case POWER_SUPPLY_PROP_CAPACITY: | 77 | case POWER_SUPPLY_PROP_CAPACITY: |
65 | val->intval = 50; | 78 | case POWER_SUPPLY_PROP_CHARGE_NOW: |
79 | val->intval = battery_capacity; | ||
80 | break; | ||
81 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
82 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
83 | val->intval = 100; | ||
66 | break; | 84 | break; |
67 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | 85 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
68 | case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: | 86 | case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: |
@@ -84,9 +102,11 @@ static enum power_supply_property test_power_battery_props[] = { | |||
84 | POWER_SUPPLY_PROP_STATUS, | 102 | POWER_SUPPLY_PROP_STATUS, |
85 | POWER_SUPPLY_PROP_CHARGE_TYPE, | 103 | POWER_SUPPLY_PROP_CHARGE_TYPE, |
86 | POWER_SUPPLY_PROP_HEALTH, | 104 | POWER_SUPPLY_PROP_HEALTH, |
105 | POWER_SUPPLY_PROP_PRESENT, | ||
87 | POWER_SUPPLY_PROP_TECHNOLOGY, | 106 | POWER_SUPPLY_PROP_TECHNOLOGY, |
107 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
88 | POWER_SUPPLY_PROP_CHARGE_FULL, | 108 | POWER_SUPPLY_PROP_CHARGE_FULL, |
89 | POWER_SUPPLY_PROP_CHARGE_EMPTY, | 109 | POWER_SUPPLY_PROP_CHARGE_NOW, |
90 | POWER_SUPPLY_PROP_CAPACITY, | 110 | POWER_SUPPLY_PROP_CAPACITY, |
91 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | 111 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, |
92 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, | 112 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, |
@@ -118,6 +138,7 @@ static struct power_supply test_power_supplies[] = { | |||
118 | }, | 138 | }, |
119 | }; | 139 | }; |
120 | 140 | ||
141 | |||
121 | static int __init test_power_init(void) | 142 | static int __init test_power_init(void) |
122 | { | 143 | { |
123 | int i; | 144 | int i; |
@@ -145,8 +166,8 @@ static void __exit test_power_exit(void) | |||
145 | int i; | 166 | int i; |
146 | 167 | ||
147 | /* Let's see how we handle changes... */ | 168 | /* Let's see how we handle changes... */ |
148 | test_power_ac_online = 0; | 169 | ac_online = 0; |
149 | test_power_battery_status = POWER_SUPPLY_STATUS_DISCHARGING; | 170 | battery_status = POWER_SUPPLY_STATUS_DISCHARGING; |
150 | for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) | 171 | for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) |
151 | power_supply_changed(&test_power_supplies[i]); | 172 | power_supply_changed(&test_power_supplies[i]); |
152 | pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n", | 173 | pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n", |
@@ -158,6 +179,241 @@ static void __exit test_power_exit(void) | |||
158 | } | 179 | } |
159 | module_exit(test_power_exit); | 180 | module_exit(test_power_exit); |
160 | 181 | ||
182 | |||
183 | |||
184 | #define MAX_KEYLENGTH 256 | ||
185 | struct battery_property_map { | ||
186 | int value; | ||
187 | char const *key; | ||
188 | }; | ||
189 | |||
190 | static struct battery_property_map map_ac_online[] = { | ||
191 | { 0, "on" }, | ||
192 | { 1, "off" }, | ||
193 | { -1, NULL }, | ||
194 | }; | ||
195 | |||
196 | static struct battery_property_map map_status[] = { | ||
197 | { POWER_SUPPLY_STATUS_CHARGING, "charging" }, | ||
198 | { POWER_SUPPLY_STATUS_DISCHARGING, "discharging" }, | ||
199 | { POWER_SUPPLY_STATUS_NOT_CHARGING, "not-charging" }, | ||
200 | { POWER_SUPPLY_STATUS_FULL, "full" }, | ||
201 | { -1, NULL }, | ||
202 | }; | ||
203 | |||
204 | static struct battery_property_map map_health[] = { | ||
205 | { POWER_SUPPLY_HEALTH_GOOD, "good" }, | ||
206 | { POWER_SUPPLY_HEALTH_OVERHEAT, "overheat" }, | ||
207 | { POWER_SUPPLY_HEALTH_DEAD, "dead" }, | ||
208 | { POWER_SUPPLY_HEALTH_OVERVOLTAGE, "overvoltage" }, | ||
209 | { POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, "failure" }, | ||
210 | { -1, NULL }, | ||
211 | }; | ||
212 | |||
213 | static struct battery_property_map map_present[] = { | ||
214 | { 0, "false" }, | ||
215 | { 1, "true" }, | ||
216 | { -1, NULL }, | ||
217 | }; | ||
218 | |||
219 | static struct battery_property_map map_technology[] = { | ||
220 | { POWER_SUPPLY_TECHNOLOGY_NiMH, "NiMH" }, | ||
221 | { POWER_SUPPLY_TECHNOLOGY_LION, "LION" }, | ||
222 | { POWER_SUPPLY_TECHNOLOGY_LIPO, "LIPO" }, | ||
223 | { POWER_SUPPLY_TECHNOLOGY_LiFe, "LiFe" }, | ||
224 | { POWER_SUPPLY_TECHNOLOGY_NiCd, "NiCd" }, | ||
225 | { POWER_SUPPLY_TECHNOLOGY_LiMn, "LiMn" }, | ||
226 | { -1, NULL }, | ||
227 | }; | ||
228 | |||
229 | |||
230 | static int map_get_value(struct battery_property_map *map, const char *key, | ||
231 | int def_val) | ||
232 | { | ||
233 | char buf[MAX_KEYLENGTH]; | ||
234 | int cr; | ||
235 | |||
236 | strncpy(buf, key, MAX_KEYLENGTH); | ||
237 | buf[MAX_KEYLENGTH-1] = '\0'; | ||
238 | |||
239 | cr = strnlen(buf, MAX_KEYLENGTH) - 1; | ||
240 | if (buf[cr] == '\n') | ||
241 | buf[cr] = '\0'; | ||
242 | |||
243 | while (map->key) { | ||
244 | if (strncasecmp(map->key, buf, MAX_KEYLENGTH) == 0) | ||
245 | return map->value; | ||
246 | map++; | ||
247 | } | ||
248 | |||
249 | return def_val; | ||
250 | } | ||
251 | |||
252 | |||
253 | static const char *map_get_key(struct battery_property_map *map, int value, | ||
254 | const char *def_key) | ||
255 | { | ||
256 | while (map->key) { | ||
257 | if (map->value == value) | ||
258 | return map->key; | ||
259 | map++; | ||
260 | } | ||
261 | |||
262 | return def_key; | ||
263 | } | ||
264 | |||
265 | static int param_set_ac_online(const char *key, const struct kernel_param *kp) | ||
266 | { | ||
267 | ac_online = map_get_value(map_ac_online, key, ac_online); | ||
268 | power_supply_changed(&test_power_supplies[0]); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int param_get_ac_online(char *buffer, const struct kernel_param *kp) | ||
273 | { | ||
274 | strcpy(buffer, map_get_key(map_ac_online, ac_online, "unknown")); | ||
275 | return strlen(buffer); | ||
276 | } | ||
277 | |||
278 | static int param_set_battery_status(const char *key, | ||
279 | const struct kernel_param *kp) | ||
280 | { | ||
281 | battery_status = map_get_value(map_status, key, battery_status); | ||
282 | power_supply_changed(&test_power_supplies[1]); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int param_get_battery_status(char *buffer, const struct kernel_param *kp) | ||
287 | { | ||
288 | strcpy(buffer, map_get_key(map_status, battery_status, "unknown")); | ||
289 | return strlen(buffer); | ||
290 | } | ||
291 | |||
292 | static int param_set_battery_health(const char *key, | ||
293 | const struct kernel_param *kp) | ||
294 | { | ||
295 | battery_health = map_get_value(map_health, key, battery_health); | ||
296 | power_supply_changed(&test_power_supplies[1]); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int param_get_battery_health(char *buffer, const struct kernel_param *kp) | ||
301 | { | ||
302 | strcpy(buffer, map_get_key(map_health, battery_health, "unknown")); | ||
303 | return strlen(buffer); | ||
304 | } | ||
305 | |||
306 | static int param_set_battery_present(const char *key, | ||
307 | const struct kernel_param *kp) | ||
308 | { | ||
309 | battery_present = map_get_value(map_present, key, battery_present); | ||
310 | power_supply_changed(&test_power_supplies[0]); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int param_get_battery_present(char *buffer, | ||
315 | const struct kernel_param *kp) | ||
316 | { | ||
317 | strcpy(buffer, map_get_key(map_present, battery_present, "unknown")); | ||
318 | return strlen(buffer); | ||
319 | } | ||
320 | |||
321 | static int param_set_battery_technology(const char *key, | ||
322 | const struct kernel_param *kp) | ||
323 | { | ||
324 | battery_technology = map_get_value(map_technology, key, | ||
325 | battery_technology); | ||
326 | power_supply_changed(&test_power_supplies[1]); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int param_get_battery_technology(char *buffer, | ||
331 | const struct kernel_param *kp) | ||
332 | { | ||
333 | strcpy(buffer, | ||
334 | map_get_key(map_technology, battery_technology, "unknown")); | ||
335 | return strlen(buffer); | ||
336 | } | ||
337 | |||
338 | static int param_set_battery_capacity(const char *key, | ||
339 | const struct kernel_param *kp) | ||
340 | { | ||
341 | int tmp; | ||
342 | |||
343 | if (1 != sscanf(key, "%d", &tmp)) | ||
344 | return -EINVAL; | ||
345 | |||
346 | battery_capacity = tmp; | ||
347 | power_supply_changed(&test_power_supplies[1]); | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | #define param_get_battery_capacity param_get_int | ||
352 | |||
353 | |||
354 | |||
355 | static struct kernel_param_ops param_ops_ac_online = { | ||
356 | .set = param_set_ac_online, | ||
357 | .get = param_get_ac_online, | ||
358 | }; | ||
359 | |||
360 | static struct kernel_param_ops param_ops_battery_status = { | ||
361 | .set = param_set_battery_status, | ||
362 | .get = param_get_battery_status, | ||
363 | }; | ||
364 | |||
365 | static struct kernel_param_ops param_ops_battery_present = { | ||
366 | .set = param_set_battery_present, | ||
367 | .get = param_get_battery_present, | ||
368 | }; | ||
369 | |||
370 | static struct kernel_param_ops param_ops_battery_technology = { | ||
371 | .set = param_set_battery_technology, | ||
372 | .get = param_get_battery_technology, | ||
373 | }; | ||
374 | |||
375 | static struct kernel_param_ops param_ops_battery_health = { | ||
376 | .set = param_set_battery_health, | ||
377 | .get = param_get_battery_health, | ||
378 | }; | ||
379 | |||
380 | static struct kernel_param_ops param_ops_battery_capacity = { | ||
381 | .set = param_set_battery_capacity, | ||
382 | .get = param_get_battery_capacity, | ||
383 | }; | ||
384 | |||
385 | |||
386 | #define param_check_ac_online(name, p) __param_check(name, p, void); | ||
387 | #define param_check_battery_status(name, p) __param_check(name, p, void); | ||
388 | #define param_check_battery_present(name, p) __param_check(name, p, void); | ||
389 | #define param_check_battery_technology(name, p) __param_check(name, p, void); | ||
390 | #define param_check_battery_health(name, p) __param_check(name, p, void); | ||
391 | #define param_check_battery_capacity(name, p) __param_check(name, p, void); | ||
392 | |||
393 | |||
394 | module_param(ac_online, ac_online, 0644); | ||
395 | MODULE_PARM_DESC(ac_online, "AC charging state <on|off>"); | ||
396 | |||
397 | module_param(battery_status, battery_status, 0644); | ||
398 | MODULE_PARM_DESC(battery_status, | ||
399 | "battery status <charging|discharging|not-charging|full>"); | ||
400 | |||
401 | module_param(battery_present, battery_present, 0644); | ||
402 | MODULE_PARM_DESC(battery_present, | ||
403 | "battery presence state <good|overheat|dead|overvoltage|failure>"); | ||
404 | |||
405 | module_param(battery_technology, battery_technology, 0644); | ||
406 | MODULE_PARM_DESC(battery_technology, | ||
407 | "battery technology <NiMH|LION|LIPO|LiFe|NiCd|LiMn>"); | ||
408 | |||
409 | module_param(battery_health, battery_health, 0644); | ||
410 | MODULE_PARM_DESC(battery_health, | ||
411 | "battery health state <good|overheat|dead|overvoltage|failure>"); | ||
412 | |||
413 | module_param(battery_capacity, battery_capacity, 0644); | ||
414 | MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)"); | ||
415 | |||
416 | |||
161 | MODULE_DESCRIPTION("Power supply driver for testing"); | 417 | MODULE_DESCRIPTION("Power supply driver for testing"); |
162 | MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); | 418 | MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); |
163 | MODULE_LICENSE("GPL"); | 419 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index e5ced3a4c1ed..d119c38b3ff6 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c | |||
@@ -271,24 +271,33 @@ static int __devexit z2_batt_remove(struct i2c_client *client) | |||
271 | } | 271 | } |
272 | 272 | ||
273 | #ifdef CONFIG_PM | 273 | #ifdef CONFIG_PM |
274 | static int z2_batt_suspend(struct i2c_client *client, pm_message_t state) | 274 | static int z2_batt_suspend(struct device *dev) |
275 | { | 275 | { |
276 | struct i2c_client *client = to_i2c_client(dev); | ||
276 | struct z2_charger *charger = i2c_get_clientdata(client); | 277 | struct z2_charger *charger = i2c_get_clientdata(client); |
277 | 278 | ||
278 | flush_work_sync(&charger->bat_work); | 279 | flush_work_sync(&charger->bat_work); |
279 | return 0; | 280 | return 0; |
280 | } | 281 | } |
281 | 282 | ||
282 | static int z2_batt_resume(struct i2c_client *client) | 283 | static int z2_batt_resume(struct device *dev) |
283 | { | 284 | { |
285 | struct i2c_client *client = to_i2c_client(dev); | ||
284 | struct z2_charger *charger = i2c_get_clientdata(client); | 286 | struct z2_charger *charger = i2c_get_clientdata(client); |
285 | 287 | ||
286 | schedule_work(&charger->bat_work); | 288 | schedule_work(&charger->bat_work); |
287 | return 0; | 289 | return 0; |
288 | } | 290 | } |
291 | |||
292 | static const struct dev_pm_ops z2_battery_pm_ops = { | ||
293 | .suspend = z2_batt_suspend, | ||
294 | .resume = z2_batt_resume, | ||
295 | }; | ||
296 | |||
297 | #define Z2_BATTERY_PM_OPS (&z2_battery_pm_ops) | ||
298 | |||
289 | #else | 299 | #else |
290 | #define z2_batt_suspend NULL | 300 | #define Z2_BATTERY_PM_OPS (NULL) |
291 | #define z2_batt_resume NULL | ||
292 | #endif | 301 | #endif |
293 | 302 | ||
294 | static const struct i2c_device_id z2_batt_id[] = { | 303 | static const struct i2c_device_id z2_batt_id[] = { |
@@ -301,11 +310,10 @@ static struct i2c_driver z2_batt_driver = { | |||
301 | .driver = { | 310 | .driver = { |
302 | .name = "z2-battery", | 311 | .name = "z2-battery", |
303 | .owner = THIS_MODULE, | 312 | .owner = THIS_MODULE, |
313 | .pm = Z2_BATTERY_PM_OPS | ||
304 | }, | 314 | }, |
305 | .probe = z2_batt_probe, | 315 | .probe = z2_batt_probe, |
306 | .remove = z2_batt_remove, | 316 | .remove = z2_batt_remove, |
307 | .suspend = z2_batt_suspend, | ||
308 | .resume = z2_batt_resume, | ||
309 | .id_table = z2_batt_id, | 317 | .id_table = z2_batt_id, |
310 | }; | 318 | }; |
311 | 319 | ||