Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae9458d6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.infradead.org/battery-2.6:
  apm_power: check I.intval for zero value, we use it as the divisor
  MAINTAINERS: remove kernel-discuss@handhelds.org list
  pda_power: implement polling
  pda_power: various cleanups
  apm_power: support using VOLTAGE_* properties for apm calculations
  pda_power: add suspend/resume support
  power_supply: add few more values and props
  pda_power: only register available psu
  power: fix incorrect unregistration in power_supply_create_attrs error path
  power: remove POWER_SUPPLY_PROP_CAPACITY_LEVEL
  [BATTERY] power_supply_leds: use kasprintf
  [BATTERY] Every file should include the headers containing the prototypes for its global functions.
parents 63e9b66e e91926e9
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -87,6 +87,10 @@ batteries use voltage for very approximated calculation of capacity.
Battery driver also can use this attribute just to inform userspace
Battery driver also can use this attribute just to inform userspace
about maximal and minimal voltage thresholds of a given battery.
about maximal and minimal voltage thresholds of a given battery.


VOLTAGE_MAX, VOLTAGE_MIN - same as _DESIGN voltage values except that
these ones should be used if hardware could only guess (measure and
retain) the thresholds of a given power supply.

CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when
CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when
battery considered full/empty.
battery considered full/empty.


@@ -100,8 +104,6 @@ age)". I.e. these attributes represents real thresholds, not design values.
ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.


CAPACITY - capacity in percents.
CAPACITY - capacity in percents.
CAPACITY_LEVEL - capacity level. This corresponds to
POWER_SUPPLY_CAPACITY_LEVEL_*.


TEMP - temperature of the power supply.
TEMP - temperature of the power supply.
TEMP_AMBIENT - ambient temperature.
TEMP_AMBIENT - ambient temperature.
+0 −1
Original line number Original line Diff line number Diff line
@@ -3053,7 +3053,6 @@ M: cbou@mail.ru
P:	David Woodhouse
P:	David Woodhouse
M:	dwmw2@infradead.org
M:	dwmw2@infradead.org
L:	linux-kernel@vger.kernel.org
L:	linux-kernel@vger.kernel.org
L:	kernel-discuss@handhelds.org
T:	git git.infradead.org/battery-2.6.git
T:	git git.infradead.org/battery-2.6.git
S:	Maintained
S:	Maintained


+73 −21
Original line number Original line Diff line number Diff line
@@ -13,7 +13,7 @@
#include <linux/power_supply.h>
#include <linux/power_supply.h>
#include <linux/apm-emulation.h>
#include <linux/apm-emulation.h>


static DEFINE_MUTEX(apm_mutex);

#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
			 POWER_SUPPLY_PROP_##prop, val)
			 POWER_SUPPLY_PROP_##prop, val)


@@ -22,8 +22,15 @@ static DEFINE_MUTEX(apm_mutex);


#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)


static DEFINE_MUTEX(apm_mutex);
static struct power_supply *main_battery;
static struct power_supply *main_battery;


enum apm_source {
	SOURCE_ENERGY,
	SOURCE_CHARGE,
	SOURCE_VOLTAGE,
};

struct find_bat_param {
struct find_bat_param {
	struct power_supply *main;
	struct power_supply *main;
	struct power_supply *bat;
	struct power_supply *bat;
@@ -107,7 +114,7 @@ static void find_main_battery(void)
	}
	}
}
}


