ds2782_battery.c revision bfdb46ce8494eae30dbaae65c81e684e6db6228b
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 * 6bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * Author: Ryan Mallon <ryan@bluewatersys.com> 7bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * 8bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * This program is free software; you can redistribute it and/or modify 9bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * it under the terms of the GNU General Public License version 2 as 10bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * published by the Free Software Foundation. 11bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * 12bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon */ 13bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 14bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/kernel.h> 15bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/module.h> 16bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/types.h> 17bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/errno.h> 18bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/swab.h> 19bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/i2c.h> 20bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/idr.h> 21bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#include <linux/power_supply.h> 22bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 23bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_REG_RARC 0x06 /* Remaining active relative capacity */ 24bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 25bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_REG_VOLT_MSB 0x0c 26bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_REG_TEMP_MSB 0x0a 27bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_REG_CURRENT_MSB 0x0e 28bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 29bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon/* EEPROM Block */ 30bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_REG_RSNSP 0x69 /* Sense resistor value */ 31bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 32bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon/* Current unit measurement in uA for a 1 milli-ohm sense resistor */ 33bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define DS2782_CURRENT_UNITS 1563 34bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 35bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon#define to_ds2782_info(x) container_of(x, struct ds2782_info, battery) 36bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 37bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstruct ds2782_info { 38bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon struct i2c_client *client; 39bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon struct power_supply battery; 40bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int id; 41bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon}; 42bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 43bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic DEFINE_IDR(battery_id); 44bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic DEFINE_MUTEX(battery_lock); 45bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 46bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val) 47bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 48bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int ret; 49bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 50bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = i2c_smbus_read_byte_data(info->client, reg); 51bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret < 0) { 52bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_err(&info->client->dev, "register read failed\n"); 53bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return ret; 54bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 55bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 56bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *val = ret; 57bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 58bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 59bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 60bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb, 61bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon s16 *val) 62bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 63bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int ret; 64bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 65bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = swab16(i2c_smbus_read_word_data(info->client, reg_msb)); 66bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret < 0) { 67bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_err(&info->client->dev, "register read failed\n"); 68bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return ret; 69bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 70bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 71bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *val = ret; 72bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 73bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 74bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 75bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int ds2782_get_temp(struct ds2782_info *info, int *temp) 76bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 77bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon s16 raw; 78bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 79bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 80bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon /* 81bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * Temperature is measured in units of 0.125 degrees celcius, the 82bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * power_supply class measures temperature in tenths of degrees 83bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * celsius. The temperature value is stored as a 10 bit number, plus 84bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * sign in the upper bits of a 16 bit register. 85bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon */ 86bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon err = ds2782_read_reg16(info, DS2782_REG_TEMP_MSB, &raw); 87bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 88bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 89bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *temp = ((raw / 32) * 125) / 100; 90bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 91bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 92bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 93bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int ds2782_get_current(struct ds2782_info *info, int *current_uA) 94bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 95bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int sense_res; 96bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 97bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon u8 sense_res_raw; 98bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon s16 raw; 99bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 100bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon /* 101bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * The units of measurement for current are dependent on the value of 102bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * the sense resistor. 103bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon */ 104bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon err = ds2782_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw); 105bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 106bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 107bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (sense_res_raw == 0) { 108bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_err(&info->client->dev, "sense resistor value is 0\n"); 109bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return -ENXIO; 110bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 111bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon sense_res = 1000 / sense_res_raw; 112bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 113bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n", 114bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon sense_res); 115bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon err = ds2782_read_reg16(info, DS2782_REG_CURRENT_MSB, &raw); 116bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 117bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 118bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res); 119bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 120bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 121bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 122bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA) 123bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 124bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon s16 raw; 125bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 126bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 127bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon /* 128bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * Voltage is measured in units of 4.88mV. The voltage is stored as 129bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon * a 10-bit number plus sign, in the upper bits of a 16-bit register 130bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon */ 131bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon err = ds2782_read_reg16(info, DS2782_REG_VOLT_MSB, &raw); 132bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 133bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 134bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *voltage_uA = (raw / 32) * 4800; 135bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 136bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 137bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 138bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int ds2782_get_capacity(struct ds2782_info *info, int *capacity) 139bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 140bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 141bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon u8 raw; 142bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 143bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon err = ds2782_read_reg(info, DS2782_REG_RARC, &raw); 144bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 145bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 146bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *capacity = raw; 147bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return raw; 148bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 149bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 150bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int ds2782_get_status(struct ds2782_info *info, int *status) 151bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 152bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int err; 153bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int current_uA; 154bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int capacity; 155bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 156bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon err = ds2782_get_current(info, ¤t_uA); 157bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 158bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 159bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 160bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon err = ds2782_get_capacity(info, &capacity); 161bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (err) 162bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return err; 163bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 164bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (capacity == 100) 165bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *status = POWER_SUPPLY_STATUS_FULL; 166bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon else if (current_uA == 0) 167bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *status = POWER_SUPPLY_STATUS_NOT_CHARGING; 168bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon else if (current_uA < 0) 169bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *status = POWER_SUPPLY_STATUS_DISCHARGING; 170bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon else 171bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon *status = POWER_SUPPLY_STATUS_CHARGING; 172bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 173bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 174bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 175bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 176bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int ds2782_battery_get_property(struct power_supply *psy, 177bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon enum power_supply_property prop, 178bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon union power_supply_propval *val) 179bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 180bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon struct ds2782_info *info = to_ds2782_info(psy); 181bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int ret; 182bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 183bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon switch (prop) { 184bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_STATUS: 185bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = ds2782_get_status(info, &val->intval); 186bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 187bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 188bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_CAPACITY: 189bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = ds2782_get_capacity(info, &val->intval); 190bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 191bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 192bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_VOLTAGE_NOW: 193bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = ds2782_get_voltage(info, &val->intval); 194bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 195bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 196bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_CURRENT_NOW: 197bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = ds2782_get_current(info, &val->intval); 198bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 199bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 200bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon case POWER_SUPPLY_PROP_TEMP: 201bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = ds2782_get_temp(info, &val->intval); 202bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon break; 203bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 204bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon default: 205bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = -EINVAL; 206bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 207bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 208bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return ret; 209bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 210bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 211bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic enum power_supply_property ds2782_battery_props[] = { 212bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_STATUS, 213bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_CAPACITY, 214bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_VOLTAGE_NOW, 215bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_CURRENT_NOW, 216bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon POWER_SUPPLY_PROP_TEMP, 217bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon}; 218bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 219bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic void ds2782_power_supply_init(struct power_supply *battery) 220bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 221bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon battery->type = POWER_SUPPLY_TYPE_BATTERY; 222bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon battery->properties = ds2782_battery_props; 223bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon battery->num_properties = ARRAY_SIZE(ds2782_battery_props); 224bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon battery->get_property = ds2782_battery_get_property; 225bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon battery->external_power_changed = NULL; 226bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 227bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 228bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int ds2782_battery_remove(struct i2c_client *client) 229bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 230bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon struct ds2782_info *info = i2c_get_clientdata(client); 231bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 232bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon power_supply_unregister(&info->battery); 233bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon kfree(info->battery.name); 234bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 235bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_lock(&battery_lock); 236bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon idr_remove(&battery_id, info->id); 237bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_unlock(&battery_lock); 238bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 239bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon i2c_set_clientdata(client, info); 240bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 241bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon kfree(info); 242bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 243bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 244bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 245bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int ds2782_battery_probe(struct i2c_client *client, 246bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon const struct i2c_device_id *id) 247bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 248bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon struct ds2782_info *info; 249bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int ret; 250bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon int num; 251bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 252bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon /* Get an ID for this battery */ 253bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = idr_pre_get(&battery_id, GFP_KERNEL); 254bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret == 0) { 255bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = -ENOMEM; 256bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_id; 257bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 258bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 259bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_lock(&battery_lock); 260bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = idr_get_new(&battery_id, client, &num); 261bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_unlock(&battery_lock); 262bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret < 0) 263bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_id; 264bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 265bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon info = kzalloc(sizeof(*info), GFP_KERNEL); 266bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (!info) { 267bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = -ENOMEM; 268bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_info; 269bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 270bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 271bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon info->battery.name = kasprintf(GFP_KERNEL, "ds2782-%d", num); 272bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (!info->battery.name) { 273bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = -ENOMEM; 274bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_name; 275bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 276bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 277bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon i2c_set_clientdata(client, info); 278bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon info->client = client; 279bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ds2782_power_supply_init(&info->battery); 280bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 281bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon ret = power_supply_register(&client->dev, &info->battery); 282bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon if (ret) { 283bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon dev_err(&client->dev, "failed to register battery\n"); 284bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon goto fail_register; 285bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon } 286bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 287bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return 0; 288bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 289bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonfail_register: 290bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon kfree(info->battery.name); 291bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonfail_name: 292bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon i2c_set_clientdata(client, info); 293bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon kfree(info); 294bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonfail_info: 295bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_lock(&battery_lock); 296bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon idr_remove(&battery_id, num); 297bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon mutex_unlock(&battery_lock); 298bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonfail_id: 299bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return ret; 300bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 301bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 302bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic const struct i2c_device_id ds2782_id[] = { 303bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon {"ds2782", 0}, 304bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon {}, 305bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon}; 306bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 307bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic struct i2c_driver ds2782_battery_driver = { 308bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon .driver = { 309bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon .name = "ds2782-battery", 310bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon }, 311bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon .probe = ds2782_battery_probe, 312bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon .remove = ds2782_battery_remove, 313bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon .id_table = ds2782_id, 314bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon}; 315bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 316bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic int __init ds2782_init(void) 317bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 318bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon return i2c_add_driver(&ds2782_battery_driver); 319bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 320bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonmodule_init(ds2782_init); 321bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 322bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonstatic void __exit ds2782_exit(void) 323bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon{ 324bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon i2c_del_driver(&ds2782_battery_driver); 325bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon} 326bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallonmodule_exit(ds2782_exit); 327bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan Mallon 328bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan MallonMODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); 329bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan MallonMODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver"); 330bfdb46ce8494eae30dbaae65c81e684e6db6228bRyan MallonMODULE_LICENSE("GPL"); 331