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