ds2782_battery.c revision 05e2cefab4acb5ae9b54266935eeec32cc5269ea
1bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon/* 2bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * I2C client/driver for the Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC 3bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * 4bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * Copyright (C) 2009 Bluewater Systems Ltd 5bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * 61c5454eed85af71df9c01ab923e0c1b841b2e99bRyan Mallon * Author: Ryan Mallon 7bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * 89b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky * DS2786 added by Yulia Vilensky <vilensky@compulab.co.il> 99b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky * 107cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov * UEvent sending added by Evgeny Romanov <romanov@neurosoft.ru> 117cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov * 12bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * This program is free software; you can redistribute it and/or modify 13bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * it under the terms of the GNU General Public License version 2 as 14bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * published by the Free Software Foundation. 15bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * 16bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon */ 17bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 18bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/kernel.h> 19bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/module.h> 20bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/types.h> 21bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/errno.h> 22bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/swab.h> 23bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/i2c.h> 247cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov#include <linux/delay.h> 25bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/idr.h> 26bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/power_supply.h> 275a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 289b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky#include <linux/ds2782_battery.h> 29bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 30bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_REG_RARC 0x06 /* Remaining active relative capacity */ 31bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 329b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky#define DS278x_REG_VOLT_MSB 0x0c 339b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky#define DS278x_REG_TEMP_MSB 0x0a 349b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky#define DS278x_REG_CURRENT_MSB 0x0e 35bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 36bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon/* EEPROM Block */ 37bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_REG_RSNSP 0x69 /* Sense resistor value */ 38bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 39bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon/* Current unit measurement in uA for a 1 milli-ohm sense resistor */ 40bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_CURRENT_UNITS 1563 41bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 429b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky#define DS2786_REG_RARC 0x02 /* Remaining active relative capacity */ 439b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 449b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky#define DS2786_CURRENT_UNITS 25 459b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 467cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov#define DS278x_DELAY 1000 477cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 489b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystruct ds278x_info; 499b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 509b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystruct ds278x_battery_ops { 51eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe int (*get_battery_current)(struct ds278x_info *info, int *current_uA); 52353f867b5536e55e46801562987d605778cf262bRyan Mallon int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uV); 53353f867b5536e55e46801562987d605778cf262bRyan Mallon int (*get_battery_capacity)(struct ds278x_info *info, int *capacity); 549b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky}; 559b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 569b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky#define to_ds278x_info(x) container_of(x, struct ds278x_info, battery) 57bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 589b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystruct ds278x_info { 59bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon struct i2c_client *client; 60bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon struct power_supply battery; 619b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky struct ds278x_battery_ops *ops; 627cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov struct delayed_work bat_work; 63bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int id; 649b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky int rsns; 657cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov int capacity; 667cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov int status; /* State Of Charge */ 67bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon}; 68bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 69bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic DEFINE_IDR(battery_id); 70bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic DEFINE_MUTEX(battery_lock); 71bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 729b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic inline int ds278x_read_reg(struct ds278x_info *info, int reg, u8 *val) 73bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 74bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int ret; 75bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 76bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = i2c_smbus_read_byte_data(info->client, reg); 77bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret < 0) { 78bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_err(&info->client->dev, "register read failed\n"); 79bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return ret; 80bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 81bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 82bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *val = ret; 83bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 84bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 85bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 869b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic inline int ds278x_read_reg16(struct ds278x_info *info, int reg_msb, 87bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon s16 *val) 88bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 89bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int ret; 90bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 918511748ba1ab83a7d89d802a50335115358a8cfcDan Carpenter ret = i2c_smbus_read_word_data(info->client, reg_msb); 92bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret < 0) { 93bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_err(&info->client->dev, "register read failed\n"); 94bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return ret; 95bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 96bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 978511748ba1ab83a7d89d802a50335115358a8cfcDan Carpenter *val = swab16(ret); 98bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 99bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 100bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 1019b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds278x_get_temp(struct ds278x_info *info, int *temp) 102bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 103bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon s16 raw; 104bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 105bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 106bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon /* 107bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * Temperature is measured in units of 0.125 degrees celcius, the 108bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * power_supply class measures temperature in tenths of degrees 109bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * celsius. The temperature value is stored as a 10 bit number, plus 110bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * sign in the upper bits of a 16 bit register. 111bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon */ 1129b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky err = ds278x_read_reg16(info, DS278x_REG_TEMP_MSB, &raw); 113bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 114bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 115bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *temp = ((raw / 32) * 125) / 100; 116bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 117bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 118bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 1199b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds2782_get_current(struct ds278x_info *info, int *current_uA) 120bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 121bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int sense_res; 122bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 123bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon u8 sense_res_raw; 124bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon s16 raw; 125bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 126bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon /* 127bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * The units of measurement for current are dependent on the value of 128bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * the sense resistor. 129bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon */ 1309b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky err = ds278x_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw); 131bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 132bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 133bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (sense_res_raw == 0) { 134bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_err(&info->client->dev, "sense resistor value is 0\n"); 135bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return -ENXIO; 136bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 137bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon sense_res = 1000 / sense_res_raw; 138bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 139bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n", 140bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon sense_res); 1419b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw); 142bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 143bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 144bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res); 145bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 146bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 147bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 148353f867b5536e55e46801562987d605778cf262bRyan Mallonstatic int ds2782_get_voltage(struct ds278x_info *info, int *voltage_uV) 149bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 150bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon s16 raw; 151bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 152bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 153bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon /* 154bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * Voltage is measured in units of 4.88mV. The voltage is stored as 155bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * a 10-bit number plus sign, in the upper bits of a 16-bit register 156bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon */ 1579b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); 158bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 159bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 160353f867b5536e55e46801562987d605778cf262bRyan Mallon *voltage_uV = (raw / 32) * 4800; 161bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 162bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 163bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 1649b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds2782_get_capacity(struct ds278x_info *info, int *capacity) 165bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 166bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 167bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon u8 raw; 168bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 1699b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky err = ds278x_read_reg(info, DS2782_REG_RARC, &raw); 170bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 171bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 172bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *capacity = raw; 1732d31757c87a741823f77daaa07eeb8d56be63943Ryan Mallon return 0; 174bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 175bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 1769b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds2786_get_current(struct ds278x_info *info, int *current_uA) 1779b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky{ 1789b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky int err; 1799b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky s16 raw; 1809b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 1819b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky err = ds278x_read_reg16(info, DS278x_REG_CURRENT_MSB, &raw); 1829b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky if (err) 1839b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky return err; 1849b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky *current_uA = (raw / 16) * (DS2786_CURRENT_UNITS / info->rsns); 1859b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky return 0; 1869b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky} 1879b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 188353f867b5536e55e46801562987d605778cf262bRyan Mallonstatic int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV) 1899b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky{ 1909b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky s16 raw; 1919b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky int err; 1929b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 1939b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky /* 1949b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky * Voltage is measured in units of 1.22mV. The voltage is stored as 1959b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky * a 10-bit number plus sign, in the upper bits of a 16-bit register 1969b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky */ 1979b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); 1989b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky if (err) 1999b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky return err; 200353f867b5536e55e46801562987d605778cf262bRyan Mallon *voltage_uV = (raw / 8) * 1220; 2019b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky return 0; 2029b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky} 2039b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 2049b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds2786_get_capacity(struct ds278x_info *info, int *capacity) 2059b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky{ 2069b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky int err; 2079b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky u8 raw; 2089b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 2099b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky err = ds278x_read_reg(info, DS2786_REG_RARC, &raw); 2109b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky if (err) 2119b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky return err; 2129b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky /* Relative capacity is displayed with resolution 0.5 % */ 2139b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky *capacity = raw/2 ; 2149b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky return 0; 2159b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky} 2169b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 2179b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds278x_get_status(struct ds278x_info *info, int *status) 218bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 219bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 220bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int current_uA; 221bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int capacity; 222bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 223eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe err = info->ops->get_battery_current(info, ¤t_uA); 224bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 225bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 226bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 227eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe err = info->ops->get_battery_capacity(info, &capacity); 228bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 229bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 230bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 2317cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov info->capacity = capacity; 2327cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 233bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (capacity == 100) 234bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *status = POWER_SUPPLY_STATUS_FULL; 235bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon else if (current_uA == 0) 236bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *status = POWER_SUPPLY_STATUS_NOT_CHARGING; 237bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon else if (current_uA < 0) 238bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *status = POWER_SUPPLY_STATUS_DISCHARGING; 239bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon else 240bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *status = POWER_SUPPLY_STATUS_CHARGING; 241bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 242bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 243bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 244bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 2459b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds278x_battery_get_property(struct power_supply *psy, 246bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon enum power_supply_property prop, 247bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon union power_supply_propval *val) 248bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 2499b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky struct ds278x_info *info = to_ds278x_info(psy); 250bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int ret; 251bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 252bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon switch (prop) { 253bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_STATUS: 2549b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky ret = ds278x_get_status(info, &val->intval); 255bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 256bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 257bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_CAPACITY: 258eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe ret = info->ops->get_battery_capacity(info, &val->intval); 259bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 260bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 261bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_VOLTAGE_NOW: 262eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe ret = info->ops->get_battery_voltage(info, &val->intval); 263bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 264bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 265bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_CURRENT_NOW: 266eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe ret = info->ops->get_battery_current(info, &val->intval); 267bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 268bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 269bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_TEMP: 2709b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky ret = ds278x_get_temp(info, &val->intval); 271bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 272bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 273bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon default: 274bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = -EINVAL; 275bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 276bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 277bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return ret; 278bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 279bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 2807cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanovstatic void ds278x_bat_update(struct ds278x_info *info) 2817cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov{ 2827cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov int old_status = info->status; 2837cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov int old_capacity = info->capacity; 2847cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 2857cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov ds278x_get_status(info, &info->status); 2867cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 2877cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov if ((old_status != info->status) || (old_capacity != info->capacity)) 2887cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov power_supply_changed(&info->battery); 2897cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov} 2907cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 2917cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanovstatic void ds278x_bat_work(struct work_struct *work) 2927cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov{ 2937cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov struct ds278x_info *info; 2947cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 2957cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov info = container_of(work, struct ds278x_info, bat_work.work); 2967cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov ds278x_bat_update(info); 2977cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 2987cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov schedule_delayed_work(&info->bat_work, DS278x_DELAY); 2997cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov} 3007cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3019b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic enum power_supply_property ds278x_battery_props[] = { 302bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_STATUS, 303bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_CAPACITY, 304bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_VOLTAGE_NOW, 305bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_CURRENT_NOW, 306bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_TEMP, 307bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon}; 308bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 3099b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic void ds278x_power_supply_init(struct power_supply *battery) 310bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 311bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon battery->type = POWER_SUPPLY_TYPE_BATTERY; 3129b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky battery->properties = ds278x_battery_props; 3139b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky battery->num_properties = ARRAY_SIZE(ds278x_battery_props); 3149b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky battery->get_property = ds278x_battery_get_property; 315bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon battery->external_power_changed = NULL; 316bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 317bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 3189b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds278x_battery_remove(struct i2c_client *client) 319bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 3209b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky struct ds278x_info *info = i2c_get_clientdata(client); 321bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 322bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon power_supply_unregister(&info->battery); 323bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon kfree(info->battery.name); 324bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 325bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_lock(&battery_lock); 326bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon idr_remove(&battery_id, info->id); 327bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_unlock(&battery_lock); 328bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 3297cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov cancel_delayed_work(&info->bat_work); 3307cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 331bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon kfree(info); 332bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 333bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 334bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 3357cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov#ifdef CONFIG_PM 3367cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3377cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanovstatic int ds278x_suspend(struct i2c_client *client, 3387cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov pm_message_t state) 3397cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov{ 3407cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov struct ds278x_info *info = i2c_get_clientdata(client); 3417cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3427cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov cancel_delayed_work(&info->bat_work); 3437cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov return 0; 3447cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov} 3457cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3467cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanovstatic int ds278x_resume(struct i2c_client *client) 3477cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov{ 3487cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov struct ds278x_info *info = i2c_get_clientdata(client); 3497cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3507cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov schedule_delayed_work(&info->bat_work, DS278x_DELAY); 3517cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov return 0; 3527cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov} 3537cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3547cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov#else 3557cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3567cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov#define ds278x_suspend NULL 3577cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov#define ds278x_resume NULL 3587cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3597cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov#endif /* CONFIG_PM */ 3607cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 3617cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 362ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsovenum ds278x_num_id { 363ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov DS2782 = 0, 364ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov DS2786, 365ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov}; 366ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov 3679b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic struct ds278x_battery_ops ds278x_ops[] = { 368ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov [DS2782] = { 369eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe .get_battery_current = ds2782_get_current, 370eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe .get_battery_voltage = ds2782_get_voltage, 371eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe .get_battery_capacity = ds2782_get_capacity, 3729b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky }, 373ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov [DS2786] = { 374eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe .get_battery_current = ds2786_get_current, 375eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe .get_battery_voltage = ds2786_get_voltage, 376eb9650d6d989f24f21232a055d8fd45f1a9dcf99Peter Huewe .get_battery_capacity = ds2786_get_capacity, 3779b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky } 3789b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky}; 3799b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 3809b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic int ds278x_battery_probe(struct i2c_client *client, 381bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon const struct i2c_device_id *id) 382bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 3839b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky struct ds278x_platform_data *pdata = client->dev.platform_data; 3849b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky struct ds278x_info *info; 385bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int ret; 386bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int num; 387bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 3889b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky /* 3899b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky * ds2786 should have the sense resistor value set 3909b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky * in the platform data 3919b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky */ 392ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov if (id->driver_data == DS2786 && !pdata) { 3939b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky dev_err(&client->dev, "missing platform data for ds2786\n"); 3949b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky return -EINVAL; 3959b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky } 3969b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 397bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon /* Get an ID for this battery */ 398bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_lock(&battery_lock); 39905e2cefab4acb5ae9b54266935eeec32cc5269eaTejun Heo ret = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL); 400bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_unlock(&battery_lock); 401bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret < 0) 402bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_id; 40305e2cefab4acb5ae9b54266935eeec32cc5269eaTejun Heo num = ret; 404bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 405bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon info = kzalloc(sizeof(*info), GFP_KERNEL); 406bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (!info) { 407bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = -ENOMEM; 408bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_info; 409bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 410bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 4119b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky info->battery.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num); 412bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (!info->battery.name) { 413bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = -ENOMEM; 414bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_name; 415bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 416bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 417ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov if (id->driver_data == DS2786) 4189b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky info->rsns = pdata->rsns; 4199b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky 420bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon i2c_set_clientdata(client, info); 421bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon info->client = client; 4229b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky info->id = num; 4239b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky info->ops = &ds278x_ops[id->driver_data]; 4249b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky ds278x_power_supply_init(&info->battery); 425bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 4267cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov info->capacity = 100; 4277cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov info->status = POWER_SUPPLY_STATUS_FULL; 4287cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 4297cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov INIT_DELAYED_WORK(&info->bat_work, ds278x_bat_work); 4307cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov 431bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = power_supply_register(&client->dev, &info->battery); 432bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret) { 433bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_err(&client->dev, "failed to register battery\n"); 434bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_register; 4357cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov } else { 4367cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov schedule_delayed_work(&info->bat_work, DS278x_DELAY); 437bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 438bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 439bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 440bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 441bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonfail_register: 442bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon kfree(info->battery.name); 443bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonfail_name: 444bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon kfree(info); 445bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonfail_info: 446bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_lock(&battery_lock); 447bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon idr_remove(&battery_id, num); 448bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_unlock(&battery_lock); 449bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonfail_id: 450bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return ret; 451bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 452bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 4539b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic const struct i2c_device_id ds278x_id[] = { 454ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov {"ds2782", DS2782}, 455ab6cc8f9b716a3d0a41b42cd81d392183211a7f2Anton Vorontsov {"ds2786", DS2786}, 456bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon {}, 457bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon}; 45884ab16f54bbde67c8c2aabc36b034c91044935cbAxel LinMODULE_DEVICE_TABLE(i2c, ds278x_id); 459bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 4609b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilenskystatic struct i2c_driver ds278x_battery_driver = { 461bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon .driver = { 462bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon .name = "ds2782-battery", 463bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon }, 4649b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky .probe = ds278x_battery_probe, 4659b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky .remove = ds278x_battery_remove, 4667cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov .suspend = ds278x_suspend, 4677cee9aefda78019b6e7c42fcf3600b9fd8aeb8d5Evgeny Romanov .resume = ds278x_resume, 4689b9ade6b612e562c4a5bd02ef38cc32e10f3f9baYulia Vilensky .id_table = ds278x_id, 469bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon}; 4705ff92e7ab3591299089cfba440acb4d2ba8ab92fAxel Linmodule_i2c_driver(ds278x_battery_driver); 471bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 4721c5454eed85af71df9c01ab923e0c1b841b2e99bRyan MallonMODULE_AUTHOR("Ryan Mallon"); 473bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan MallonMODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver"); 474bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan MallonMODULE_LICENSE("GPL"); 475