generic-adc-battery.c revision c8afa6406e60aec6ff90033e5ffe41a206609296
1e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar/* 2e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * Generic battery driver code using IIO 3e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * Copyright (C) 2012, Anish Kumar <anish198519851985@gmail.com> 4e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * based on jz4740-battery.c 5e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * based on s3c_adc_battery.c 6e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * 7e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * This file is subject to the terms and conditions of the GNU General Public 8e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * License. See the file COPYING in the main directory of this archive for 9e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * more details. 10e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * 11e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar */ 12e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/interrupt.h> 13e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/platform_device.h> 14e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/power_supply.h> 15e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/gpio.h> 16e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/err.h> 17e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/timer.h> 18e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/jiffies.h> 19e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/errno.h> 20e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/init.h> 21e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/module.h> 22e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/slab.h> 23e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/iio/consumer.h> 24e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/iio/types.h> 25e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#include <linux/power/generic-adc-battery.h> 26e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 27e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#define JITTER_DEFAULT 10 /* hope 10ms is enough */ 28e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 29e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarenum gab_chan_type { 30e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar GAB_VOLTAGE = 0, 31e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar GAB_CURRENT, 32e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar GAB_POWER, 33e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar GAB_MAX_CHAN_TYPE 34e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar}; 35e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 36e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar/* 37e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * gab_chan_name suggests the standard channel names for commonly used 38e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * channel types. 39e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar */ 40e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic const char *const gab_chan_name[] = { 41e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar [GAB_VOLTAGE] = "voltage", 42e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar [GAB_CURRENT] = "current", 43e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar [GAB_POWER] = "power", 44e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar}; 45e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 46e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstruct gab { 47e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct power_supply psy; 48e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct iio_channel *channel[GAB_MAX_CHAN_TYPE]; 49e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata; 50e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct delayed_work bat_work; 51e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int level; 52e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int status; 53e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar bool cable_plugged; 54e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar}; 55e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 56e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic struct gab *to_generic_bat(struct power_supply *psy) 57e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 58e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return container_of(psy, struct gab, psy); 59e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 60e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 61e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic void gab_ext_power_changed(struct power_supply *psy) 62e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 63e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab *adc_bat = to_generic_bat(psy); 64e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 65e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar schedule_delayed_work(&adc_bat->bat_work, msecs_to_jiffies(0)); 66e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 67e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 68e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic const enum power_supply_property gab_props[] = { 69e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_STATUS, 70e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 71e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, 72e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_CHARGE_NOW, 73e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_VOLTAGE_NOW, 74e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_CURRENT_NOW, 75e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_TECHNOLOGY, 76e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 77e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 78e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_MODEL_NAME, 79e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar}; 80e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 81e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar/* 82e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * This properties are set based on the received platform data and this 83e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * should correspond one-to-one with enum chan_type. 84e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar */ 85e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic const enum power_supply_property gab_dyn_props[] = { 86e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_VOLTAGE_NOW, 87e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_CURRENT_NOW, 88e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar POWER_SUPPLY_PROP_POWER_NOW, 89e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar}; 90e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 91e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic bool gab_charge_finished(struct gab *adc_bat) 92e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 93e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata = adc_bat->pdata; 94e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar bool ret = gpio_get_value(pdata->gpio_charge_finished); 95e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar bool inv = pdata->gpio_inverted; 96e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 97e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (!gpio_is_valid(pdata->gpio_charge_finished)) 98e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return false; 99e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return ret ^ inv; 100e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 101e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 102e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic int gab_get_status(struct gab *adc_bat) 103e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 104e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata = adc_bat->pdata; 105e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct power_supply_info *bat_info; 106e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 107e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar bat_info = &pdata->battery_info; 108e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (adc_bat->level == bat_info->charge_full_design) 109e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return POWER_SUPPLY_STATUS_FULL; 110e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return adc_bat->status; 111e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 112e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 113e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic enum gab_chan_type gab_prop_to_chan(enum power_supply_property psp) 114e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 115e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar switch (psp) { 116e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_POWER_NOW: 117e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return GAB_POWER; 118e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_VOLTAGE_NOW: 119e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return GAB_VOLTAGE; 120e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_CURRENT_NOW: 121e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return GAB_CURRENT; 122e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar default: 123e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar WARN_ON(1); 124e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 125e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 126e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return GAB_POWER; 127e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 128e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 129e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic int read_channel(struct gab *adc_bat, enum power_supply_property psp, 130e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int *result) 131e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 132e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int ret; 133e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int chan_index; 134e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 135e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar chan_index = gab_prop_to_chan(psp); 136e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar ret = iio_read_channel_processed(adc_bat->channel[chan_index], 137e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar result); 138e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (ret < 0) 139e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar pr_err("read channel error\n"); 140e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return ret; 141e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 142e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 143e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic int gab_get_property(struct power_supply *psy, 144e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar enum power_supply_property psp, union power_supply_propval *val) 145e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 146e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab *adc_bat; 147e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata; 148e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct power_supply_info *bat_info; 149e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int result = 0; 150e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int ret = 0; 151e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 152e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat = to_generic_bat(psy); 153e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (!adc_bat) { 154e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar dev_err(psy->dev, "no battery infos ?!\n"); 155e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return -EINVAL; 156e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 157e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar pdata = adc_bat->pdata; 158e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar bat_info = &pdata->battery_info; 159e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 160e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar switch (psp) { 161e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_STATUS: 162e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar gab_get_status(adc_bat); 163e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 164e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: 165e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar val->intval = 0; 166e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 167e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_CHARGE_NOW: 168e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar val->intval = pdata->cal_charge(result); 169e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 170e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_VOLTAGE_NOW: 171e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_CURRENT_NOW: 172e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_POWER_NOW: 173e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar ret = read_channel(adc_bat, psp, &result); 174e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (ret < 0) 175e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar goto err; 176e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar val->intval = result; 177e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 178e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_TECHNOLOGY: 179e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar val->intval = bat_info->technology; 180e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 181e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 182e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar val->intval = bat_info->voltage_min_design; 183e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 184e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 185e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar val->intval = bat_info->voltage_max_design; 186e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 187e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 188e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar val->intval = bat_info->charge_full_design; 189e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 190e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar case POWER_SUPPLY_PROP_MODEL_NAME: 191e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar val->strval = bat_info->name; 192e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar break; 193e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar default: 194e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return -EINVAL; 195e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 196e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarerr: 197e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return ret; 198e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 199e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 200e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic void gab_work(struct work_struct *work) 201e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 202e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab *adc_bat; 203e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata; 204e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct delayed_work *delayed_work; 205e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar bool is_plugged; 206e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int status; 207e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 208e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar delayed_work = container_of(work, struct delayed_work, work); 209e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat = container_of(delayed_work, struct gab, bat_work); 210e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar pdata = adc_bat->pdata; 211e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar status = adc_bat->status; 212e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 213e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar is_plugged = power_supply_am_i_supplied(&adc_bat->psy); 214e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->cable_plugged = is_plugged; 215e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 216e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (!is_plugged) 217e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; 218e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar else if (gab_charge_finished(adc_bat)) 219e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; 220e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar else 221e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->status = POWER_SUPPLY_STATUS_CHARGING; 222e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 223e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (status != adc_bat->status) 224e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar power_supply_changed(&adc_bat->psy); 225e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 226e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 227e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic irqreturn_t gab_charged(int irq, void *dev_id) 228e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 229e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab *adc_bat = dev_id; 230e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata = adc_bat->pdata; 231e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int delay; 232e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 233e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT; 234e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar schedule_delayed_work(&adc_bat->bat_work, 235e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar msecs_to_jiffies(delay)); 236e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return IRQ_HANDLED; 237e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 238e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 239c8afa6406e60aec6ff90033e5ffe41a206609296Bill Pembertonstatic int gab_probe(struct platform_device *pdev) 240e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 241e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab *adc_bat; 242e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct power_supply *psy; 243e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata = pdev->dev.platform_data; 244e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar enum power_supply_property *properties; 245e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int ret = 0; 246e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int chan; 247e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int index = 0; 248e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 249e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL); 250e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (!adc_bat) { 251e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar dev_err(&pdev->dev, "failed to allocate memory\n"); 252e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return -ENOMEM; 253e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 254e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 255e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar psy = &adc_bat->psy; 256e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar psy->name = pdata->battery_info.name; 257e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 258e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* bootup default values for the battery */ 259e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->cable_plugged = false; 260e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; 261e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar psy->type = POWER_SUPPLY_TYPE_BATTERY; 262e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar psy->get_property = gab_get_property; 263e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar psy->external_power_changed = gab_ext_power_changed; 264e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->pdata = pdata; 265e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 266e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* calculate the total number of channels */ 267e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar chan = ARRAY_SIZE(gab_chan_name); 268e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 269e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* 270e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * copying the static properties and allocating extra memory for holding 271e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * the extra configurable properties received from platform data. 272e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar */ 273e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar psy->properties = kcalloc(ARRAY_SIZE(gab_props) + 274e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar ARRAY_SIZE(gab_chan_name), 275e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar sizeof(*psy->properties), GFP_KERNEL); 276e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (!psy->properties) { 277e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar ret = -ENOMEM; 278e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar goto first_mem_fail; 279e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 280e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 281e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar memcpy(psy->properties, gab_props, sizeof(gab_props)); 282e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar properties = psy->properties + sizeof(gab_props); 283e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 284e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* 285e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * getting channel from iio and copying the battery properties 286e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * based on the channel supported by consumer device. 287e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar */ 288e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) { 289e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->channel[chan] = iio_channel_get(dev_name(&pdev->dev), 290e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar gab_chan_name[chan]); 291e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (IS_ERR(adc_bat->channel[chan])) { 292e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar ret = PTR_ERR(adc_bat->channel[chan]); 293e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } else { 294e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* copying properties for supported channels only */ 295e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar memcpy(properties + sizeof(*(psy->properties)) * index, 296e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar &gab_dyn_props[chan], 297e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar sizeof(gab_dyn_props[chan])); 298e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar index++; 299e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 300e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 301e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 302e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* none of the channels are supported so let's bail out */ 303e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (index == ARRAY_SIZE(gab_chan_name)) 304e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar goto second_mem_fail; 305e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 306e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* 307e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * Total number of properties is equal to static properties 308e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * plus the dynamic properties.Some properties may not be set 309e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * as come channels may be not be supported by the device.So 310e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar * we need to take care of that. 311e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar */ 312e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar psy->num_properties = ARRAY_SIZE(gab_props) + index; 313e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 314e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar ret = power_supply_register(&pdev->dev, psy); 315e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (ret) 316e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar goto err_reg_fail; 317e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 318e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar INIT_DELAYED_WORK(&adc_bat->bat_work, gab_work); 319e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 320e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (gpio_is_valid(pdata->gpio_charge_finished)) { 321e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int irq; 322e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar ret = gpio_request(pdata->gpio_charge_finished, "charged"); 323e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (ret) 324e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar goto gpio_req_fail; 325e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 326e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar irq = gpio_to_irq(pdata->gpio_charge_finished); 327e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar ret = request_any_context_irq(irq, gab_charged, 328e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 329e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar "battery charged", adc_bat); 330e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (ret) 331e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar goto err_gpio; 332e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 333e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 334e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar platform_set_drvdata(pdev, adc_bat); 335e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 336e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* Schedule timer to check current status */ 337e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar schedule_delayed_work(&adc_bat->bat_work, 338e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar msecs_to_jiffies(0)); 339e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return 0; 340e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 341e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarerr_gpio: 342e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar gpio_free(pdata->gpio_charge_finished); 343e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumargpio_req_fail: 344e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar power_supply_unregister(psy); 345e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarerr_reg_fail: 346e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++) 347e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar iio_channel_release(adc_bat->channel[chan]); 348e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarsecond_mem_fail: 349e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar kfree(psy->properties); 350e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarfirst_mem_fail: 351e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return ret; 352e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 353e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 354e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic int __devexit gab_remove(struct platform_device *pdev) 355e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 356e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int chan; 357e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab *adc_bat = platform_get_drvdata(pdev); 358e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata = adc_bat->pdata; 359e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 360e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar power_supply_unregister(&adc_bat->psy); 361e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 362e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar if (gpio_is_valid(pdata->gpio_charge_finished)) { 363e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar free_irq(gpio_to_irq(pdata->gpio_charge_finished), adc_bat); 364e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar gpio_free(pdata->gpio_charge_finished); 365e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar } 366e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 367e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++) 368e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar iio_channel_release(adc_bat->channel[chan]); 369e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 370e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar kfree(adc_bat->psy.properties); 371e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar cancel_delayed_work(&adc_bat->bat_work); 372e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return 0; 373e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 374e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 375e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#ifdef CONFIG_PM 376e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic int gab_suspend(struct device *dev) 377e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 378e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab *adc_bat = dev_get_drvdata(dev); 379e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 380e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar cancel_delayed_work_sync(&adc_bat->bat_work); 381e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar adc_bat->status = POWER_SUPPLY_STATUS_UNKNOWN; 382e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return 0; 383e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 384e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 385e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic int gab_resume(struct device *dev) 386e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar{ 387e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab *adc_bat = dev_get_drvdata(dev); 388e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar struct gab_platform_data *pdata = adc_bat->pdata; 389e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar int delay; 390e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 391e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT; 392e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 393e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar /* Schedule timer to check current status */ 394e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar schedule_delayed_work(&adc_bat->bat_work, 395e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar msecs_to_jiffies(delay)); 396e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar return 0; 397e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar} 398e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 399e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic const struct dev_pm_ops gab_pm_ops = { 400e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar .suspend = gab_suspend, 401e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar .resume = gab_resume, 402e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar}; 403e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 404e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#define GAB_PM_OPS (&gab_pm_ops) 405e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#else 406e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#define GAB_PM_OPS (NULL) 407e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar#endif 408e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 409e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarstatic struct platform_driver gab_driver = { 410e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar .driver = { 411e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar .name = "generic-adc-battery", 412e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar .owner = THIS_MODULE, 413e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar .pm = GAB_PM_OPS 414e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar }, 415e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar .probe = gab_probe, 41628ea73f4c67cb3dd8c972b21d9fdf84ea78d6daaBill Pemberton .remove = gab_remove, 417e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar}; 418e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarmodule_platform_driver(gab_driver); 419e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumar 420e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarMODULE_AUTHOR("anish kumar <anish198519851985@gmail.com>"); 421e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarMODULE_DESCRIPTION("generic battery driver using IIO"); 422e60fea794e6ecb9ea4df2623c9498412afe31d4danish kumarMODULE_LICENSE("GPL"); 423