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