static int calculate_time(int status, int using_charge)
static int do_calculate_time(int status, enum apm_source source)
{
{
	union power_supply_propval full;
	union power_supply_propval full;
	union power_supply_propval empty;
	union power_supply_propval empty;
@@ -126,20 +133,37 @@ static int calculate_time(int status, int using_charge)
			return -1;
			return -1;
	}
	}


	if (using_charge) {
	if (!I.intval)
		return 0;

	switch (source) {
	case SOURCE_CHARGE:
		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
		cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
		cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
		cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
		cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
	} else {
		break;
	case SOURCE_ENERGY:
		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
		cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
		cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
		cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
		cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
		break;
	case SOURCE_VOLTAGE:
		full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
		full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
		empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
		empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
		cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
		cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
		break;
	default:
		printk(KERN_ERR "Unsupported source: %d\n", source);
		return -1;
	}
	}


	if (_MPSY_PROP(full_prop, &full)) {
	if (_MPSY_PROP(full_prop, &full)) {
@@ -166,7 +190,26 @@ static int calculate_time(int status, int using_charge)
		return -((cur.intval - empty.intval) * 60L) / I.intval;
		return -((cur.intval - empty.intval) * 60L) / I.intval;
}
}


static int calculate_capacity(int using_charge)
static int calculate_time(int status)
{
	int time;

	time = do_calculate_time(status, SOURCE_ENERGY);
	if (time != -1)
		return time;

	time = do_calculate_time(status, SOURCE_CHARGE);
	if (time != -1)
		return time;

	time = do_calculate_time(status, SOURCE_VOLTAGE);
	if (time != -1)
		return time;

	return -1;
}

static int calculate_capacity(enum apm_source source)
{
{
	enum power_supply_property full_prop, empty_prop;
	enum power_supply_property full_prop, empty_prop;
	enum power_supply_property full_design_prop, empty_design_prop;
	enum power_supply_property full_design_prop, empty_design_prop;
@@ -174,20 +217,33 @@ static int calculate_capacity(int using_charge)
	union power_supply_propval empty, full, cur;
	union power_supply_propval empty, full, cur;
	int ret;
	int ret;


	if (using_charge) {
	switch (source) {
	case SOURCE_CHARGE:
		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
		now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
		now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
		avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
		avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
	} else {
		break;
	case SOURCE_ENERGY:
		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
		empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
		empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
		now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
		now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
		avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
		avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
	case SOURCE_VOLTAGE:
		full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
		empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
		full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
		empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
		now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
		avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
		break;
	default:
		printk(KERN_ERR "Unsupported source: %d\n", source);
		return -1;
	}
	}


	if (_MPSY_PROP(full_prop, &full)) {
	if (_MPSY_PROP(full_prop, &full)) {
@@ -254,10 +310,12 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
		info->battery_life = capacity.intval;
		info->battery_life = capacity.intval;
	} else {
	} else {
		/* try calculate using energy */
		/* try calculate using energy */
		info->battery_life = calculate_capacity(0);
		info->battery_life = calculate_capacity(SOURCE_ENERGY);
		/* if failed try calculate using charge instead */
		/* if failed try calculate using charge instead */
		if (info->battery_life == -1)
		if (info->battery_life == -1)
			info->battery_life = calculate_capacity(1);
			info->battery_life = calculate_capacity(SOURCE_CHARGE);
		if (info->battery_life == -1)
			info->battery_life = calculate_capacity(SOURCE_VOLTAGE);
	}
	}


	/* charging status */
	/* charging status */
@@ -280,22 +338,16 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)


	if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
	if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
		if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
		if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
				!MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
				!MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
			info->time = time_to_full.intval / 60;
			info->time = time_to_full.intval / 60;
		} else {
		else
			info->time = calculate_time(status.intval, 0);
			info->time = calculate_time(status.intval);
			if (info->time == -1)
				info->time = calculate_time(status.intval, 1);
		}
	} else {
	} else {
		if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
		if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
			      !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
			      !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
			info->time = time_to_empty.intval / 60;
			info->time = time_to_empty.intval / 60;
		} else {
		else
			info->time = calculate_time(status.intval, 0);
			info->time = calculate_time(status.intval);
			if (info->time == -1)
				info->time = calculate_time(status.intval, 1);
		}
	}
	}


	mutex_unlock(&apm_mutex);
	mutex_unlock(&apm_mutex);
