diff options
Diffstat (limited to 'drivers/power/ds2782_battery.c')
-rw-r--r-- | drivers/power/ds2782_battery.c | 184 |
1 files changed, 136 insertions, 48 deletions
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c index ba1bd1a545be..c665e8007235 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); |
@@ -241,13 +300,36 @@ static int ds2782_battery_remove(struct i2c_client *client) | |||
241 | return 0; | 300 | return 0; |
242 | } | 301 | } |
243 | 302 | ||
244 | static int ds2782_battery_probe(struct i2c_client *client, | 303 | static struct ds278x_battery_ops ds278x_ops[] = { |
304 | [0] = { | ||
305 | .get_current = ds2782_get_current, | ||
306 | .get_voltage = ds2782_get_voltage, | ||
307 | .get_capacity = ds2782_get_capacity, | ||
308 | }, | ||
309 | [1] = { | ||
310 | .get_current = ds2786_get_current, | ||
311 | .get_voltage = ds2786_get_voltage, | ||
312 | .get_capacity = ds2786_get_capacity, | ||
313 | } | ||
314 | }; | ||
315 | |||
316 | static int ds278x_battery_probe(struct i2c_client *client, | ||
245 | const struct i2c_device_id *id) | 317 | const struct i2c_device_id *id) |
246 | { | 318 | { |
247 | struct ds2782_info *info; | 319 | struct ds278x_platform_data *pdata = client->dev.platform_data; |
320 | struct ds278x_info *info; | ||
248 | int ret; | 321 | int ret; |
249 | int num; | 322 | int num; |
250 | 323 | ||
324 | /* | ||
325 | * ds2786 should have the sense resistor value set | ||
326 | * in the platform data | ||
327 | */ | ||
328 | if (id->driver_data == 1 && !pdata) { | ||
329 | dev_err(&client->dev, "missing platform data for ds2786\n"); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
251 | /* Get an ID for this battery */ | 333 | /* Get an ID for this battery */ |
252 | ret = idr_pre_get(&battery_id, GFP_KERNEL); | 334 | ret = idr_pre_get(&battery_id, GFP_KERNEL); |
253 | if (ret == 0) { | 335 | if (ret == 0) { |
@@ -267,15 +349,20 @@ static int ds2782_battery_probe(struct i2c_client *client, | |||
267 | goto fail_info; | 349 | goto fail_info; |
268 | } | 350 | } |
269 | 351 | ||
270 | info->battery.name = kasprintf(GFP_KERNEL, "ds2782-%d", num); | 352 | info->battery.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num); |
271 | if (!info->battery.name) { | 353 | if (!info->battery.name) { |
272 | ret = -ENOMEM; | 354 | ret = -ENOMEM; |
273 | goto fail_name; | 355 | goto fail_name; |
274 | } | 356 | } |
275 | 357 | ||
358 | if (id->driver_data == 1) | ||
359 | info->rsns = pdata->rsns; | ||
360 | |||
276 | i2c_set_clientdata(client, info); | 361 | i2c_set_clientdata(client, info); |
277 | info->client = client; | 362 | info->client = client; |
278 | ds2782_power_supply_init(&info->battery); | 363 | info->id = num; |
364 | info->ops = &ds278x_ops[id->driver_data]; | ||
365 | ds278x_power_supply_init(&info->battery); | ||
279 | 366 | ||
280 | ret = power_supply_register(&client->dev, &info->battery); | 367 | ret = power_supply_register(&client->dev, &info->battery); |
281 | if (ret) { | 368 | if (ret) { |
@@ -297,31 +384,32 @@ fail_id: | |||
297 | return ret; | 384 | return ret; |
298 | } | 385 | } |
299 | 386 | ||
300 | static const struct i2c_device_id ds2782_id[] = { | 387 | static const struct i2c_device_id ds278x_id[] = { |
301 | {"ds2782", 0}, | 388 | {"ds2782", 0}, |
389 | {"ds2786", 1}, | ||
302 | {}, | 390 | {}, |
303 | }; | 391 | }; |
304 | 392 | ||
305 | static struct i2c_driver ds2782_battery_driver = { | 393 | static struct i2c_driver ds278x_battery_driver = { |
306 | .driver = { | 394 | .driver = { |
307 | .name = "ds2782-battery", | 395 | .name = "ds2782-battery", |
308 | }, | 396 | }, |
309 | .probe = ds2782_battery_probe, | 397 | .probe = ds278x_battery_probe, |
310 | .remove = ds2782_battery_remove, | 398 | .remove = ds278x_battery_remove, |
311 | .id_table = ds2782_id, | 399 | .id_table = ds278x_id, |
312 | }; | 400 | }; |
313 | 401 | ||
314 | static int __init ds2782_init(void) | 402 | static int __init ds278x_init(void) |
315 | { | 403 | { |
316 | return i2c_add_driver(&ds2782_battery_driver); | 404 | return i2c_add_driver(&ds278x_battery_driver); |
317 | } | 405 | } |
318 | module_init(ds2782_init); | 406 | module_init(ds278x_init); |
319 | 407 | ||
320 | static void __exit ds2782_exit(void) | 408 | static void __exit ds278x_exit(void) |
321 | { | 409 | { |
322 | i2c_del_driver(&ds2782_battery_driver); | 410 | i2c_del_driver(&ds278x_battery_driver); |
323 | } | 411 | } |
324 | module_exit(ds2782_exit); | 412 | module_exit(ds278x_exit); |
325 | 413 | ||
326 | MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); | 414 | MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); |
327 | MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver"); | 415 | MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver"); |