diff options
author | Renata Sayakhova <rsayakhova@gmail.com> | 2012-02-29 08:58:53 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-03-08 14:15:33 -0500 |
commit | fef37e9a47b9927ce2817fe1a0fa8cf40f6eefb6 (patch) | |
tree | 4cba1a0e4cf7b1e1f342bc86d8305c7ab037a4eb /drivers | |
parent | f6e8a1d7b4c4087e13913da43deb45b3e3413f29 (diff) |
DS2781 Maxim Stand-Alone Fuel Gauge battery and w1 slave drivers
Signed-off-by: Renata Sayakhova <rsayakhova@gmail.com>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/Kconfig | 14 | ||||
-rw-r--r-- | drivers/power/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/ds2781_battery.c | 874 | ||||
-rw-r--r-- | drivers/w1/slaves/Kconfig | 13 | ||||
-rw-r--r-- | drivers/w1/slaves/Makefile | 1 | ||||
-rw-r--r-- | drivers/w1/slaves/w1_ds2781.c | 201 | ||||
-rw-r--r-- | drivers/w1/slaves/w1_ds2781.h | 136 | ||||
-rw-r--r-- | drivers/w1/w1_family.h | 1 |
8 files changed, 1241 insertions, 0 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 3a8daf858742..459f66437fe9 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
@@ -76,6 +76,20 @@ config BATTERY_DS2780 | |||
76 | help | 76 | help |
77 | Say Y here to enable support for batteries with ds2780 chip. | 77 | Say Y here to enable support for batteries with ds2780 chip. |
78 | 78 | ||
79 | config BATTERY_DS2781 | ||
80 | tristate "2781 battery driver" | ||
81 | depends on HAS_IOMEM | ||
82 | select W1 | ||
83 | select W1_SLAVE_DS2781 | ||
84 | help | ||
85 | If you enable this you will have the DS2781 battery driver support. | ||
86 | |||
87 | The battery monitor chip is used in many batteries/devices | ||
88 | as the one who is responsible for charging/discharging/monitoring | ||
89 | Li+ batteries. | ||
90 | |||
91 | If you are unsure, say N. | ||
92 | |||
79 | config BATTERY_DS2782 | 93 | config BATTERY_DS2782 |
80 | tristate "DS2782/DS2786 standalone gas-gauge" | 94 | tristate "DS2782/DS2786 standalone gas-gauge" |
81 | depends on I2C | 95 | depends on I2C |
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index e429008eaf10..c590fa533406 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
@@ -16,6 +16,7 @@ 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_DS2780) += ds2780_battery.o |
19 | obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o | ||
19 | obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o | 20 | obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o |
20 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o | 21 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o |
21 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | 22 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o |
diff --git a/drivers/power/ds2781_battery.c b/drivers/power/ds2781_battery.c new file mode 100644 index 000000000000..ca0d653d0a7a --- /dev/null +++ b/drivers/power/ds2781_battery.c | |||
@@ -0,0 +1,874 @@ | |||
1 | /* | ||
2 | * 1-wire client/driver for the Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC | ||
3 | * | ||
4 | * Author: Renata Sayakhova <renata@oktetlabs.ru> | ||
5 | * | ||
6 | * Based on ds2780_battery drivers | ||
7 | * | ||
8 | * 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 | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/param.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/power_supply.h> | ||
20 | #include <linux/idr.h> | ||
21 | |||
22 | #include "../w1/w1.h" | ||
23 | #include "../w1/slaves/w1_ds2781.h" | ||
24 | |||
25 | /* Current unit measurement in uA for a 1 milli-ohm sense resistor */ | ||
26 | #define DS2781_CURRENT_UNITS 1563 | ||
27 | /* Charge unit measurement in uAh for a 1 milli-ohm sense resistor */ | ||
28 | #define DS2781_CHARGE_UNITS 6250 | ||
29 | /* Number of bytes in user EEPROM space */ | ||
30 | #define DS2781_USER_EEPROM_SIZE (DS2781_EEPROM_BLOCK0_END - \ | ||
31 | DS2781_EEPROM_BLOCK0_START + 1) | ||
32 | /* Number of bytes in parameter EEPROM space */ | ||
33 | #define DS2781_PARAM_EEPROM_SIZE (DS2781_EEPROM_BLOCK1_END - \ | ||
34 | DS2781_EEPROM_BLOCK1_START + 1) | ||
35 | |||
36 | struct ds2781_device_info { | ||
37 | struct device *dev; | ||
38 | struct power_supply bat; | ||
39 | struct device *w1_dev; | ||
40 | struct task_struct *mutex_holder; | ||
41 | }; | ||
42 | |||
43 | enum current_types { | ||
44 | CURRENT_NOW, | ||
45 | CURRENT_AVG, | ||
46 | }; | ||
47 | |||
48 | static const char model[] = "DS2781"; | ||
49 | static const char manufacturer[] = "Maxim/Dallas"; | ||
50 | |||
51 | static inline struct ds2781_device_info * | ||
52 | to_ds2781_device_info(struct power_supply *psy) | ||
53 | { | ||
54 | return container_of(psy, struct ds2781_device_info, bat); | ||
55 | } | ||
56 | |||
57 | static inline struct power_supply *to_power_supply(struct device *dev) | ||
58 | { | ||
59 | return dev_get_drvdata(dev); | ||
60 | } | ||
61 | |||
62 | static inline int ds2781_battery_io(struct ds2781_device_info *dev_info, | ||
63 | char *buf, int addr, size_t count, int io) | ||
64 | { | ||
65 | if (dev_info->mutex_holder == current) | ||
66 | return w1_ds2781_io_nolock(dev_info->w1_dev, buf, addr, | ||
67 | count, io); | ||
68 | else | ||
69 | return w1_ds2781_io(dev_info->w1_dev, buf, addr, count, io); | ||
70 | } | ||
71 | |||
72 | int w1_ds2781_read(struct ds2781_device_info *dev_info, char *buf, | ||
73 | int addr, size_t count) | ||
74 | { | ||
75 | return ds2781_battery_io(dev_info, buf, addr, count, 0); | ||
76 | } | ||
77 | |||
78 | static inline int ds2781_read8(struct ds2781_device_info *dev_info, u8 *val, | ||
79 | int addr) | ||
80 | { | ||
81 | return ds2781_battery_io(dev_info, val, addr, sizeof(u8), 0); | ||
82 | } | ||
83 | |||
84 | static int ds2781_read16(struct ds2781_device_info *dev_info, s16 *val, | ||
85 | int addr) | ||
86 | { | ||
87 | int ret; | ||
88 | u8 raw[2]; | ||
89 | |||
90 | ret = ds2781_battery_io(dev_info, raw, addr, sizeof(raw), 0); | ||
91 | if (ret < 0) | ||
92 | return ret; | ||
93 | |||
94 | *val = (raw[0] << 8) | raw[1]; | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static inline int ds2781_read_block(struct ds2781_device_info *dev_info, | ||
100 | u8 *val, int addr, size_t count) | ||
101 | { | ||
102 | return ds2781_battery_io(dev_info, val, addr, count, 0); | ||
103 | } | ||
104 | |||
105 | static inline int ds2781_write(struct ds2781_device_info *dev_info, u8 *val, | ||
106 | int addr, size_t count) | ||
107 | { | ||
108 | return ds2781_battery_io(dev_info, val, addr, count, 1); | ||
109 | } | ||
110 | |||
111 | static inline int ds2781_store_eeprom(struct device *dev, int addr) | ||
112 | { | ||
113 | return w1_ds2781_eeprom_cmd(dev, addr, W1_DS2781_COPY_DATA); | ||
114 | } | ||
115 | |||
116 | static inline int ds2781_recall_eeprom(struct device *dev, int addr) | ||
117 | { | ||
118 | return w1_ds2781_eeprom_cmd(dev, addr, W1_DS2781_RECALL_DATA); | ||
119 | } | ||
120 | |||
121 | static int ds2781_save_eeprom(struct ds2781_device_info *dev_info, int reg) | ||
122 | { | ||
123 | int ret; | ||
124 | |||
125 | ret = ds2781_store_eeprom(dev_info->w1_dev, reg); | ||
126 | if (ret < 0) | ||
127 | return ret; | ||
128 | |||
129 | ret = ds2781_recall_eeprom(dev_info->w1_dev, reg); | ||
130 | if (ret < 0) | ||
131 | return ret; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | /* Set sense resistor value in mhos */ | ||
137 | static int ds2781_set_sense_register(struct ds2781_device_info *dev_info, | ||
138 | u8 conductance) | ||
139 | { | ||
140 | int ret; | ||
141 | |||
142 | ret = ds2781_write(dev_info, &conductance, | ||
143 | DS2781_RSNSP, sizeof(u8)); | ||
144 | if (ret < 0) | ||
145 | return ret; | ||
146 | |||
147 | return ds2781_save_eeprom(dev_info, DS2781_RSNSP); | ||
148 | } | ||
149 | |||
150 | /* Get RSGAIN value from 0 to 1.999 in steps of 0.001 */ | ||
151 | static int ds2781_get_rsgain_register(struct ds2781_device_info *dev_info, | ||
152 | u16 *rsgain) | ||
153 | { | ||
154 | return ds2781_read16(dev_info, rsgain, DS2781_RSGAIN_MSB); | ||
155 | } | ||
156 | |||
157 | /* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */ | ||
158 | static int ds2781_set_rsgain_register(struct ds2781_device_info *dev_info, | ||
159 | u16 rsgain) | ||
160 | { | ||
161 | int ret; | ||
162 | u8 raw[] = {rsgain >> 8, rsgain & 0xFF}; | ||
163 | |||
164 | ret = ds2781_write(dev_info, raw, | ||
165 | DS2781_RSGAIN_MSB, sizeof(raw)); | ||
166 | if (ret < 0) | ||
167 | return ret; | ||
168 | |||
169 | return ds2781_save_eeprom(dev_info, DS2781_RSGAIN_MSB); | ||
170 | } | ||
171 | |||
172 | static int ds2781_get_voltage(struct ds2781_device_info *dev_info, | ||
173 | int *voltage_uV) | ||
174 | { | ||
175 | int ret; | ||
176 | char val[2]; | ||
177 | int voltage_raw; | ||
178 | |||
179 | ret = w1_ds2781_read(dev_info, val, DS2781_VOLT_MSB, 2 * sizeof(u8)); | ||
180 | if (ret < 0) | ||
181 | return ret; | ||
182 | /* | ||
183 | * The voltage value is located in 10 bits across the voltage MSB | ||
184 | * and LSB registers in two's compliment form | ||
185 | * Sign bit of the voltage value is in bit 7 of the voltage MSB register | ||
186 | * Bits 9 - 3 of the voltage value are in bits 6 - 0 of the | ||
187 | * voltage MSB register | ||
188 | * Bits 2 - 0 of the voltage value are in bits 7 - 5 of the | ||
189 | * voltage LSB register | ||
190 | */ | ||
191 | voltage_raw = (val[0] << 3) | | ||
192 | (val[1] >> 5); | ||
193 | |||
194 | /* DS2781 reports voltage in units of 9.76mV, but the battery class | ||
195 | * reports in units of uV, so convert by multiplying by 9760. */ | ||
196 | *voltage_uV = voltage_raw * 9760; | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int ds2781_get_temperature(struct ds2781_device_info *dev_info, | ||
202 | int *temp) | ||
203 | { | ||
204 | int ret; | ||
205 | char val[2]; | ||
206 | int temp_raw; | ||
207 | |||
208 | ret = w1_ds2781_read(dev_info, val, DS2781_TEMP_MSB, 2 * sizeof(u8)); | ||
209 | if (ret < 0) | ||
210 | return ret; | ||
211 | /* | ||
212 | * The temperature value is located in 10 bits across the temperature | ||
213 | * MSB and LSB registers in two's compliment form | ||
214 | * Sign bit of the temperature value is in bit 7 of the temperature | ||
215 | * MSB register | ||
216 | * Bits 9 - 3 of the temperature value are in bits 6 - 0 of the | ||
217 | * temperature MSB register | ||
218 | * Bits 2 - 0 of the temperature value are in bits 7 - 5 of the | ||
219 | * temperature LSB register | ||
220 | */ | ||
221 | temp_raw = ((val[0]) << 3) | | ||
222 | (val[1] >> 5); | ||
223 | *temp = temp_raw + (temp_raw / 4); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int ds2781_get_current(struct ds2781_device_info *dev_info, | ||
229 | enum current_types type, int *current_uA) | ||
230 | { | ||
231 | int ret, sense_res; | ||
232 | s16 current_raw; | ||
233 | u8 sense_res_raw, reg_msb; | ||
234 | |||
235 | /* | ||
236 | * The units of measurement for current are dependent on the value of | ||
237 | * the sense resistor. | ||
238 | */ | ||
239 | ret = ds2781_read8(dev_info, &sense_res_raw, DS2781_RSNSP); | ||
240 | if (ret < 0) | ||
241 | return ret; | ||
242 | |||
243 | if (sense_res_raw == 0) { | ||
244 | dev_err(dev_info->dev, "sense resistor value is 0\n"); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | sense_res = 1000 / sense_res_raw; | ||
248 | |||
249 | if (type == CURRENT_NOW) | ||
250 | reg_msb = DS2781_CURRENT_MSB; | ||
251 | else if (type == CURRENT_AVG) | ||
252 | reg_msb = DS2781_IAVG_MSB; | ||
253 | else | ||
254 | return -EINVAL; | ||
255 | |||
256 | /* | ||
257 | * The current value is located in 16 bits across the current MSB | ||
258 | * and LSB registers in two's compliment form | ||
259 | * Sign bit of the current value is in bit 7 of the current MSB register | ||
260 | * Bits 14 - 8 of the current value are in bits 6 - 0 of the current | ||
261 | * MSB register | ||
262 | * Bits 7 - 0 of the current value are in bits 7 - 0 of the current | ||
263 | * LSB register | ||
264 | */ | ||
265 | ret = ds2781_read16(dev_info, ¤t_raw, reg_msb); | ||
266 | if (ret < 0) | ||
267 | return ret; | ||
268 | |||
269 | *current_uA = current_raw * (DS2781_CURRENT_UNITS / sense_res); | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int ds2781_get_accumulated_current(struct ds2781_device_info *dev_info, | ||
274 | int *accumulated_current) | ||
275 | { | ||
276 | int ret, sense_res; | ||
277 | s16 current_raw; | ||
278 | u8 sense_res_raw; | ||
279 | |||
280 | /* | ||
281 | * The units of measurement for accumulated current are dependent on | ||
282 | * the value of the sense resistor. | ||
283 | */ | ||
284 | ret = ds2781_read8(dev_info, &sense_res_raw, DS2781_RSNSP); | ||
285 | if (ret < 0) | ||
286 | return ret; | ||
287 | |||
288 | if (sense_res_raw == 0) { | ||
289 | dev_err(dev_info->dev, "sense resistor value is 0\n"); | ||
290 | return -EINVAL; | ||
291 | } | ||
292 | sense_res = 1000 / sense_res_raw; | ||
293 | |||
294 | /* | ||
295 | * The ACR value is located in 16 bits across the ACR MSB and | ||
296 | * LSB registers | ||
297 | * Bits 15 - 8 of the ACR value are in bits 7 - 0 of the ACR | ||
298 | * MSB register | ||
299 | * Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR | ||
300 | * LSB register | ||
301 | */ | ||
302 | ret = ds2781_read16(dev_info, ¤t_raw, DS2781_ACR_MSB); | ||
303 | if (ret < 0) | ||
304 | return ret; | ||
305 | |||
306 | *accumulated_current = current_raw * (DS2781_CHARGE_UNITS / sense_res); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int ds2781_get_capacity(struct ds2781_device_info *dev_info, | ||
311 | int *capacity) | ||
312 | { | ||
313 | int ret; | ||
314 | u8 raw; | ||
315 | |||
316 | ret = ds2781_read8(dev_info, &raw, DS2781_RARC); | ||
317 | if (ret < 0) | ||
318 | return ret; | ||
319 | |||
320 | *capacity = raw; | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int ds2781_get_status(struct ds2781_device_info *dev_info, int *status) | ||
325 | { | ||
326 | int ret, current_uA, capacity; | ||
327 | |||
328 | ret = ds2781_get_current(dev_info, CURRENT_NOW, ¤t_uA); | ||
329 | if (ret < 0) | ||
330 | return ret; | ||
331 | |||
332 | ret = ds2781_get_capacity(dev_info, &capacity); | ||
333 | if (ret < 0) | ||
334 | return ret; | ||
335 | |||
336 | if (power_supply_am_i_supplied(&dev_info->bat)) { | ||
337 | if (capacity == 100) | ||
338 | *status = POWER_SUPPLY_STATUS_FULL; | ||
339 | else if (current_uA > 50000) | ||
340 | *status = POWER_SUPPLY_STATUS_CHARGING; | ||
341 | else | ||
342 | *status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
343 | } else { | ||
344 | *status = POWER_SUPPLY_STATUS_DISCHARGING; | ||
345 | } | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int ds2781_get_charge_now(struct ds2781_device_info *dev_info, | ||
350 | int *charge_now) | ||
351 | { | ||
352 | int ret; | ||
353 | u16 charge_raw; | ||
354 | |||
355 | /* | ||
356 | * The RAAC value is located in 16 bits across the RAAC MSB and | ||
357 | * LSB registers | ||
358 | * Bits 15 - 8 of the RAAC value are in bits 7 - 0 of the RAAC | ||
359 | * MSB register | ||
360 | * Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC | ||
361 | * LSB register | ||
362 | */ | ||
363 | ret = ds2781_read16(dev_info, &charge_raw, DS2781_RAAC_MSB); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | |||
367 | *charge_now = charge_raw * 1600; | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int ds2781_get_control_register(struct ds2781_device_info *dev_info, | ||
372 | u8 *control_reg) | ||
373 | { | ||
374 | return ds2781_read8(dev_info, control_reg, DS2781_CONTROL); | ||
375 | } | ||
376 | |||
377 | static int ds2781_set_control_register(struct ds2781_device_info *dev_info, | ||
378 | u8 control_reg) | ||
379 | { | ||
380 | int ret; | ||
381 | |||
382 | ret = ds2781_write(dev_info, &control_reg, | ||
383 | DS2781_CONTROL, sizeof(u8)); | ||
384 | if (ret < 0) | ||
385 | return ret; | ||
386 | |||
387 | return ds2781_save_eeprom(dev_info, DS2781_CONTROL); | ||
388 | } | ||
389 | |||
390 | static int ds2781_battery_get_property(struct power_supply *psy, | ||
391 | enum power_supply_property psp, | ||
392 | union power_supply_propval *val) | ||
393 | { | ||
394 | int ret = 0; | ||
395 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
396 | |||
397 | switch (psp) { | ||
398 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
399 | ret = ds2781_get_voltage(dev_info, &val->intval); | ||
400 | break; | ||
401 | |||
402 | case POWER_SUPPLY_PROP_TEMP: | ||
403 | ret = ds2781_get_temperature(dev_info, &val->intval); | ||
404 | break; | ||
405 | |||
406 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
407 | val->strval = model; | ||
408 | break; | ||
409 | |||
410 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
411 | val->strval = manufacturer; | ||
412 | break; | ||
413 | |||
414 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
415 | ret = ds2781_get_current(dev_info, CURRENT_NOW, &val->intval); | ||
416 | break; | ||
417 | |||
418 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
419 | ret = ds2781_get_current(dev_info, CURRENT_AVG, &val->intval); | ||
420 | break; | ||
421 | |||
422 | case POWER_SUPPLY_PROP_STATUS: | ||
423 | ret = ds2781_get_status(dev_info, &val->intval); | ||
424 | break; | ||
425 | |||
426 | case POWER_SUPPLY_PROP_CAPACITY: | ||
427 | ret = ds2781_get_capacity(dev_info, &val->intval); | ||
428 | break; | ||
429 | |||
430 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | ||
431 | ret = ds2781_get_accumulated_current(dev_info, &val->intval); | ||
432 | break; | ||
433 | |||
434 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
435 | ret = ds2781_get_charge_now(dev_info, &val->intval); | ||
436 | break; | ||
437 | |||
438 | default: | ||
439 | ret = -EINVAL; | ||
440 | } | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | static enum power_supply_property ds2781_battery_props[] = { | ||
446 | POWER_SUPPLY_PROP_STATUS, | ||
447 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
448 | POWER_SUPPLY_PROP_TEMP, | ||
449 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
450 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
451 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
452 | POWER_SUPPLY_PROP_CURRENT_AVG, | ||
453 | POWER_SUPPLY_PROP_CAPACITY, | ||
454 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | ||
455 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
456 | }; | ||
457 | |||
458 | static ssize_t ds2781_get_pmod_enabled(struct device *dev, | ||
459 | struct device_attribute *attr, | ||
460 | char *buf) | ||
461 | { | ||
462 | int ret; | ||
463 | u8 control_reg; | ||
464 | struct power_supply *psy = to_power_supply(dev); | ||
465 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
466 | |||
467 | /* Get power mode */ | ||
468 | ret = ds2781_get_control_register(dev_info, &control_reg); | ||
469 | if (ret < 0) | ||
470 | return ret; | ||
471 | |||
472 | return sprintf(buf, "%d\n", | ||
473 | !!(control_reg & DS2781_CONTROL_PMOD)); | ||
474 | } | ||
475 | |||
476 | static ssize_t ds2781_set_pmod_enabled(struct device *dev, | ||
477 | struct device_attribute *attr, | ||
478 | const char *buf, | ||
479 | size_t count) | ||
480 | { | ||
481 | int ret; | ||
482 | u8 control_reg, new_setting; | ||
483 | struct power_supply *psy = to_power_supply(dev); | ||
484 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
485 | |||
486 | /* Set power mode */ | ||
487 | ret = ds2781_get_control_register(dev_info, &control_reg); | ||
488 | if (ret < 0) | ||
489 | return ret; | ||
490 | |||
491 | ret = kstrtou8(buf, 0, &new_setting); | ||
492 | if (ret < 0) | ||
493 | return ret; | ||
494 | |||
495 | if ((new_setting != 0) && (new_setting != 1)) { | ||
496 | dev_err(dev_info->dev, "Invalid pmod setting (0 or 1)\n"); | ||
497 | return -EINVAL; | ||
498 | } | ||
499 | |||
500 | if (new_setting) | ||
501 | control_reg |= DS2781_CONTROL_PMOD; | ||
502 | else | ||
503 | control_reg &= ~DS2781_CONTROL_PMOD; | ||
504 | |||
505 | ret = ds2781_set_control_register(dev_info, control_reg); | ||
506 | if (ret < 0) | ||
507 | return ret; | ||
508 | |||
509 | return count; | ||
510 | } | ||
511 | |||
512 | static ssize_t ds2781_get_sense_resistor_value(struct device *dev, | ||
513 | struct device_attribute *attr, | ||
514 | char *buf) | ||
515 | { | ||
516 | int ret; | ||
517 | u8 sense_resistor; | ||
518 | struct power_supply *psy = to_power_supply(dev); | ||
519 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
520 | |||
521 | ret = ds2781_read8(dev_info, &sense_resistor, DS2781_RSNSP); | ||
522 | if (ret < 0) | ||
523 | return ret; | ||
524 | |||
525 | ret = sprintf(buf, "%d\n", sense_resistor); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | static ssize_t ds2781_set_sense_resistor_value(struct device *dev, | ||
530 | struct device_attribute *attr, | ||
531 | const char *buf, | ||
532 | size_t count) | ||
533 | { | ||
534 | int ret; | ||
535 | u8 new_setting; | ||
536 | struct power_supply *psy = to_power_supply(dev); | ||
537 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
538 | |||
539 | ret = kstrtou8(buf, 0, &new_setting); | ||
540 | if (ret < 0) | ||
541 | return ret; | ||
542 | |||
543 | ret = ds2781_set_sense_register(dev_info, new_setting); | ||
544 | if (ret < 0) | ||
545 | return ret; | ||
546 | |||
547 | return count; | ||
548 | } | ||
549 | |||
550 | static ssize_t ds2781_get_rsgain_setting(struct device *dev, | ||
551 | struct device_attribute *attr, | ||
552 | char *buf) | ||
553 | { | ||
554 | int ret; | ||
555 | u16 rsgain; | ||
556 | struct power_supply *psy = to_power_supply(dev); | ||
557 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
558 | |||
559 | ret = ds2781_get_rsgain_register(dev_info, &rsgain); | ||
560 | if (ret < 0) | ||
561 | return ret; | ||
562 | |||
563 | return sprintf(buf, "%d\n", rsgain); | ||
564 | } | ||
565 | |||
566 | static ssize_t ds2781_set_rsgain_setting(struct device *dev, | ||
567 | struct device_attribute *attr, | ||
568 | const char *buf, | ||
569 | size_t count) | ||
570 | { | ||
571 | int ret; | ||
572 | u16 new_setting; | ||
573 | struct power_supply *psy = to_power_supply(dev); | ||
574 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
575 | |||
576 | ret = kstrtou16(buf, 0, &new_setting); | ||
577 | if (ret < 0) | ||
578 | return ret; | ||
579 | |||
580 | /* Gain can only be from 0 to 1.999 in steps of .001 */ | ||
581 | if (new_setting > 1999) { | ||
582 | dev_err(dev_info->dev, "Invalid rsgain setting (0 - 1999)\n"); | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | |||
586 | ret = ds2781_set_rsgain_register(dev_info, new_setting); | ||
587 | if (ret < 0) | ||
588 | return ret; | ||
589 | |||
590 | return count; | ||
591 | } | ||
592 | |||
593 | static ssize_t ds2781_get_pio_pin(struct device *dev, | ||
594 | struct device_attribute *attr, | ||
595 | char *buf) | ||
596 | { | ||
597 | int ret; | ||
598 | u8 sfr; | ||
599 | struct power_supply *psy = to_power_supply(dev); | ||
600 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
601 | |||
602 | ret = ds2781_read8(dev_info, &sfr, DS2781_SFR); | ||
603 | if (ret < 0) | ||
604 | return ret; | ||
605 | |||
606 | ret = sprintf(buf, "%d\n", sfr & DS2781_SFR_PIOSC); | ||
607 | return ret; | ||
608 | } | ||
609 | |||
610 | static ssize_t ds2781_set_pio_pin(struct device *dev, | ||
611 | struct device_attribute *attr, | ||
612 | const char *buf, | ||
613 | size_t count) | ||
614 | { | ||
615 | int ret; | ||
616 | u8 new_setting; | ||
617 | struct power_supply *psy = to_power_supply(dev); | ||
618 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
619 | |||
620 | ret = kstrtou8(buf, 0, &new_setting); | ||
621 | if (ret < 0) | ||
622 | return ret; | ||
623 | |||
624 | if ((new_setting != 0) && (new_setting != 1)) { | ||
625 | dev_err(dev_info->dev, "Invalid pio_pin setting (0 or 1)\n"); | ||
626 | return -EINVAL; | ||
627 | } | ||
628 | |||
629 | ret = ds2781_write(dev_info, &new_setting, | ||
630 | DS2781_SFR, sizeof(u8)); | ||
631 | if (ret < 0) | ||
632 | return ret; | ||
633 | |||
634 | return count; | ||
635 | } | ||
636 | |||
637 | static ssize_t ds2781_read_param_eeprom_bin(struct file *filp, | ||
638 | struct kobject *kobj, | ||
639 | struct bin_attribute *bin_attr, | ||
640 | char *buf, loff_t off, size_t count) | ||
641 | { | ||
642 | struct device *dev = container_of(kobj, struct device, kobj); | ||
643 | struct power_supply *psy = to_power_supply(dev); | ||
644 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
645 | |||
646 | count = min_t(loff_t, count, | ||
647 | DS2781_EEPROM_BLOCK1_END - | ||
648 | DS2781_EEPROM_BLOCK1_START + 1 - off); | ||
649 | |||
650 | return ds2781_read_block(dev_info, buf, | ||
651 | DS2781_EEPROM_BLOCK1_START + off, count); | ||
652 | } | ||
653 | |||
654 | static ssize_t ds2781_write_param_eeprom_bin(struct file *filp, | ||
655 | struct kobject *kobj, | ||
656 | struct bin_attribute *bin_attr, | ||
657 | char *buf, loff_t off, size_t count) | ||
658 | { | ||
659 | struct device *dev = container_of(kobj, struct device, kobj); | ||
660 | struct power_supply *psy = to_power_supply(dev); | ||
661 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
662 | int ret; | ||
663 | |||
664 | count = min_t(loff_t, count, | ||
665 | DS2781_EEPROM_BLOCK1_END - | ||
666 | DS2781_EEPROM_BLOCK1_START + 1 - off); | ||
667 | |||
668 | ret = ds2781_write(dev_info, buf, | ||
669 | DS2781_EEPROM_BLOCK1_START + off, count); | ||
670 | if (ret < 0) | ||
671 | return ret; | ||
672 | |||
673 | ret = ds2781_save_eeprom(dev_info, DS2781_EEPROM_BLOCK1_START); | ||
674 | if (ret < 0) | ||
675 | return ret; | ||
676 | |||
677 | return count; | ||
678 | } | ||
679 | |||
680 | static struct bin_attribute ds2781_param_eeprom_bin_attr = { | ||
681 | .attr = { | ||
682 | .name = "param_eeprom", | ||
683 | .mode = S_IRUGO | S_IWUSR, | ||
684 | }, | ||
685 | .size = DS2781_EEPROM_BLOCK1_END - DS2781_EEPROM_BLOCK1_START + 1, | ||
686 | .read = ds2781_read_param_eeprom_bin, | ||
687 | .write = ds2781_write_param_eeprom_bin, | ||
688 | }; | ||
689 | |||
690 | static ssize_t ds2781_read_user_eeprom_bin(struct file *filp, | ||
691 | struct kobject *kobj, | ||
692 | struct bin_attribute *bin_attr, | ||
693 | char *buf, loff_t off, size_t count) | ||
694 | { | ||
695 | struct device *dev = container_of(kobj, struct device, kobj); | ||
696 | struct power_supply *psy = to_power_supply(dev); | ||
697 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
698 | |||
699 | count = min_t(loff_t, count, | ||
700 | DS2781_EEPROM_BLOCK0_END - | ||
701 | DS2781_EEPROM_BLOCK0_START + 1 - off); | ||
702 | |||
703 | return ds2781_read_block(dev_info, buf, | ||
704 | DS2781_EEPROM_BLOCK0_START + off, count); | ||
705 | |||
706 | } | ||
707 | |||
708 | static ssize_t ds2781_write_user_eeprom_bin(struct file *filp, | ||
709 | struct kobject *kobj, | ||
710 | struct bin_attribute *bin_attr, | ||
711 | char *buf, loff_t off, size_t count) | ||
712 | { | ||
713 | struct device *dev = container_of(kobj, struct device, kobj); | ||
714 | struct power_supply *psy = to_power_supply(dev); | ||
715 | struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); | ||
716 | int ret; | ||
717 | |||
718 | count = min_t(loff_t, count, | ||
719 | DS2781_EEPROM_BLOCK0_END - | ||
720 | DS2781_EEPROM_BLOCK0_START + 1 - off); | ||
721 | |||
722 | ret = ds2781_write(dev_info, buf, | ||
723 | DS2781_EEPROM_BLOCK0_START + off, count); | ||
724 | if (ret < 0) | ||
725 | return ret; | ||
726 | |||
727 | ret = ds2781_save_eeprom(dev_info, DS2781_EEPROM_BLOCK0_START); | ||
728 | if (ret < 0) | ||
729 | return ret; | ||
730 | |||
731 | return count; | ||
732 | } | ||
733 | |||
734 | static struct bin_attribute ds2781_user_eeprom_bin_attr = { | ||
735 | .attr = { | ||
736 | .name = "user_eeprom", | ||
737 | .mode = S_IRUGO | S_IWUSR, | ||
738 | }, | ||
739 | .size = DS2781_EEPROM_BLOCK0_END - DS2781_EEPROM_BLOCK0_START + 1, | ||
740 | .read = ds2781_read_user_eeprom_bin, | ||
741 | .write = ds2781_write_user_eeprom_bin, | ||
742 | }; | ||
743 | |||
744 | static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2781_get_pmod_enabled, | ||
745 | ds2781_set_pmod_enabled); | ||
746 | static DEVICE_ATTR(sense_resistor_value, S_IRUGO | S_IWUSR, | ||
747 | ds2781_get_sense_resistor_value, ds2781_set_sense_resistor_value); | ||
748 | static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2781_get_rsgain_setting, | ||
749 | ds2781_set_rsgain_setting); | ||
750 | static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2781_get_pio_pin, | ||
751 | ds2781_set_pio_pin); | ||
752 | |||
753 | |||
754 | static struct attribute *ds2781_attributes[] = { | ||
755 | &dev_attr_pmod_enabled.attr, | ||
756 | &dev_attr_sense_resistor_value.attr, | ||
757 | &dev_attr_rsgain_setting.attr, | ||
758 | &dev_attr_pio_pin.attr, | ||
759 | NULL | ||
760 | }; | ||
761 | |||
762 | static const struct attribute_group ds2781_attr_group = { | ||
763 | .attrs = ds2781_attributes, | ||
764 | }; | ||
765 | |||
766 | static int __devinit ds2781_battery_probe(struct platform_device *pdev) | ||
767 | { | ||
768 | int ret = 0; | ||
769 | struct ds2781_device_info *dev_info; | ||
770 | |||
771 | dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); | ||
772 | if (!dev_info) { | ||
773 | ret = -ENOMEM; | ||
774 | goto fail; | ||
775 | } | ||
776 | |||
777 | platform_set_drvdata(pdev, dev_info); | ||
778 | |||
779 | dev_info->dev = &pdev->dev; | ||
780 | dev_info->w1_dev = pdev->dev.parent; | ||
781 | dev_info->bat.name = dev_name(&pdev->dev); | ||
782 | dev_info->bat.type = POWER_SUPPLY_TYPE_BATTERY; | ||
783 | dev_info->bat.properties = ds2781_battery_props; | ||
784 | dev_info->bat.num_properties = ARRAY_SIZE(ds2781_battery_props); | ||
785 | dev_info->bat.get_property = ds2781_battery_get_property; | ||
786 | dev_info->mutex_holder = current; | ||
787 | |||
788 | ret = power_supply_register(&pdev->dev, &dev_info->bat); | ||
789 | if (ret) { | ||
790 | dev_err(dev_info->dev, "failed to register battery\n"); | ||
791 | goto fail_free_info; | ||
792 | } | ||
793 | |||
794 | ret = sysfs_create_group(&dev_info->bat.dev->kobj, &ds2781_attr_group); | ||
795 | if (ret) { | ||
796 | dev_err(dev_info->dev, "failed to create sysfs group\n"); | ||
797 | goto fail_unregister; | ||
798 | } | ||
799 | |||
800 | ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj, | ||
801 | &ds2781_param_eeprom_bin_attr); | ||
802 | if (ret) { | ||
803 | dev_err(dev_info->dev, | ||
804 | "failed to create param eeprom bin file"); | ||
805 | goto fail_remove_group; | ||
806 | } | ||
807 | |||
808 | ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj, | ||
809 | &ds2781_user_eeprom_bin_attr); | ||
810 | if (ret) { | ||
811 | dev_err(dev_info->dev, | ||
812 | "failed to create user eeprom bin file"); | ||
813 | goto fail_remove_bin_file; | ||
814 | } | ||
815 | |||
816 | dev_info->mutex_holder = NULL; | ||
817 | |||
818 | return 0; | ||
819 | |||
820 | fail_remove_bin_file: | ||
821 | sysfs_remove_bin_file(&dev_info->bat.dev->kobj, | ||
822 | &ds2781_param_eeprom_bin_attr); | ||
823 | fail_remove_group: | ||
824 | sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2781_attr_group); | ||
825 | fail_unregister: | ||
826 | power_supply_unregister(&dev_info->bat); | ||
827 | fail_free_info: | ||
828 | kfree(dev_info); | ||
829 | fail: | ||
830 | return ret; | ||
831 | } | ||
832 | |||
833 | static int __devexit ds2781_battery_remove(struct platform_device *pdev) | ||
834 | { | ||
835 | struct ds2781_device_info *dev_info = platform_get_drvdata(pdev); | ||
836 | |||
837 | dev_info->mutex_holder = current; | ||
838 | |||
839 | /* remove attributes */ | ||
840 | sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2781_attr_group); | ||
841 | |||
842 | power_supply_unregister(&dev_info->bat); | ||
843 | |||
844 | kfree(dev_info); | ||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | static struct platform_driver ds2781_battery_driver = { | ||
849 | .driver = { | ||
850 | .name = "ds2781-battery", | ||
851 | }, | ||
852 | .probe = ds2781_battery_probe, | ||
853 | .remove = __devexit_p(ds2781_battery_remove), | ||
854 | }; | ||
855 | |||
856 | static int __init ds2781_battery_init(void) | ||
857 | { | ||
858 | return platform_driver_register(&ds2781_battery_driver); | ||
859 | } | ||
860 | |||
861 | static void __exit ds2781_battery_exit(void) | ||
862 | { | ||
863 | platform_driver_unregister(&ds2781_battery_driver); | ||
864 | } | ||
865 | |||
866 | module_init(ds2781_battery_init); | ||
867 | module_exit(ds2781_battery_exit); | ||
868 | |||
869 | |||
870 | MODULE_LICENSE("GPL"); | ||
871 | MODULE_AUTHOR("Renata Sayakhova <renata@oktetlabs.ru>"); | ||
872 | MODULE_DESCRIPTION("Maxim/Dallas DS2781 Stand-Alone Fuel Gauage IC driver"); | ||
873 | MODULE_ALIAS("platform:ds2781-battery"); | ||
874 | |||
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index d0cb01b42012..eb9e376d6244 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig | |||
@@ -81,6 +81,19 @@ config W1_SLAVE_DS2780 | |||
81 | 81 | ||
82 | If you are unsure, say N. | 82 | If you are unsure, say N. |
83 | 83 | ||
84 | config W1_SLAVE_DS2781 | ||
85 | tristate "Dallas 2781 battery monitor chip" | ||
86 | depends on W1 | ||
87 | help | ||
88 | If you enable this you will have the DS2781 battery monitor | ||
89 | chip support. | ||
90 | |||
91 | The battery monitor chip is used in many batteries/devices | ||
92 | as the one who is responsible for charging/discharging/monitoring | ||
93 | Li+ batteries. | ||
94 | |||
95 | If you are unsure, say N. | ||
96 | |||
84 | config W1_SLAVE_BQ27000 | 97 | config W1_SLAVE_BQ27000 |
85 | tristate "BQ27000 slave support" | 98 | tristate "BQ27000 slave support" |
86 | depends on W1 | 99 | depends on W1 |
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index 1f31e9fb0b25..c4f1859fb520 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile | |||
@@ -10,4 +10,5 @@ obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o | |||
10 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o | 10 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o |
11 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o | 11 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o |
12 | obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o | 12 | obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o |
13 | obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o | ||
13 | obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o | 14 | obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o |
diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c new file mode 100644 index 000000000000..0d0c7985293f --- /dev/null +++ b/drivers/w1/slaves/w1_ds2781.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * 1-Wire implementation for the ds2781 chip | ||
3 | * | ||
4 | * Author: Renata Sayakhova <renata@oktetlabs.ru> | ||
5 | * | ||
6 | * Based on w1-ds2780 driver | ||
7 | * | ||
8 | * 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 | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/idr.h> | ||
21 | |||
22 | #include "../w1.h" | ||
23 | #include "../w1_int.h" | ||
24 | #include "../w1_family.h" | ||
25 | #include "w1_ds2781.h" | ||
26 | |||
27 | static int w1_ds2781_do_io(struct device *dev, char *buf, int addr, | ||
28 | size_t count, int io) | ||
29 | { | ||
30 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
31 | |||
32 | if (addr > DS2781_DATA_SIZE || addr < 0) | ||
33 | return 0; | ||
34 | |||
35 | count = min_t(int, count, DS2781_DATA_SIZE - addr); | ||
36 | |||
37 | if (w1_reset_select_slave(sl) == 0) { | ||
38 | if (io) { | ||
39 | w1_write_8(sl->master, W1_DS2781_WRITE_DATA); | ||
40 | w1_write_8(sl->master, addr); | ||
41 | w1_write_block(sl->master, buf, count); | ||
42 | } else { | ||
43 | w1_write_8(sl->master, W1_DS2781_READ_DATA); | ||
44 | w1_write_8(sl->master, addr); | ||
45 | count = w1_read_block(sl->master, buf, count); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | return count; | ||
50 | } | ||
51 | |||
52 | int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count, | ||
53 | int io) | ||
54 | { | ||
55 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
56 | int ret; | ||
57 | |||
58 | if (!dev) | ||
59 | return -ENODEV; | ||
60 | |||
61 | mutex_lock(&sl->master->mutex); | ||
62 | |||
63 | ret = w1_ds2781_do_io(dev, buf, addr, count, io); | ||
64 | |||
65 | mutex_unlock(&sl->master->mutex); | ||
66 | |||
67 | return ret; | ||
68 | } | ||
69 | EXPORT_SYMBOL(w1_ds2781_io); | ||
70 | |||
71 | int w1_ds2781_io_nolock(struct device *dev, char *buf, int addr, size_t count, | ||
72 | int io) | ||
73 | { | ||
74 | int ret; | ||
75 | |||
76 | if (!dev) | ||
77 | return -ENODEV; | ||
78 | |||
79 | ret = w1_ds2781_do_io(dev, buf, addr, count, io); | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | EXPORT_SYMBOL(w1_ds2781_io_nolock); | ||
84 | |||
85 | int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd) | ||
86 | { | ||
87 | struct w1_slave *sl = container_of(dev, struct w1_slave, dev); | ||
88 | |||
89 | if (!dev) | ||
90 | return -EINVAL; | ||
91 | |||
92 | mutex_lock(&sl->master->mutex); | ||
93 | |||
94 | if (w1_reset_select_slave(sl) == 0) { | ||
95 | w1_write_8(sl->master, cmd); | ||
96 | w1_write_8(sl->master, addr); | ||
97 | } | ||
98 | |||
99 | mutex_unlock(&sl->master->mutex); | ||
100 | return 0; | ||
101 | } | ||
102 | EXPORT_SYMBOL(w1_ds2781_eeprom_cmd); | ||
103 | |||
104 | static ssize_t w1_ds2781_read_bin(struct file *filp, | ||
105 | struct kobject *kobj, | ||
106 | struct bin_attribute *bin_attr, | ||
107 | char *buf, loff_t off, size_t count) | ||
108 | { | ||
109 | struct device *dev = container_of(kobj, struct device, kobj); | ||
110 | return w1_ds2781_io(dev, buf, off, count, 0); | ||
111 | } | ||
112 | |||
113 | static struct bin_attribute w1_ds2781_bin_attr = { | ||
114 | .attr = { | ||
115 | .name = "w1_slave", | ||
116 | .mode = S_IRUGO, | ||
117 | }, | ||
118 | .size = DS2781_DATA_SIZE, | ||
119 | .read = w1_ds2781_read_bin, | ||
120 | }; | ||
121 | |||
122 | static DEFINE_IDA(bat_ida); | ||
123 | |||
124 | static int w1_ds2781_add_slave(struct w1_slave *sl) | ||
125 | { | ||
126 | int ret; | ||
127 | int id; | ||
128 | struct platform_device *pdev; | ||
129 | |||
130 | id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL); | ||
131 | if (id < 0) { | ||
132 | ret = id; | ||
133 | goto noid; | ||
134 | } | ||
135 | |||
136 | pdev = platform_device_alloc("ds2781-battery", id); | ||
137 | if (!pdev) { | ||
138 | ret = -ENOMEM; | ||
139 | goto pdev_alloc_failed; | ||
140 | } | ||
141 | pdev->dev.parent = &sl->dev; | ||
142 | |||
143 | ret = platform_device_add(pdev); | ||
144 | if (ret) | ||
145 | goto pdev_add_failed; | ||
146 | |||
147 | ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2781_bin_attr); | ||
148 | if (ret) | ||
149 | goto bin_attr_failed; | ||
150 | |||
151 | dev_set_drvdata(&sl->dev, pdev); | ||
152 | |||
153 | return 0; | ||
154 | |||
155 | bin_attr_failed: | ||
156 | pdev_add_failed: | ||
157 | platform_device_unregister(pdev); | ||
158 | pdev_alloc_failed: | ||
159 | ida_simple_remove(&bat_ida, id); | ||
160 | noid: | ||
161 | return ret; | ||
162 | } | ||
163 | |||
164 | static void w1_ds2781_remove_slave(struct w1_slave *sl) | ||
165 | { | ||
166 | struct platform_device *pdev = dev_get_drvdata(&sl->dev); | ||
167 | int id = pdev->id; | ||
168 | |||
169 | platform_device_unregister(pdev); | ||
170 | ida_simple_remove(&bat_ida, id); | ||
171 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2781_bin_attr); | ||
172 | } | ||
173 | |||
174 | static struct w1_family_ops w1_ds2781_fops = { | ||
175 | .add_slave = w1_ds2781_add_slave, | ||
176 | .remove_slave = w1_ds2781_remove_slave, | ||
177 | }; | ||
178 | |||
179 | static struct w1_family w1_ds2781_family = { | ||
180 | .fid = W1_FAMILY_DS2781, | ||
181 | .fops = &w1_ds2781_fops, | ||
182 | }; | ||
183 | |||
184 | static int __init w1_ds2781_init(void) | ||
185 | { | ||
186 | ida_init(&bat_ida); | ||
187 | return w1_register_family(&w1_ds2781_family); | ||
188 | } | ||
189 | |||
190 | static void __exit w1_ds2781_exit(void) | ||
191 | { | ||
192 | w1_unregister_family(&w1_ds2781_family); | ||
193 | ida_destroy(&bat_ida); | ||
194 | } | ||
195 | |||
196 | module_init(w1_ds2781_init); | ||
197 | module_exit(w1_ds2781_exit); | ||
198 | |||
199 | MODULE_LICENSE("GPL"); | ||
200 | MODULE_AUTHOR("Renata Sayakhova <renata@oktetlabs.ru>"); | ||
201 | MODULE_DESCRIPTION("1-wire Driver for Maxim/Dallas DS2781 Stand-Alone Fuel Gauge IC"); | ||
diff --git a/drivers/w1/slaves/w1_ds2781.h b/drivers/w1/slaves/w1_ds2781.h new file mode 100644 index 000000000000..82bc66497b43 --- /dev/null +++ b/drivers/w1/slaves/w1_ds2781.h | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * 1-Wire implementation for the ds2780 chip | ||
3 | * | ||
4 | * Author: Renata Sayakhova <renata@oktetlabs.ru> | ||
5 | * | ||
6 | * Based on w1-ds2760 driver | ||
7 | * | ||
8 | * 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 | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _W1_DS2781_H | ||
15 | #define _W1_DS2781_H | ||
16 | |||
17 | /* Function commands */ | ||
18 | #define W1_DS2781_READ_DATA 0x69 | ||
19 | #define W1_DS2781_WRITE_DATA 0x6C | ||
20 | #define W1_DS2781_COPY_DATA 0x48 | ||
21 | #define W1_DS2781_RECALL_DATA 0xB8 | ||
22 | #define W1_DS2781_LOCK 0x6A | ||
23 | |||
24 | /* Register map */ | ||
25 | /* Register 0x00 Reserved */ | ||
26 | #define DS2781_STATUS 0x01 | ||
27 | #define DS2781_RAAC_MSB 0x02 | ||
28 | #define DS2781_RAAC_LSB 0x03 | ||
29 | #define DS2781_RSAC_MSB 0x04 | ||
30 | #define DS2781_RSAC_LSB 0x05 | ||
31 | #define DS2781_RARC 0x06 | ||
32 | #define DS2781_RSRC 0x07 | ||
33 | #define DS2781_IAVG_MSB 0x08 | ||
34 | #define DS2781_IAVG_LSB 0x09 | ||
35 | #define DS2781_TEMP_MSB 0x0A | ||
36 | #define DS2781_TEMP_LSB 0x0B | ||
37 | #define DS2781_VOLT_MSB 0x0C | ||
38 | #define DS2781_VOLT_LSB 0x0D | ||
39 | #define DS2781_CURRENT_MSB 0x0E | ||
40 | #define DS2781_CURRENT_LSB 0x0F | ||
41 | #define DS2781_ACR_MSB 0x10 | ||
42 | #define DS2781_ACR_LSB 0x11 | ||
43 | #define DS2781_ACRL_MSB 0x12 | ||
44 | #define DS2781_ACRL_LSB 0x13 | ||
45 | #define DS2781_AS 0x14 | ||
46 | #define DS2781_SFR 0x15 | ||
47 | #define DS2781_FULL_MSB 0x16 | ||
48 | #define DS2781_FULL_LSB 0x17 | ||
49 | #define DS2781_AE_MSB 0x18 | ||
50 | #define DS2781_AE_LSB 0x19 | ||
51 | #define DS2781_SE_MSB 0x1A | ||
52 | #define DS2781_SE_LSB 0x1B | ||
53 | /* Register 0x1C - 0x1E Reserved */ | ||
54 | #define DS2781_EEPROM 0x1F | ||
55 | #define DS2781_EEPROM_BLOCK0_START 0x20 | ||
56 | /* Register 0x20 - 0x2F User EEPROM */ | ||
57 | #define DS2781_EEPROM_BLOCK0_END 0x2F | ||
58 | /* Register 0x30 - 0x5F Reserved */ | ||
59 | #define DS2781_EEPROM_BLOCK1_START 0x60 | ||
60 | #define DS2781_CONTROL 0x60 | ||
61 | #define DS2781_AB 0x61 | ||
62 | #define DS2781_AC_MSB 0x62 | ||
63 | #define DS2781_AC_LSB 0x63 | ||
64 | #define DS2781_VCHG 0x64 | ||
65 | #define DS2781_IMIN 0x65 | ||
66 | #define DS2781_VAE 0x66 | ||
67 | #define DS2781_IAE 0x67 | ||
68 | #define DS2781_AE_40 0x68 | ||
69 | #define DS2781_RSNSP 0x69 | ||
70 | #define DS2781_FULL_40_MSB 0x6A | ||
71 | #define DS2781_FULL_40_LSB 0x6B | ||
72 | #define DS2781_FULL_4_SLOPE 0x6C | ||
73 | #define DS2781_FULL_3_SLOPE 0x6D | ||
74 | #define DS2781_FULL_2_SLOPE 0x6E | ||
75 | #define DS2781_FULL_1_SLOPE 0x6F | ||
76 | #define DS2781_AE_4_SLOPE 0x70 | ||
77 | #define DS2781_AE_3_SLOPE 0x71 | ||
78 | #define DS2781_AE_2_SLOPE 0x72 | ||
79 | #define DS2781_AE_1_SLOPE 0x73 | ||
80 | #define DS2781_SE_4_SLOPE 0x74 | ||
81 | #define DS2781_SE_3_SLOPE 0x75 | ||
82 | #define DS2781_SE_2_SLOPE 0x76 | ||
83 | #define DS2781_SE_1_SLOPE 0x77 | ||
84 | #define DS2781_RSGAIN_MSB 0x78 | ||
85 | #define DS2781_RSGAIN_LSB 0x79 | ||
86 | #define DS2781_RSTC 0x7A | ||
87 | #define DS2781_COB 0x7B | ||
88 | #define DS2781_TBP34 0x7C | ||
89 | #define DS2781_TBP23 0x7D | ||
90 | #define DS2781_TBP12 0x7E | ||
91 | #define DS2781_EEPROM_BLOCK1_END 0x7F | ||
92 | /* Register 0x7D - 0xFF Reserved */ | ||
93 | |||
94 | #define DS2781_FSGAIN_MSB 0xB0 | ||
95 | #define DS2781_FSGAIN_LSB 0xB1 | ||
96 | |||
97 | /* Number of valid register addresses */ | ||
98 | #define DS2781_DATA_SIZE 0xB2 | ||
99 | |||
100 | /* Status register bits */ | ||
101 | #define DS2781_STATUS_CHGTF (1 << 7) | ||
102 | #define DS2781_STATUS_AEF (1 << 6) | ||
103 | #define DS2781_STATUS_SEF (1 << 5) | ||
104 | #define DS2781_STATUS_LEARNF (1 << 4) | ||
105 | /* Bit 3 Reserved */ | ||
106 | #define DS2781_STATUS_UVF (1 << 2) | ||
107 | #define DS2781_STATUS_PORF (1 << 1) | ||
108 | /* Bit 0 Reserved */ | ||
109 | |||
110 | /* Control register bits */ | ||
111 | /* Bit 7 Reserved */ | ||
112 | #define DS2781_CONTROL_NBEN (1 << 7) | ||
113 | #define DS2781_CONTROL_UVEN (1 << 6) | ||
114 | #define DS2781_CONTROL_PMOD (1 << 5) | ||
115 | #define DS2781_CONTROL_RNAOP (1 << 4) | ||
116 | #define DS1781_CONTROL_UVTH (1 << 3) | ||
117 | /* Bit 0 - 2 Reserved */ | ||
118 | |||
119 | /* Special feature register bits */ | ||
120 | /* Bit 1 - 7 Reserved */ | ||
121 | #define DS2781_SFR_PIOSC (1 << 0) | ||
122 | |||
123 | /* EEPROM register bits */ | ||
124 | #define DS2781_EEPROM_EEC (1 << 7) | ||
125 | #define DS2781_EEPROM_LOCK (1 << 6) | ||
126 | /* Bit 2 - 6 Reserved */ | ||
127 | #define DS2781_EEPROM_BL1 (1 << 1) | ||
128 | #define DS2781_EEPROM_BL0 (1 << 0) | ||
129 | |||
130 | extern int w1_ds2781_io(struct device *dev, char *buf, int addr, size_t count, | ||
131 | int io); | ||
132 | extern int w1_ds2781_io_nolock(struct device *dev, char *buf, int addr, | ||
133 | size_t count, int io); | ||
134 | extern int w1_ds2781_eeprom_cmd(struct device *dev, int addr, int cmd); | ||
135 | |||
136 | #endif /* !_W1_DS2781_H */ | ||
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 490cda2281bc..874aeb05011b 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
@@ -38,6 +38,7 @@ | |||
38 | #define W1_EEPROM_DS2431 0x2D | 38 | #define W1_EEPROM_DS2431 0x2D |
39 | #define W1_FAMILY_DS2760 0x30 | 39 | #define W1_FAMILY_DS2760 0x30 |
40 | #define W1_FAMILY_DS2780 0x32 | 40 | #define W1_FAMILY_DS2780 0x32 |
41 | #define W1_FAMILY_DS2781 0x3D | ||
41 | #define W1_THERM_DS28EA00 0x42 | 42 | #define W1_THERM_DS28EA00 0x42 |
42 | 43 | ||
43 | #define MAXNAMELEN 32 | 44 | #define MAXNAMELEN 32 |