ds2760_battery.c revision 02d0d2758821c38b2601d34dac544140af09e651
1fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov/* 2fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * Driver for batteries with DS2760 chips inside. 3fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * 4fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * Copyright © 2007 Anton Vorontsov 5fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * 2004-2007 Matt Reimer 6fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * 2004 Szabolcs Gyurko 7fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * 8fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * Use consistent with the GNU GPL is permitted, 9fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * provided that this copyright notice is 10fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * preserved in its entirety in all copies and derived works. 11fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * 12fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * Author: Anton Vorontsov <cbou@mail.ru> 13fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * February 2007 14fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * 15fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * Matt Reimer <mreimer@vpop.net> 16fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * April 2004, 2005, 2007 17fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * 18fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> 19fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * September 2004 20fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov */ 21fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 22fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include <linux/module.h> 23fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include <linux/param.h> 24fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include <linux/jiffies.h> 25fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include <linux/workqueue.h> 26fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include <linux/pm.h> 27fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include <linux/platform_device.h> 28fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include <linux/power_supply.h> 29fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 30fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include "../w1/w1.h" 31fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#include "../w1/slaves/w1_ds2760.h" 32fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 33fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstruct ds2760_device_info { 34fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct device *dev; 35fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 36fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* DS2760 data, valid after calling ds2760_battery_read_status() */ 37fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov unsigned long update_time; /* jiffies when data read */ 38fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov char raw[DS2760_DATA_SIZE]; /* raw DS2760 data */ 39fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int voltage_raw; /* units of 4.88 mV */ 40fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int voltage_uV; /* units of µV */ 41fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int current_raw; /* units of 0.625 mA */ 42fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int current_uA; /* units of µA */ 43fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int accum_current_raw; /* units of 0.25 mAh */ 44fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int accum_current_uAh; /* units of µAh */ 45fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int temp_raw; /* units of 0.125 °C */ 46fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int temp_C; /* units of 0.1 °C */ 47fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int rated_capacity; /* units of µAh */ 48fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int rem_capacity; /* percentage */ 49fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int full_active_uAh; /* units of µAh */ 50fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int empty_uAh; /* units of µAh */ 51fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int life_sec; /* units of seconds */ 52fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int charge_status; /* POWER_SUPPLY_STATUS_* */ 53fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 54fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int full_counter; 55fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct power_supply bat; 56fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct device *w1_dev; 57fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct workqueue_struct *monitor_wqueue; 58fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct delayed_work monitor_work; 59fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov}; 60fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 61fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic unsigned int cache_time = 1000; 62fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovmodule_param(cache_time, uint, 0644); 63fe0e3153acfef4864b69932cf116eb5f38f7500cAnton VorontsovMODULE_PARM_DESC(cache_time, "cache time in milliseconds"); 64fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 65cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mackstatic unsigned int pmod_enabled; 66cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mackmodule_param(pmod_enabled, bool, 0644); 67cef437e3a9b6d229d4ed3730cde047007267df6dDaniel MackMODULE_PARM_DESC(pmod_enabled, "PMOD enable bit"); 68cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack 69c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mackstatic unsigned int rated_capacity; 70c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mackmodule_param(rated_capacity, uint, 0644); 71c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel MackMODULE_PARM_DESC(rated_capacity, "rated battery capacity, 10*mAh or index"); 72c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack 7302d0d2758821c38b2601d34dac544140af09e651Daniel Mackstatic unsigned int current_accum; 7402d0d2758821c38b2601d34dac544140af09e651Daniel Mackmodule_param(current_accum, uint, 0644); 7502d0d2758821c38b2601d34dac544140af09e651Daniel MackMODULE_PARM_DESC(current_accum, "current accumulator value"); 7602d0d2758821c38b2601d34dac544140af09e651Daniel Mack 77fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov/* Some batteries have their rated capacity stored a N * 10 mAh, while 78fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * others use an index into this table. */ 79fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int rated_capacities[] = { 80fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 0, 81fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 920, /* Samsung */ 82fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 920, /* BYD */ 83fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 920, /* Lishen */ 84fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 920, /* NEC */ 85fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 1440, /* Samsung */ 86fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 1440, /* BYD */ 87fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 1440, /* Lishen */ 88fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 1440, /* NEC */ 89fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 2880, /* Samsung */ 90fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 2880, /* BYD */ 91fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 2880, /* Lishen */ 92fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 2880 /* NEC */ 93fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov}; 94fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 95fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov/* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C 96fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * temp is in Celsius */ 97fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int battery_interpolate(int array[], int temp) 98fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 99fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int index, dt; 100fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 101fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (temp <= 0) 102fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return array[0]; 103fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (temp >= 40) 104fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return array[4]; 105fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 106fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov index = temp / 10; 107fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov dt = temp % 10; 108fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 109fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return array[index] + (((array[index + 1] - array[index]) * dt) / 10); 110fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 111fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 112fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int ds2760_battery_read_status(struct ds2760_device_info *di) 113fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 114fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int ret, i, start, count, scale[5]; 115fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 116fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->update_time && time_before(jiffies, di->update_time + 117fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov msecs_to_jiffies(cache_time))) 118fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return 0; 119fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 120fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* The first time we read the entire contents of SRAM/EEPROM, 121fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * but after that we just read the interesting bits that change. */ 122fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->update_time == 0) { 123fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov start = 0; 124fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov count = DS2760_DATA_SIZE; 125fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } else { 126fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov start = DS2760_VOLTAGE_MSB; 127fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov count = DS2760_TEMP_LSB - start + 1; 128fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 129fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 130fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count); 131fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (ret != count) { 132fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n", 133fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->w1_dev); 134fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return 1; 135fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 136fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 137fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->update_time = jiffies; 138fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 139fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* DS2760 reports voltage in units of 4.88mV, but the battery class 140fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * reports in units of uV, so convert by multiplying by 4880. */ 141fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) | 142fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov (di->raw[DS2760_VOLTAGE_LSB] >> 5); 143fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->voltage_uV = di->voltage_raw * 4880; 144fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 145fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* DS2760 reports current in signed units of 0.625mA, but the battery 146fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * class reports in units of µA, so convert by multiplying by 625. */ 147fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->current_raw = 148fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) | 149fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov (di->raw[DS2760_CURRENT_LSB] >> 3); 150fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->current_uA = di->current_raw * 625; 151fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 152fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* DS2760 reports accumulated current in signed units of 0.25mAh. */ 153fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->accum_current_raw = 154fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) | 155fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->raw[DS2760_CURRENT_ACCUM_LSB]; 156fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->accum_current_uAh = di->accum_current_raw * 250; 157fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 158fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* DS2760 reports temperature in signed units of 0.125°C, but the 159fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * battery class reports in units of 1/10 °C, so we convert by 160fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * multiplying by .125 * 10 = 1.25. */ 161fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) | 162fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov (di->raw[DS2760_TEMP_LSB] >> 5); 163fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->temp_C = di->temp_raw + (di->temp_raw / 4); 164fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 165fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* At least some battery monitors (e.g. HP iPAQ) store the battery's 166fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * maximum rated capacity. */ 167fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities)) 168fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->rated_capacity = rated_capacities[ 169fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov (unsigned int)di->raw[DS2760_RATED_CAPACITY]]; 170fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov else 171fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10; 172fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 173fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->rated_capacity *= 1000; /* convert to µAh */ 174fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 175fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* Calculate the full level at the present temperature. */ 176fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 | 177fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->raw[DS2760_ACTIVE_FULL + 1]; 178fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 17925f2bfa62ae77820a8185734c4a2ab7f3971a2fcDaniel Mack /* If the full_active_uAh value is not given, fall back to the rated 18025f2bfa62ae77820a8185734c4a2ab7f3971a2fcDaniel Mack * capacity. This is likely to happen when chips are not part of the 18125f2bfa62ae77820a8185734c4a2ab7f3971a2fcDaniel Mack * battery pack and is therefore not bootstrapped. */ 18225f2bfa62ae77820a8185734c4a2ab7f3971a2fcDaniel Mack if (di->full_active_uAh == 0) 18325f2bfa62ae77820a8185734c4a2ab7f3971a2fcDaniel Mack di->full_active_uAh = di->rated_capacity / 1000L; 18425f2bfa62ae77820a8185734c4a2ab7f3971a2fcDaniel Mack 18525f2bfa62ae77820a8185734c4a2ab7f3971a2fcDaniel Mack scale[0] = di->full_active_uAh; 186fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov for (i = 1; i < 5; i++) 187fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i]; 188fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 189fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10); 190fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->full_active_uAh *= 1000; /* convert to µAh */ 191fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 192fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* Calculate the empty level at the present temperature. */ 193fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4]; 194fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov for (i = 3; i >= 0; i--) 195fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i]; 196fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 197fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->empty_uAh = battery_interpolate(scale, di->temp_C / 10); 198fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->empty_uAh *= 1000; /* convert to µAh */ 199fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 200a4e3f91b98d86ae0b5c816fe45190bb29ac32f71Daniel Mack if (di->full_active_uAh == di->empty_uAh) 201a4e3f91b98d86ae0b5c816fe45190bb29ac32f71Daniel Mack di->rem_capacity = 0; 202a4e3f91b98d86ae0b5c816fe45190bb29ac32f71Daniel Mack else 203a4e3f91b98d86ae0b5c816fe45190bb29ac32f71Daniel Mack /* From Maxim Application Note 131: remaining capacity = 204a4e3f91b98d86ae0b5c816fe45190bb29ac32f71Daniel Mack * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */ 205a4e3f91b98d86ae0b5c816fe45190bb29ac32f71Daniel Mack di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) / 206a4e3f91b98d86ae0b5c816fe45190bb29ac32f71Daniel Mack (di->full_active_uAh - di->empty_uAh); 207fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 208fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->rem_capacity < 0) 209fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->rem_capacity = 0; 210fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->rem_capacity > 100) 211fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->rem_capacity = 100; 212fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 213fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->current_uA) 214fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 215fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 3600L) / di->current_uA; 216fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov else 217fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->life_sec = 0; 218fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 219fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return 0; 220fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 221fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 22202d0d2758821c38b2601d34dac544140af09e651Daniel Mackstatic void ds2760_battery_set_current_accum(struct ds2760_device_info *di, 22302d0d2758821c38b2601d34dac544140af09e651Daniel Mack unsigned int acr_val) 22402d0d2758821c38b2601d34dac544140af09e651Daniel Mack{ 22502d0d2758821c38b2601d34dac544140af09e651Daniel Mack unsigned char acr[2]; 22602d0d2758821c38b2601d34dac544140af09e651Daniel Mack 22702d0d2758821c38b2601d34dac544140af09e651Daniel Mack /* acr is in units of 0.25 mAh */ 22802d0d2758821c38b2601d34dac544140af09e651Daniel Mack acr_val *= 4L; 22902d0d2758821c38b2601d34dac544140af09e651Daniel Mack acr_val /= 1000; 23002d0d2758821c38b2601d34dac544140af09e651Daniel Mack 23102d0d2758821c38b2601d34dac544140af09e651Daniel Mack acr[0] = acr_val >> 8; 23202d0d2758821c38b2601d34dac544140af09e651Daniel Mack acr[1] = acr_val & 0xff; 23302d0d2758821c38b2601d34dac544140af09e651Daniel Mack 23402d0d2758821c38b2601d34dac544140af09e651Daniel Mack if (w1_ds2760_write(di->w1_dev, acr, DS2760_CURRENT_ACCUM_MSB, 2) < 2) 23502d0d2758821c38b2601d34dac544140af09e651Daniel Mack dev_warn(di->dev, "ACR write failed\n"); 23602d0d2758821c38b2601d34dac544140af09e651Daniel Mack} 23702d0d2758821c38b2601d34dac544140af09e651Daniel Mack 238fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic void ds2760_battery_update_status(struct ds2760_device_info *di) 239fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 240fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int old_charge_status = di->charge_status; 241fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 242fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov ds2760_battery_read_status(di); 243fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 244fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN) 245fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->full_counter = 0; 246fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 247fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (power_supply_am_i_supplied(&di->bat)) { 248fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->current_uA > 10000) { 249fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status = POWER_SUPPLY_STATUS_CHARGING; 250fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->full_counter = 0; 251fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } else if (di->current_uA < -5000) { 252fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING) 253fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov dev_notice(di->dev, "not enough power to " 254fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov "charge\n"); 255fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING; 256fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->full_counter = 0; 257fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } else if (di->current_uA < 10000 && 258fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status != POWER_SUPPLY_STATUS_FULL) { 259fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 260fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov /* Don't consider the battery to be full unless 261fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * we've seen the current < 10 mA at least two 262fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov * consecutive times. */ 263fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 264fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->full_counter++; 265fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 266fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->full_counter < 2) { 267fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status = POWER_SUPPLY_STATUS_CHARGING; 268fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } else { 269fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status = POWER_SUPPLY_STATUS_FULL; 27002d0d2758821c38b2601d34dac544140af09e651Daniel Mack ds2760_battery_set_current_accum(di, 27102d0d2758821c38b2601d34dac544140af09e651Daniel Mack di->full_active_uAh); 272fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 273fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 274fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } else { 275fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING; 276fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->full_counter = 0; 277fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 278fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 279fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (di->charge_status != old_charge_status) 280fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov power_supply_changed(&di->bat); 281fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 282fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 283cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mackstatic void ds2760_battery_write_status(struct ds2760_device_info *di, 284cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack char status) 285cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack{ 286cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack if (status == di->raw[DS2760_STATUS_REG]) 287cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack return; 288cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack 289cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack w1_ds2760_write(di->w1_dev, &status, DS2760_STATUS_WRITE_REG, 1); 290cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); 291cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); 292cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack} 293cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack 294c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mackstatic void ds2760_battery_write_rated_capacity(struct ds2760_device_info *di, 295c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack unsigned char rated_capacity) 296c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack{ 297c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack if (rated_capacity == di->raw[DS2760_RATED_CAPACITY]) 298c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack return; 299c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack 300c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack w1_ds2760_write(di->w1_dev, &rated_capacity, DS2760_RATED_CAPACITY, 1); 301c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack w1_ds2760_store_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); 302c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack w1_ds2760_recall_eeprom(di->w1_dev, DS2760_EEPROM_BLOCK1); 303c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack} 304c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack 305fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic void ds2760_battery_work(struct work_struct *work) 306fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 307fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct ds2760_device_info *di = container_of(work, 308fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct ds2760_device_info, monitor_work.work); 309fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov const int interval = HZ * 60; 310fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 3110cddc0a906ee3e47ce3e09107d385ff89f87cd6dHarvey Harrison dev_dbg(di->dev, "%s\n", __func__); 312fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 313fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov ds2760_battery_update_status(di); 314fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval); 315fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 316fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 317fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \ 318fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov bat); 319fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 320fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic void ds2760_battery_external_power_changed(struct power_supply *psy) 321fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 322fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct ds2760_device_info *di = to_ds2760_device_info(psy); 323fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 3240cddc0a906ee3e47ce3e09107d385ff89f87cd6dHarvey Harrison dev_dbg(di->dev, "%s\n", __func__); 325fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 326fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov cancel_delayed_work(&di->monitor_work); 327fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10); 328fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 329fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 330fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int ds2760_battery_get_property(struct power_supply *psy, 331fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov enum power_supply_property psp, 332fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov union power_supply_propval *val) 333fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 334fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct ds2760_device_info *di = to_ds2760_device_info(psy); 335fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 336fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov switch (psp) { 337fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov case POWER_SUPPLY_PROP_STATUS: 338fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov val->intval = di->charge_status; 339fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return 0; 340fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov default: 341fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov break; 342fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 343fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 344fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov ds2760_battery_read_status(di); 345fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 346fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov switch (psp) { 347fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov case POWER_SUPPLY_PROP_VOLTAGE_NOW: 348fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov val->intval = di->voltage_uV; 349fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov break; 350fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov case POWER_SUPPLY_PROP_CURRENT_NOW: 351fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov val->intval = di->current_uA; 352fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov break; 353fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 354fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov val->intval = di->rated_capacity; 355fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov break; 356fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov case POWER_SUPPLY_PROP_CHARGE_FULL: 357fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov val->intval = di->full_active_uAh; 358fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov break; 359fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov case POWER_SUPPLY_PROP_CHARGE_EMPTY: 360fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov val->intval = di->empty_uAh; 361fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov break; 362fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov case POWER_SUPPLY_PROP_CHARGE_NOW: 363fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov val->intval = di->accum_current_uAh; 364fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov break; 365fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov case POWER_SUPPLY_PROP_TEMP: 366fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov val->intval = di->temp_C; 367fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov break; 3685c6e9bf2c96e746237516bc8897add67682ee452Daniel Mack case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: 3695c6e9bf2c96e746237516bc8897add67682ee452Daniel Mack val->intval = di->life_sec; 3705c6e9bf2c96e746237516bc8897add67682ee452Daniel Mack break; 3715c6e9bf2c96e746237516bc8897add67682ee452Daniel Mack case POWER_SUPPLY_PROP_CAPACITY: 3725c6e9bf2c96e746237516bc8897add67682ee452Daniel Mack val->intval = di->rem_capacity; 3735c6e9bf2c96e746237516bc8897add67682ee452Daniel Mack break; 374fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov default: 375fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return -EINVAL; 376fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 377fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 378fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return 0; 379fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 380fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 381fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic enum power_supply_property ds2760_battery_props[] = { 382fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov POWER_SUPPLY_PROP_STATUS, 383fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov POWER_SUPPLY_PROP_VOLTAGE_NOW, 384fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov POWER_SUPPLY_PROP_CURRENT_NOW, 385fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 386fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov POWER_SUPPLY_PROP_CHARGE_FULL, 387fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov POWER_SUPPLY_PROP_CHARGE_EMPTY, 388fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov POWER_SUPPLY_PROP_CHARGE_NOW, 389fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov POWER_SUPPLY_PROP_TEMP, 3905c6e9bf2c96e746237516bc8897add67682ee452Daniel Mack POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 3915c6e9bf2c96e746237516bc8897add67682ee452Daniel Mack POWER_SUPPLY_PROP_CAPACITY, 392fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov}; 393fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 394fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int ds2760_battery_probe(struct platform_device *pdev) 395fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 396cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack char status; 397fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov int retval = 0; 398fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct ds2760_device_info *di; 399fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 400fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di = kzalloc(sizeof(*di), GFP_KERNEL); 401fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (!di) { 402fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov retval = -ENOMEM; 403fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov goto di_alloc_failed; 404fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 405fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 406fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov platform_set_drvdata(pdev, di); 407fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 408ae9fb6e814ecede683bcd404910085cea3ab1260Daniel Mack di->dev = &pdev->dev; 409ae9fb6e814ecede683bcd404910085cea3ab1260Daniel Mack di->w1_dev = pdev->dev.parent; 410ae9fb6e814ecede683bcd404910085cea3ab1260Daniel Mack di->bat.name = dev_name(&pdev->dev); 411ae9fb6e814ecede683bcd404910085cea3ab1260Daniel Mack di->bat.type = POWER_SUPPLY_TYPE_BATTERY; 412ae9fb6e814ecede683bcd404910085cea3ab1260Daniel Mack di->bat.properties = ds2760_battery_props; 413ae9fb6e814ecede683bcd404910085cea3ab1260Daniel Mack di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props); 414ae9fb6e814ecede683bcd404910085cea3ab1260Daniel Mack di->bat.get_property = ds2760_battery_get_property; 415fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->bat.external_power_changed = 416fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov ds2760_battery_external_power_changed; 417fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 418fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; 419fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 420cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack /* enable sleep mode feature */ 421cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack ds2760_battery_read_status(di); 422cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack status = di->raw[DS2760_STATUS_REG]; 423cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack if (pmod_enabled) 424cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack status |= DS2760_STATUS_PMOD; 425cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack else 426cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack status &= ~DS2760_STATUS_PMOD; 427cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack 428cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack ds2760_battery_write_status(di, status); 429cef437e3a9b6d229d4ed3730cde047007267df6dDaniel Mack 430c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack /* set rated capacity from module param */ 431c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack if (rated_capacity) 432c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack ds2760_battery_write_rated_capacity(di, rated_capacity); 433c1e72193ea3fa02e96bf3aa66006e18d107d0266Daniel Mack 43402d0d2758821c38b2601d34dac544140af09e651Daniel Mack /* set current accumulator if given as parameter. 43502d0d2758821c38b2601d34dac544140af09e651Daniel Mack * this should only be done for bootstrapping the value */ 43602d0d2758821c38b2601d34dac544140af09e651Daniel Mack if (current_accum) 43702d0d2758821c38b2601d34dac544140af09e651Daniel Mack ds2760_battery_set_current_accum(di, current_accum); 43802d0d2758821c38b2601d34dac544140af09e651Daniel Mack 4392e83a5c5d2317c386de2880eb43ef0bef8eb1fa9Daniel Mack retval = power_supply_register(&pdev->dev, &di->bat); 4402e83a5c5d2317c386de2880eb43ef0bef8eb1fa9Daniel Mack if (retval) { 4412e83a5c5d2317c386de2880eb43ef0bef8eb1fa9Daniel Mack dev_err(di->dev, "failed to register battery\n"); 4422e83a5c5d2317c386de2880eb43ef0bef8eb1fa9Daniel Mack goto batt_failed; 4432e83a5c5d2317c386de2880eb43ef0bef8eb1fa9Daniel Mack } 4442e83a5c5d2317c386de2880eb43ef0bef8eb1fa9Daniel Mack 445fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work); 446ba88b0029fcdc39d23acd4d0e64b38145ffa4d5fKay Sievers di->monitor_wqueue = create_singlethread_workqueue(dev_name(&pdev->dev)); 447fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov if (!di->monitor_wqueue) { 448fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov retval = -ESRCH; 449fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov goto workqueue_failed; 450fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov } 451fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1); 452fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 453fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov goto success; 454fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 455fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovworkqueue_failed: 456fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov power_supply_unregister(&di->bat); 457fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovbatt_failed: 458fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov kfree(di); 459fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovdi_alloc_failed: 460fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovsuccess: 461fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return retval; 462fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 463fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 464fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int ds2760_battery_remove(struct platform_device *pdev) 465fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 466fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct ds2760_device_info *di = platform_get_drvdata(pdev); 467fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 468fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov cancel_rearming_delayed_workqueue(di->monitor_wqueue, 469fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov &di->monitor_work); 470fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov destroy_workqueue(di->monitor_wqueue); 471fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov power_supply_unregister(&di->bat); 472fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 473fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return 0; 474fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 475fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 476fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#ifdef CONFIG_PM 477fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 478fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int ds2760_battery_suspend(struct platform_device *pdev, 479fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov pm_message_t state) 480fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 481fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct ds2760_device_info *di = platform_get_drvdata(pdev); 482fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 483fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; 484fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 485fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return 0; 486fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 487fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 488fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int ds2760_battery_resume(struct platform_device *pdev) 489fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 490fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov struct ds2760_device_info *di = platform_get_drvdata(pdev); 491fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 492fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; 493fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov power_supply_changed(&di->bat); 494fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 495fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov cancel_delayed_work(&di->monitor_work); 496fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ); 497fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 498fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return 0; 499fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 500fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 501fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#else 502fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 503fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#define ds2760_battery_suspend NULL 504fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#define ds2760_battery_resume NULL 505fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 506fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov#endif /* CONFIG_PM */ 507fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 5082f5a5cf93fae7b8354b45b8443dcc3448a8fc276Kay SieversMODULE_ALIAS("platform:ds2760-battery"); 5092f5a5cf93fae7b8354b45b8443dcc3448a8fc276Kay Sievers 510fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic struct platform_driver ds2760_battery_driver = { 511fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov .driver = { 512fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov .name = "ds2760-battery", 513fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov }, 514fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov .probe = ds2760_battery_probe, 515fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov .remove = ds2760_battery_remove, 516fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov .suspend = ds2760_battery_suspend, 517fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov .resume = ds2760_battery_resume, 518fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov}; 519fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 520fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic int __init ds2760_battery_init(void) 521fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 522fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov return platform_driver_register(&ds2760_battery_driver); 523fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 524fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 525fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovstatic void __exit ds2760_battery_exit(void) 526fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov{ 527fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov platform_driver_unregister(&ds2760_battery_driver); 528fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov} 529fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 530fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovmodule_init(ds2760_battery_init); 531fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsovmodule_exit(ds2760_battery_exit); 532fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov 533fe0e3153acfef4864b69932cf116eb5f38f7500cAnton VorontsovMODULE_LICENSE("GPL"); 534fe0e3153acfef4864b69932cf116eb5f38f7500cAnton VorontsovMODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " 535fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov "Matt Reimer <mreimer@vpop.net>, " 536fe0e3153acfef4864b69932cf116eb5f38f7500cAnton Vorontsov "Anton Vorontsov <cbou@mail.ru>"); 537fe0e3153acfef4864b69932cf116eb5f38f7500cAnton VorontsovMODULE_DESCRIPTION("ds2760 battery driver"); 538