Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ds2782_battery: Add support for ds2786 battery gas gauge

Signed-off-by: Yulia Vilensky <vilensky@compulab.co.il>
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>

authored by

Yulia Vilensky and committed by
Anton Vorontsov
9b9ade6b 8ef1bb53

+146 -50
+2 -2
drivers/power/Kconfig
··· 65 65 Say Y here to enable support for batteries with ds2760 chip. 66 66 67 67 config BATTERY_DS2782 68 - tristate "DS2782 standalone gas-gauge" 68 + tristate "DS2782/DS2786 standalone gas-gauge" 69 69 depends on I2C 70 70 help 71 - Say Y here to enable support for the DS2782 standalone battery 71 + Say Y here to enable support for the DS2782/DS2786 standalone battery 72 72 gas-gauge. 73 73 74 74 config BATTERY_PMU
+136 -48
drivers/power/ds2782_battery.c
··· 5 5 * 6 6 * Author: Ryan Mallon <ryan@bluewatersys.com> 7 7 * 8 + * DS2786 added by Yulia Vilensky <vilensky@compulab.co.il> 9 + * 8 10 * This program is free software; you can redistribute it and/or modify 9 11 * it under the terms of the GNU General Public License version 2 as 10 12 * published by the Free Software Foundation. ··· 22 20 #include <linux/idr.h> 23 21 #include <linux/power_supply.h> 24 22 #include <linux/slab.h> 23 + #include <linux/ds2782_battery.h> 25 24 26 25 #define DS2782_REG_RARC 0x06 /* Remaining active relative capacity */ 27 26 28 - #define DS2782_REG_VOLT_MSB 0x0c 29 - #define DS2782_REG_TEMP_MSB 0x0a 30 - #define DS2782_REG_CURRENT_MSB 0x0e 27 + #define DS278x_REG_VOLT_MSB 0x0c 28 + #define DS278x_REG_TEMP_MSB 0x0a 29 + #define DS278x_REG_CURRENT_MSB 0x0e 31 30 32 31 /* EEPROM Block */ 33 32 #define DS2782_REG_RSNSP 0x69 /* Sense resistor value */ ··· 36 33 /* Current unit measurement in uA for a 1 milli-ohm sense resistor */ 37 34 #define DS2782_CURRENT_UNITS 1563 38 35 39 - #define to_ds2782_info(x) container_of(x, struct ds2782_info, battery) 36 + #define DS2786_REG_RARC 0x02 /* Remaining active relative capacity */ 40 37 41 - struct ds2782_info { 38 + #define DS2786_CURRENT_UNITS 25 39 + 40 + struct ds278x_info; 41 + 42 + struct ds278x_battery_ops { 43 + int (*get_current)(struct ds278x_info *info, int *current_uA); 44 + int (*get_voltage)(struct ds278x_info *info, int *voltage_uA); 45 + int (*get_capacity)(struct ds278x_info *info, int *capacity_uA); 46 + 47 + }; 48 + 49 + #define to_ds278x_info(x) container_of(x, struct ds278x_info, battery) 50 + 51 + struct ds278x_info { 42 52 struct i2c_client *client; 43 53 struct power_supply battery; 54 + struct ds278x_battery_ops *ops; 44 55 int id; 56 + int rsns; 45 57 }; 46 58 47 59 static DEFINE_IDR(battery_id); 48 60 static DEFINE_MUTEX(battery_lock); 49 61 50 - static inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val) 62 + static inline int ds278x_read_reg(struct ds278x_info *info, int reg, u8 *val) 51 63 { 52 64 int ret; 53 65 ··· 76 58 return 0; 77 59 } 78 60 79 - static inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb, 61 + static inline int ds278x_read_reg16(struct ds278x_info *info, int reg_msb, 80 62 s16 *val) 81 63 { 82 64 int ret; ··· 91 73 return 0; 92 74 } 93 75 94 - static int ds2782_get_temp(struct ds2782_info *info, int *temp) 76 + static int ds278x_get_temp(struct ds278x_info *info, int *temp) 95 77 { 96 78 s16 raw; 97 79 int err; ··· 102 84 * celsius. The temperature value is stored as a 10 bit number, plus 103 85 * sign in the upper bits of a 16 bit register. 104 86 */ 105 - err = ds2782_read_reg16(info, DS2782_REG_TEMP_MSB, &raw); 87 + err = ds278x_read_reg16(info, DS278x_REG_TEMP_MSB, &raw); 106 88 if (err) 107 89 return err; 108 90 *temp = ((raw / 32) * 125) / 100; 109 91 return 0; 110 92 } 111 93 112 - static int ds2782_get_current(struct ds2782_info *info, int *current_uA) 94 + static int ds2782_get_current(struct ds278x_info *info, int *current_uA) 113 95 { 114 96 int sense_res; 115 97 int err; ··· 120 102 * The units of measurement for current are dependent on the value of 121 103 * the sense resistor. 122 104 */ 123 - err = ds2782_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw); 105 + err = ds278x_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw); 124 106 if (err) 125 107 return err; 126 108 if (sense_res_raw == 0) { ··· 131 113 132 114 dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n", 133 115 sense_res); 134 - err = ds2782_read_reg16(info, DS2782_REG_CURRENT_MSB, &raw); 116 + err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw); 135 117 if (err) 136 118 return err; 137 119 *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res); 138 120 return 0; 139 121 } 140 122 141 - static int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA) 123 + static int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uA) 142 124 { 143 125 s16 raw; 144 126 int err; ··· 147 129 * Voltage is measured in units of 4.88mV. The voltage is stored as 148 130 * a 10-bit number plus sign, in the upper bits of a 16-bit register 149 131 */ 150 - err = ds2782_read_reg16(info, DS2782_REG_VOLT_MSB, &raw); 132 + err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); 151 133 if (err) 152 134 return err; 153 135 *voltage_uA = (raw / 32) * 4800; 154 136 return 0; 155 137 } 156 138 157 - static int ds2782_get_capacity(struct ds2782_info *info, int *capacity) 139 + static int ds2782_get_capacity(struct ds278x_info *info, int *capacity) 158 140 { 159 141 int err; 160 142 u8 raw; 161 143 162 - err = ds2782_read_reg(info, DS2782_REG_RARC, &raw); 144 + err = ds278x_read_reg(info, DS2782_REG_RARC, &raw); 163 145 if (err) 164 146 return err; 165 147 *capacity = raw; 166 148 return raw; 167 149 } 168 150 169 - static int ds2782_get_status(struct ds2782_info *info, int *status) 151 + static int ds2786_get_current(struct ds278x_info *info, int *current_uA) 152 + { 153 + int err; 154 + s16 raw; 155 + 156 + err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw); 157 + if (err) 158 + return err; 159 + *current_uA = (raw / 16) * (DS2786_CURRENT_UNITS / info->rsns); 160 + return 0; 161 + } 162 + 163 + static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uA) 164 + { 165 + s16 raw; 166 + int err; 167 + 168 + /* 169 + * Voltage is measured in units of 1.22mV. The voltage is stored as 170 + * a 10-bit number plus sign, in the upper bits of a 16-bit register 171 + */ 172 + err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); 173 + if (err) 174 + return err; 175 + *voltage_uA = (raw / 8) * 1220; 176 + return 0; 177 + } 178 + 179 + static int ds2786_get_capacity(struct ds278x_info *info, int *capacity) 180 + { 181 + int err; 182 + u8 raw; 183 + 184 + err = ds278x_read_reg(info, DS2786_REG_RARC, &raw); 185 + if (err) 186 + return err; 187 + /* Relative capacity is displayed with resolution 0.5 % */ 188 + *capacity = raw/2 ; 189 + return 0; 190 + } 191 + 192 + static int ds278x_get_status(struct ds278x_info *info, int *status) 170 193 { 171 194 int err; 172 195 int current_uA; 173 196 int capacity; 174 197 175 - err = ds2782_get_current(info, &current_uA); 198 + err = info->ops->get_current(info, &current_uA); 176 199 if (err) 177 200 return err; 178 201 179 - err = ds2782_get_capacity(info, &capacity); 202 + err = info->ops->get_capacity(info, &capacity); 180 203 if (err) 181 204 return err; 182 205 ··· 233 174 return 0; 234 175 } 235 176 236 - static int ds2782_battery_get_property(struct power_supply *psy, 177 + static int ds278x_battery_get_property(struct power_supply *psy, 237 178 enum power_supply_property prop, 238 179 union power_supply_propval *val) 239 180 { 240 - struct ds2782_info *info = to_ds2782_info(psy); 181 + struct ds278x_info *info = to_ds278x_info(psy); 241 182 int ret; 242 183 243 184 switch (prop) { 244 185 case POWER_SUPPLY_PROP_STATUS: 245 - ret = ds2782_get_status(info, &val->intval); 186 + ret = ds278x_get_status(info, &val->intval); 246 187 break; 247 188 248 189 case POWER_SUPPLY_PROP_CAPACITY: 249 - ret = ds2782_get_capacity(info, &val->intval); 190 + ret = info->ops->get_capacity(info, &val->intval); 250 191 break; 251 192 252 193 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 253 - ret = ds2782_get_voltage(info, &val->intval); 194 + ret = info->ops->get_voltage(info, &val->intval); 254 195 break; 255 196 256 197 case POWER_SUPPLY_PROP_CURRENT_NOW: 257 - ret = ds2782_get_current(info, &val->intval); 198 + ret = info->ops->get_current(info, &val->intval); 258 199 break; 259 200 260 201 case POWER_SUPPLY_PROP_TEMP: 261 - ret = ds2782_get_temp(info, &val->intval); 202 + ret = ds278x_get_temp(info, &val->intval); 262 203 break; 263 204 264 205 default: ··· 268 209 return ret; 269 210 } 270 211 271 - static enum power_supply_property ds2782_battery_props[] = { 212 + static enum power_supply_property ds278x_battery_props[] = { 272 213 POWER_SUPPLY_PROP_STATUS, 273 214 POWER_SUPPLY_PROP_CAPACITY, 274 215 POWER_SUPPLY_PROP_VOLTAGE_NOW, ··· 276 217 POWER_SUPPLY_PROP_TEMP, 277 218 }; 278 219 279 - static void ds2782_power_supply_init(struct power_supply *battery) 220 + static void ds278x_power_supply_init(struct power_supply *battery) 280 221 { 281 222 battery->type = POWER_SUPPLY_TYPE_BATTERY; 282 - battery->properties = ds2782_battery_props; 283 - battery->num_properties = ARRAY_SIZE(ds2782_battery_props); 284 - battery->get_property = ds2782_battery_get_property; 223 + battery->properties = ds278x_battery_props; 224 + battery->num_properties = ARRAY_SIZE(ds278x_battery_props); 225 + battery->get_property = ds278x_battery_get_property; 285 226 battery->external_power_changed = NULL; 286 227 } 287 228 288 - static int ds2782_battery_remove(struct i2c_client *client) 229 + static int ds278x_battery_remove(struct i2c_client *client) 289 230 { 290 - struct ds2782_info *info = i2c_get_clientdata(client); 231 + struct ds278x_info *info = i2c_get_clientdata(client); 291 232 292 233 power_supply_unregister(&info->battery); 293 234 kfree(info->battery.name); ··· 300 241 return 0; 301 242 } 302 243 303 - static int ds2782_battery_probe(struct i2c_client *client, 244 + static struct ds278x_battery_ops ds278x_ops[] = { 245 + [0] = { 246 + .get_current = ds2782_get_current, 247 + .get_voltage = ds2782_get_voltage, 248 + .get_capacity = ds2782_get_capacity, 249 + }, 250 + [1] = { 251 + .get_current = ds2786_get_current, 252 + .get_voltage = ds2786_get_voltage, 253 + .get_capacity = ds2786_get_capacity, 254 + } 255 + }; 256 + 257 + static int ds278x_battery_probe(struct i2c_client *client, 304 258 const struct i2c_device_id *id) 305 259 { 306 - struct ds2782_info *info; 260 + struct ds278x_platform_data *pdata = client->dev.platform_data; 261 + struct ds278x_info *info; 307 262 int ret; 308 263 int num; 264 + 265 + /* 266 + * ds2786 should have the sense resistor value set 267 + * in the platform data 268 + */ 269 + if (id->driver_data == 1 && !pdata) { 270 + dev_err(&client->dev, "missing platform data for ds2786\n"); 271 + return -EINVAL; 272 + } 309 273 310 274 /* Get an ID for this battery */ 311 275 ret = idr_pre_get(&battery_id, GFP_KERNEL); ··· 349 267 goto fail_info; 350 268 } 351 269 352 - info->battery.name = kasprintf(GFP_KERNEL, "ds2782-%d", num); 270 + info->battery.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num); 353 271 if (!info->battery.name) { 354 272 ret = -ENOMEM; 355 273 goto fail_name; 356 274 } 357 275 276 + if (id->driver_data == 1) 277 + info->rsns = pdata->rsns; 278 + 358 279 i2c_set_clientdata(client, info); 359 280 info->client = client; 360 - ds2782_power_supply_init(&info->battery); 281 + info->id = num; 282 + info->ops = &ds278x_ops[id->driver_data]; 283 + ds278x_power_supply_init(&info->battery); 361 284 362 285 ret = power_supply_register(&client->dev, &info->battery); 363 286 if (ret) { ··· 384 297 return ret; 385 298 } 386 299 387 - static const struct i2c_device_id ds2782_id[] = { 300 + static const struct i2c_device_id ds278x_id[] = { 388 301 {"ds2782", 0}, 302 + {"ds2786", 1}, 389 303 {}, 390 304 }; 391 305 392 - static struct i2c_driver ds2782_battery_driver = { 306 + static struct i2c_driver ds278x_battery_driver = { 393 307 .driver = { 394 308 .name = "ds2782-battery", 395 309 }, 396 - .probe = ds2782_battery_probe, 397 - .remove = ds2782_battery_remove, 398 - .id_table = ds2782_id, 310 + .probe = ds278x_battery_probe, 311 + .remove = ds278x_battery_remove, 312 + .id_table = ds278x_id, 399 313 }; 400 314 401 - static int __init ds2782_init(void) 315 + static int __init ds278x_init(void) 402 316 { 403 - return i2c_add_driver(&ds2782_battery_driver); 317 + return i2c_add_driver(&ds278x_battery_driver); 404 318 } 405 - module_init(ds2782_init); 319 + module_init(ds278x_init); 406 320 407 - static void __exit ds2782_exit(void) 321 + static void __exit ds278x_exit(void) 408 322 { 409 - i2c_del_driver(&ds2782_battery_driver); 323 + i2c_del_driver(&ds278x_battery_driver); 410 324 } 411 - module_exit(ds2782_exit); 325 + module_exit(ds278x_exit); 412 326 413 327 MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); 414 328 MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver");
+8
include/linux/ds2782_battery.h
··· 1 + #ifndef __LINUX_DS2782_BATTERY_H 2 + #define __LINUX_DS2782_BATTERY_H 3 + 4 + struct ds278x_platform_data { 5 + int rsns; 6 + }; 7 + 8 + #endif