+0 −9
Original line number Original line Diff line number Diff line
@@ -226,14 +226,6 @@ static int olpc_bat_get_property(struct power_supply *psy,
			return ret;
			return ret;
		val->intval = ec_byte;
		val->intval = ec_byte;
		break;
		break;
	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
		if (ec_byte & BAT_STAT_FULL)
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
		else if (ec_byte & BAT_STAT_LOW)
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
		else
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
		break;
	case POWER_SUPPLY_PROP_TEMP:
	case POWER_SUPPLY_PROP_TEMP:
		ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
		ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
		if (ret)
		if (ret)
@@ -265,7 +257,6 @@ static enum power_supply_property olpc_bat_props[] = {
	POWER_SUPPLY_PROP_VOLTAGE_AVG,
	POWER_SUPPLY_PROP_VOLTAGE_AVG,
	POWER_SUPPLY_PROP_CURRENT_AVG,
	POWER_SUPPLY_PROP_CURRENT_AVG,
	POWER_SUPPLY_PROP_CAPACITY,
	POWER_SUPPLY_PROP_CAPACITY,
	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
	POWER_SUPPLY_PROP_TEMP,
	POWER_SUPPLY_PROP_TEMP,
	POWER_SUPPLY_PROP_TEMP_AMBIENT,
	POWER_SUPPLY_PROP_TEMP_AMBIENT,
	POWER_SUPPLY_PROP_MANUFACTURER,
	POWER_SUPPLY_PROP_MANUFACTURER,
+202 −80
Original line number Original line Diff line number Diff line
@@ -32,6 +32,18 @@ static struct pda_power_pdata *pdata;
static struct resource *ac_irq, *usb_irq;
static struct resource *ac_irq, *usb_irq;
static struct timer_list charger_timer;
static struct timer_list charger_timer;
static struct timer_list supply_timer;
static struct timer_list supply_timer;
static struct timer_list polling_timer;
static int polling;

enum {
	PDA_PSY_OFFLINE = 0,
	PDA_PSY_ONLINE = 1,
	PDA_PSY_TO_CHANGE,
};
static int new_ac_status = -1;
static int new_usb_status = -1;
static int ac_status = -1;
static int usb_status = -1;


static int pda_power_get_property(struct power_supply *psy,
static int pda_power_get_property(struct power_supply *psy,
				  enum power_supply_property psp,
				  enum power_supply_property psp,
@@ -61,8 +73,7 @@ static char *pda_power_supplied_to[] = {
	"backup-battery",
	"backup-battery",
};
};


static struct power_supply pda_power_supplies[] = {
static struct power_supply pda_psy_ac = {
	{
	.name = "ac",
	.name = "ac",
	.type = POWER_SUPPLY_TYPE_MAINS,
	.type = POWER_SUPPLY_TYPE_MAINS,
	.supplied_to = pda_power_supplied_to,
	.supplied_to = pda_power_supplied_to,
@@ -70,8 +81,9 @@ static struct power_supply pda_power_supplies[] = {
	.properties = pda_power_props,
	.properties = pda_power_props,
	.num_properties = ARRAY_SIZE(pda_power_props),
	.num_properties = ARRAY_SIZE(pda_power_props),
	.get_property = pda_power_get_property,
	.get_property = pda_power_get_property,
	},
};
	{

static struct power_supply pda_psy_usb = {
	.name = "usb",
	.name = "usb",
	.type = POWER_SUPPLY_TYPE_USB,
	.type = POWER_SUPPLY_TYPE_USB,
	.supplied_to = pda_power_supplied_to,
	.supplied_to = pda_power_supplied_to,
@@ -79,18 +91,26 @@ static struct power_supply pda_power_supplies[] = {
	.properties = pda_power_props,
	.properties = pda_power_props,
	.num_properties = ARRAY_SIZE(pda_power_props),
	.num_properties = ARRAY_SIZE(pda_power_props),
	.get_property = pda_power_get_property,
	.get_property = pda_power_get_property,
	},
};
};


static void update_status(void)
{
	if (pdata->is_ac_online)
		new_ac_status = !!pdata->is_ac_online();

	if (pdata->is_usb_online)
		new_usb_status = !!pdata->is_usb_online();
}

static void update_charger(void)
static void update_charger(void)
{
{
	if (!pdata->set_charge)
	if (!pdata->set_charge)
		return;
		return;


	if (pdata->is_ac_online && pdata->is_ac_online()) {
	if (new_ac_status > 0) {
		dev_dbg(dev, "charger on (AC)\n");
		dev_dbg(dev, "charger on (AC)\n");
		pdata->set_charge(PDA_POWER_CHARGE_AC);
		pdata->set_charge(PDA_POWER_CHARGE_AC);
	} else if (pdata->is_usb_online && pdata->is_usb_online()) {
	} else if (new_usb_status > 0) {
		dev_dbg(dev, "charger on (USB)\n");
		dev_dbg(dev, "charger on (USB)\n");
		pdata->set_charge(PDA_POWER_CHARGE_USB);
		pdata->set_charge(PDA_POWER_CHARGE_USB);
	} else {
	} else {
@@ -99,34 +119,81 @@ static void update_charger(void)
	}
	}
}
}


static void supply_timer_func(unsigned long power_supply_ptr)
static void supply_timer_func(unsigned long unused)
{
{
	void *power_supply = (void *)power_supply_ptr;
	if (ac_status == PDA_PSY_TO_CHANGE) {
		ac_status = new_ac_status;
		power_supply_changed(&pda_psy_ac);
	}


	power_supply_changed(power_supply);
	if (usb_status == PDA_PSY_TO_CHANGE) {
		usb_status = new_usb_status;
		power_supply_changed(&pda_psy_usb);
	}
}
}


static void charger_timer_func(unsigned long power_supply_ptr)
static void psy_changed(void)
{
{
	update_charger();
	update_charger();


	/* Okay, charger set. Now wait a bit before notifying supplicants,
	/*
	 * charge power should stabilize. */
	 * Okay, charger set. Now wait a bit before notifying supplicants,
	supply_timer.data = power_supply_ptr;
	 * charge power should stabilize.
	 */
	mod_timer(&supply_timer,
	mod_timer(&supply_timer,
		  jiffies + msecs_to_jiffies(pdata->wait_for_charger));
		  jiffies + msecs_to_jiffies(pdata->wait_for_charger));
}
}


static void charger_timer_func(unsigned long unused)
{
	update_status();
	psy_changed();
}

static irqreturn_t power_changed_isr(int irq, void *power_supply)
static irqreturn_t power_changed_isr(int irq, void *power_supply)
{
{
	/* Wait a bit before reading ac/usb line status and setting charger,
	if (power_supply == &pda_psy_ac)
	 * because ac/usb status readings may lag from irq. */
		ac_status = PDA_PSY_TO_CHANGE;
	charger_timer.data = (unsigned long)power_supply;
	else if (power_supply == &pda_psy_usb)
		usb_status = PDA_PSY_TO_CHANGE;
	else
		return IRQ_NONE;

	/*
	 * Wait a bit before reading ac/usb line status and setting charger,
	 * because ac/usb status readings may lag from irq.
	 */
	mod_timer(&charger_timer,
	mod_timer(&charger_timer,
		  jiffies + msecs_to_jiffies(pdata->wait_for_status));
		  jiffies + msecs_to_jiffies(pdata->wait_for_status));

	return IRQ_HANDLED;
	return IRQ_HANDLED;
}
}


static void polling_timer_func(unsigned long unused)
{
	int changed = 0;

	dev_dbg(dev, "polling...\n");

	update_status();

	if (!ac_irq && new_ac_status != ac_status) {
		ac_status = PDA_PSY_TO_CHANGE;
		changed = 1;
	}

	if (!usb_irq && new_usb_status != usb_status) {
		usb_status = PDA_PSY_TO_CHANGE;
		changed = 1;
	}

	if (changed)
		psy_changed();

	mod_timer(&polling_timer,
		  jiffies + msecs_to_jiffies(pdata->polling_interval));
}

static int pda_power_probe(struct platform_device *pdev)
static int pda_power_probe(struct platform_device *pdev)
{
{
	int ret = 0;
	int ret = 0;
@@ -142,6 +209,7 @@ static int pda_power_probe(struct platform_device *pdev)


	pdata = pdev->dev.platform_data;
	pdata = pdev->dev.platform_data;


	update_status();
	update_charger();
	update_charger();


	if (!pdata->wait_for_status)
	if (!pdata->wait_for_status)
@@ -150,86 +218,138 @@ static int pda_power_probe(struct platform_device *pdev)
	if (!pdata->wait_for_charger)
	if (!pdata->wait_for_charger)
		pdata->wait_for_charger = 500;
		pdata->wait_for_charger = 500;


	if (!pdata->polling_interval)
		pdata->polling_interval = 2000;

	setup_timer(&charger_timer, charger_timer_func, 0);
	setup_timer(&charger_timer, charger_timer_func, 0);
	setup_timer(&supply_timer, supply_timer_func, 0);
	setup_timer(&supply_timer, supply_timer_func, 0);


	ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
	ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
	usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
	usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
	if (!ac_irq && !usb_irq) {
		dev_err(dev, "no ac/usb irq specified\n");
		ret = -ENODEV;
		goto noirqs;
	}


	if (pdata->supplied_to) {
	if (pdata->supplied_to) {
		pda_power_supplies[0].supplied_to = pdata->supplied_to;
		pda_psy_ac.supplied_to = pdata->supplied_to;
		pda_power_supplies[1].supplied_to = pdata->supplied_to;
		pda_psy_ac.num_supplicants = pdata->num_supplicants;
		pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
		pda_psy_usb.supplied_to = pdata->supplied_to;
		pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
		pda_psy_usb.num_supplicants = pdata->num_supplicants;
	}
	}


	ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
	if (pdata->is_ac_online) {
		ret = power_supply_register(&pdev->dev, &pda_psy_ac);
		if (ret) {
		if (ret) {
			dev_err(dev, "failed to register %s power supply\n",
			dev_err(dev, "failed to register %s power supply\n",
			pda_power_supplies[0].name);
				pda_psy_ac.name);
		goto supply0_failed;
			goto ac_supply_failed;
	}

	ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
	if (ret) {
		dev_err(dev, "failed to register %s power supply\n",
			pda_power_supplies[1].name);
		goto supply1_failed;
		}
		}


		if (ac_irq) {
		if (ac_irq) {
			ret = request_irq(ac_irq->start, power_changed_isr,
			ret = request_irq(ac_irq->start, power_changed_isr,
					  get_irq_flags(ac_irq), ac_irq->name,
					  get_irq_flags(ac_irq), ac_irq->name,
				  &pda_power_supplies[0]);
					  &pda_psy_ac);
			if (ret) {
			if (ret) {
				dev_err(dev, "request ac irq failed\n");
				dev_err(dev, "request ac irq failed\n");
				goto ac_irq_failed;
				goto ac_irq_failed;
			}
			}
		} else {
			polling = 1;
		}
	}

	if (pdata->is_usb_online) {
		ret = power_supply_register(&pdev->dev, &pda_psy_usb);
		if (ret) {
			dev_err(dev, "failed to register %s power supply\n",
				pda_psy_usb.name);
			goto usb_supply_failed;
		}
		}


		if (usb_irq) {
		if (usb_irq) {
			ret = request_irq(usb_irq->start, power_changed_isr,
			ret = request_irq(usb_irq->start, power_changed_isr,
				  get_irq_flags(usb_irq), usb_irq->name,
					  get_irq_flags(usb_irq),
				  &pda_power_supplies[1]);
					  usb_irq->name, &pda_psy_usb);
			if (ret) {
			if (ret) {
				dev_err(dev, "request usb irq failed\n");
				dev_err(dev, "request usb irq failed\n");
				goto usb_irq_failed;
				goto usb_irq_failed;
			}
			}
		} else {
			polling = 1;
		}
	}

	if (polling) {
		dev_dbg(dev, "will poll for status\n");
		setup_timer(&polling_timer, polling_timer_func, 0);
		mod_timer(&polling_timer,
			  jiffies + msecs_to_jiffies(pdata->polling_interval));
	}
	}


	goto success;
	if (ac_irq || usb_irq)
		device_init_wakeup(&pdev->dev, 1);

	return 0;


usb_irq_failed:
usb_irq_failed:
	if (ac_irq)
	if (pdata->is_usb_online)
		free_irq(ac_irq->start, &pda_power_supplies[0]);
		power_supply_unregister(&pda_psy_usb);
usb_supply_failed:
	if (pdata->is_ac_online && ac_irq)
		free_irq(ac_irq->start, &pda_psy_ac);
ac_irq_failed:
ac_irq_failed:
	power_supply_unregister(&pda_power_supplies[1]);
	if (pdata->is_ac_online)
supply1_failed:
		power_supply_unregister(&pda_psy_ac);
	power_supply_unregister(&pda_power_supplies[0]);
ac_supply_failed:
supply0_failed:
noirqs:
wrongid:
wrongid:
success:
	return ret;
	return ret;
}
}


static int pda_power_remove(struct platform_device *pdev)
static int pda_power_remove(struct platform_device *pdev)
{
{
	if (usb_irq)
	if (pdata->is_usb_online && usb_irq)
		free_irq(usb_irq->start, &pda_power_supplies[1]);
		free_irq(usb_irq->start, &pda_psy_usb);
	if (ac_irq)
	if (pdata->is_ac_online && ac_irq)
		free_irq(ac_irq->start, &pda_power_supplies[0]);
		free_irq(ac_irq->start, &pda_psy_ac);

	if (polling)
		del_timer_sync(&polling_timer);
	del_timer_sync(&charger_timer);
	del_timer_sync(&charger_timer);
	del_timer_sync(&supply_timer);
	del_timer_sync(&supply_timer);
	power_supply_unregister(&pda_power_supplies[1]);

	power_supply_unregister(&pda_power_supplies[0]);
	if (pdata->is_usb_online)
		power_supply_unregister(&pda_psy_usb);
	if (pdata->is_ac_online)
		power_supply_unregister(&pda_psy_ac);

	return 0;
}

#ifdef CONFIG_PM
static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
{
	if (device_may_wakeup(&pdev->dev)) {
		if (ac_irq)
			enable_irq_wake(ac_irq->start);
		if (usb_irq)
			enable_irq_wake(usb_irq->start);
	}

	return 0;
}

static int pda_power_resume(struct platform_device *pdev)
{
	if (device_may_wakeup(&pdev->dev)) {
		if (usb_irq)
			disable_irq_wake(usb_irq->start);
		if (ac_irq)
			disable_irq_wake(ac_irq->start);
	}

	return 0;
	return 0;
}
}
#else
#define pda_power_suspend NULL
#define pda_power_resume NULL
#endif /* CONFIG_PM */


static struct platform_driver pda_power_pdrv = {
static struct platform_driver pda_power_pdrv = {
	.driver = {
	.driver = {
@@ -237,6 +357,8 @@ static struct platform_driver pda_power_pdrv = {
	},
	},
	.probe = pda_power_probe,
	.probe = pda_power_probe,
	.remove = pda_power_remove,
	.remove = pda_power_remove,
	.suspend = pda_power_suspend,
	.resume = pda_power_resume,
};
};


static int __init pda_power_init(void)
static int __init pda_power_init(void)
Loading