1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * 1-wire client/driver for the Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC |
4 | * |
5 | * Copyright (C) 2010 Indesign, LLC |
6 | * |
7 | * Author: Clifton Barnes <cabarnes@indesign-llc.com> |
8 | * |
9 | * Based on ds2760_battery and ds2782_battery drivers |
10 | */ |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/param.h> |
15 | #include <linux/pm.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/power_supply.h> |
18 | #include <linux/idr.h> |
19 | |
20 | #include <linux/w1.h> |
21 | #include "../../w1/slaves/w1_ds2780.h" |
22 | |
23 | /* Current unit measurement in uA for a 1 milli-ohm sense resistor */ |
24 | #define DS2780_CURRENT_UNITS 1563 |
25 | /* Charge unit measurement in uAh for a 1 milli-ohm sense resistor */ |
26 | #define DS2780_CHARGE_UNITS 6250 |
27 | /* Number of bytes in user EEPROM space */ |
28 | #define DS2780_USER_EEPROM_SIZE (DS2780_EEPROM_BLOCK0_END - \ |
29 | DS2780_EEPROM_BLOCK0_START + 1) |
30 | /* Number of bytes in parameter EEPROM space */ |
31 | #define DS2780_PARAM_EEPROM_SIZE (DS2780_EEPROM_BLOCK1_END - \ |
32 | DS2780_EEPROM_BLOCK1_START + 1) |
33 | |
34 | struct ds2780_device_info { |
35 | struct device *dev; |
36 | struct power_supply *bat; |
37 | struct power_supply_desc bat_desc; |
38 | struct device *w1_dev; |
39 | }; |
40 | |
41 | enum current_types { |
42 | CURRENT_NOW, |
43 | CURRENT_AVG, |
44 | }; |
45 | |
46 | static const char model[] = "DS2780" ; |
47 | static const char manufacturer[] = "Maxim/Dallas" ; |
48 | |
49 | static inline struct ds2780_device_info * |
50 | to_ds2780_device_info(struct power_supply *psy) |
51 | { |
52 | return power_supply_get_drvdata(psy); |
53 | } |
54 | |
55 | static inline int ds2780_battery_io(struct ds2780_device_info *dev_info, |
56 | char *buf, int addr, size_t count, int io) |
57 | { |
58 | return w1_ds2780_io(dev: dev_info->w1_dev, buf, addr, count, io); |
59 | } |
60 | |
61 | static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val, |
62 | int addr) |
63 | { |
64 | return ds2780_battery_io(dev_info, buf: val, addr, count: sizeof(u8), io: 0); |
65 | } |
66 | |
67 | static int ds2780_read16(struct ds2780_device_info *dev_info, s16 *val, |
68 | int addr) |
69 | { |
70 | int ret; |
71 | u8 raw[2]; |
72 | |
73 | ret = ds2780_battery_io(dev_info, buf: raw, addr, count: sizeof(raw), io: 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 ds2780_device_info *dev_info, |
83 | u8 *val, int addr, size_t count) |
84 | { |
85 | return ds2780_battery_io(dev_info, buf: val, addr, count, io: 0); |
86 | } |
87 | |
88 | static inline int ds2780_write(struct ds2780_device_info *dev_info, u8 *val, |
89 | int addr, size_t count) |
90 | { |
91 | return ds2780_battery_io(dev_info, buf: val, addr, count, io: 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: dev_info->w1_dev, addr: reg); |
109 | if (ret < 0) |
110 | return ret; |
111 | |
112 | ret = ds2780_recall_eeprom(dev: dev_info->w1_dev, addr: 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, val: &conductance, |
126 | DS2780_RSNSP_REG, count: 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, val: 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, val: raw, |
148 | DS2780_RSGAIN_MSB_REG, count: sizeof(raw)); |
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 complement 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, val: &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 complement 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, val: &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, val: &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 -EINVAL; |
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 complement 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, val: ¤t_raw, addr: 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, val: &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, val: ¤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, val: &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, type: CURRENT_NOW, current_uA: ¤t_uA); |
315 | if (ret < 0) |
316 | return ret; |
317 | |
318 | ret = ds2780_get_capacity(dev_info, capacity: &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, val: &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, val: 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, val: &control_reg, |
368 | DS2780_CONTROL_REG, count: 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, voltage_uV: &val->intval); |
385 | break; |
386 | |
387 | case POWER_SUPPLY_PROP_TEMP: |
388 | ret = ds2780_get_temperature(dev_info, temperature: &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, type: CURRENT_NOW, current_uA: &val->intval); |
401 | break; |
402 | |
403 | case POWER_SUPPLY_PROP_CURRENT_AVG: |
404 | ret = ds2780_get_current(dev_info, type: CURRENT_AVG, current_uA: &val->intval); |
405 | break; |
406 | |
407 | case POWER_SUPPLY_PROP_STATUS: |
408 | ret = ds2780_get_status(dev_info, status: &val->intval); |
409 | break; |
410 | |
411 | case POWER_SUPPLY_PROP_CAPACITY: |
412 | ret = ds2780_get_capacity(dev_info, capacity: &val->intval); |
413 | break; |
414 | |
415 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: |
416 | ret = ds2780_get_accumulated_current(dev_info, accumulated_current: &val->intval); |
417 | break; |
418 | |
419 | case POWER_SUPPLY_PROP_CHARGE_NOW: |
420 | ret = ds2780_get_charge_now(dev_info, charge_now: &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: &control_reg); |
454 | if (ret < 0) |
455 | return ret; |
456 | |
457 | return sysfs_emit(buf, fmt: "%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: &control_reg); |
473 | if (ret < 0) |
474 | return ret; |
475 | |
476 | ret = kstrtou8(s: buf, base: 0, res: &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, val: &sense_resistor, DS2780_RSNSP_REG); |
507 | if (ret < 0) |
508 | return ret; |
509 | |
510 | ret = sysfs_emit(buf, fmt: "%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(s: buf, base: 0, res: &new_setting); |
525 | if (ret < 0) |
526 | return ret; |
527 | |
528 | ret = ds2780_set_sense_register(dev_info, conductance: 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: &rsgain); |
545 | if (ret < 0) |
546 | return ret; |
547 | |
548 | return sysfs_emit(buf, fmt: "%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(s: buf, base: 0, res: &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, rsgain: 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, val: &sfr, DS2780_SFR_REG); |
588 | if (ret < 0) |
589 | return ret; |
590 | |
591 | ret = sysfs_emit(buf, fmt: "%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(s: buf, base: 0, res: &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, val: &new_setting, |
615 | DS2780_SFR_REG, count: 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 = kobj_to_dev(kobj); |
628 | struct power_supply *psy = to_power_supply(dev); |
629 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); |
630 | |
631 | return ds2780_read_block(dev_info, val: buf, |
632 | DS2780_EEPROM_BLOCK1_START + off, count); |
633 | } |
634 | |
635 | static ssize_t ds2780_write_param_eeprom_bin(struct file *filp, |
636 | struct kobject *kobj, |
637 | struct bin_attribute *bin_attr, |
638 | char *buf, loff_t off, size_t count) |
639 | { |
640 | struct device *dev = kobj_to_dev(kobj); |
641 | struct power_supply *psy = to_power_supply(dev); |
642 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); |
643 | int ret; |
644 | |
645 | ret = ds2780_write(dev_info, val: buf, |
646 | DS2780_EEPROM_BLOCK1_START + off, count); |
647 | if (ret < 0) |
648 | return ret; |
649 | |
650 | ret = ds2780_save_eeprom(dev_info, DS2780_EEPROM_BLOCK1_START); |
651 | if (ret < 0) |
652 | return ret; |
653 | |
654 | return count; |
655 | } |
656 | |
657 | static struct bin_attribute ds2780_param_eeprom_bin_attr = { |
658 | .attr = { |
659 | .name = "param_eeprom" , |
660 | .mode = S_IRUGO | S_IWUSR, |
661 | }, |
662 | .size = DS2780_PARAM_EEPROM_SIZE, |
663 | .read = ds2780_read_param_eeprom_bin, |
664 | .write = ds2780_write_param_eeprom_bin, |
665 | }; |
666 | |
667 | static ssize_t ds2780_read_user_eeprom_bin(struct file *filp, |
668 | struct kobject *kobj, |
669 | struct bin_attribute *bin_attr, |
670 | char *buf, loff_t off, size_t count) |
671 | { |
672 | struct device *dev = kobj_to_dev(kobj); |
673 | struct power_supply *psy = to_power_supply(dev); |
674 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); |
675 | |
676 | return ds2780_read_block(dev_info, val: buf, |
677 | DS2780_EEPROM_BLOCK0_START + off, count); |
678 | } |
679 | |
680 | static ssize_t ds2780_write_user_eeprom_bin(struct file *filp, |
681 | struct kobject *kobj, |
682 | struct bin_attribute *bin_attr, |
683 | char *buf, loff_t off, size_t count) |
684 | { |
685 | struct device *dev = kobj_to_dev(kobj); |
686 | struct power_supply *psy = to_power_supply(dev); |
687 | struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); |
688 | int ret; |
689 | |
690 | ret = ds2780_write(dev_info, val: buf, |
691 | DS2780_EEPROM_BLOCK0_START + off, count); |
692 | if (ret < 0) |
693 | return ret; |
694 | |
695 | ret = ds2780_save_eeprom(dev_info, DS2780_EEPROM_BLOCK0_START); |
696 | if (ret < 0) |
697 | return ret; |
698 | |
699 | return count; |
700 | } |
701 | |
702 | static struct bin_attribute ds2780_user_eeprom_bin_attr = { |
703 | .attr = { |
704 | .name = "user_eeprom" , |
705 | .mode = S_IRUGO | S_IWUSR, |
706 | }, |
707 | .size = DS2780_USER_EEPROM_SIZE, |
708 | .read = ds2780_read_user_eeprom_bin, |
709 | .write = ds2780_write_user_eeprom_bin, |
710 | }; |
711 | |
712 | static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2780_get_pmod_enabled, |
713 | ds2780_set_pmod_enabled); |
714 | static DEVICE_ATTR(sense_resistor_value, S_IRUGO | S_IWUSR, |
715 | ds2780_get_sense_resistor_value, ds2780_set_sense_resistor_value); |
716 | static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2780_get_rsgain_setting, |
717 | ds2780_set_rsgain_setting); |
718 | static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2780_get_pio_pin, |
719 | ds2780_set_pio_pin); |
720 | |
721 | static struct attribute *ds2780_sysfs_attrs[] = { |
722 | &dev_attr_pmod_enabled.attr, |
723 | &dev_attr_sense_resistor_value.attr, |
724 | &dev_attr_rsgain_setting.attr, |
725 | &dev_attr_pio_pin.attr, |
726 | NULL |
727 | }; |
728 | |
729 | static struct bin_attribute *ds2780_sysfs_bin_attrs[] = { |
730 | &ds2780_param_eeprom_bin_attr, |
731 | &ds2780_user_eeprom_bin_attr, |
732 | NULL |
733 | }; |
734 | |
735 | static const struct attribute_group ds2780_sysfs_group = { |
736 | .attrs = ds2780_sysfs_attrs, |
737 | .bin_attrs = ds2780_sysfs_bin_attrs, |
738 | }; |
739 | |
740 | static const struct attribute_group *ds2780_sysfs_groups[] = { |
741 | &ds2780_sysfs_group, |
742 | NULL, |
743 | }; |
744 | |
745 | static int ds2780_battery_probe(struct platform_device *pdev) |
746 | { |
747 | struct power_supply_config psy_cfg = {}; |
748 | struct ds2780_device_info *dev_info; |
749 | |
750 | dev_info = devm_kzalloc(dev: &pdev->dev, size: sizeof(*dev_info), GFP_KERNEL); |
751 | if (!dev_info) |
752 | return -ENOMEM; |
753 | |
754 | platform_set_drvdata(pdev, data: dev_info); |
755 | |
756 | dev_info->dev = &pdev->dev; |
757 | dev_info->w1_dev = pdev->dev.parent; |
758 | dev_info->bat_desc.name = dev_name(dev: &pdev->dev); |
759 | dev_info->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; |
760 | dev_info->bat_desc.properties = ds2780_battery_props; |
761 | dev_info->bat_desc.num_properties = ARRAY_SIZE(ds2780_battery_props); |
762 | dev_info->bat_desc.get_property = ds2780_battery_get_property; |
763 | |
764 | psy_cfg.drv_data = dev_info; |
765 | psy_cfg.attr_grp = ds2780_sysfs_groups; |
766 | |
767 | dev_info->bat = devm_power_supply_register(parent: &pdev->dev, |
768 | desc: &dev_info->bat_desc, |
769 | cfg: &psy_cfg); |
770 | if (IS_ERR(ptr: dev_info->bat)) { |
771 | dev_err(dev_info->dev, "failed to register battery\n" ); |
772 | return PTR_ERR(ptr: dev_info->bat); |
773 | } |
774 | |
775 | return 0; |
776 | } |
777 | |
778 | static struct platform_driver ds2780_battery_driver = { |
779 | .driver = { |
780 | .name = "ds2780-battery" , |
781 | }, |
782 | .probe = ds2780_battery_probe, |
783 | }; |
784 | |
785 | module_platform_driver(ds2780_battery_driver); |
786 | |
787 | MODULE_LICENSE("GPL" ); |
788 | MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>" ); |
789 | MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC driver" ); |
790 | MODULE_ALIAS("platform:ds2780-battery" ); |
791 | |