[PATCH 1/3] PMU and Battery interaction in regard to kobject uevent

Holger Freyther zecke at openmoko.org
Tue Jun 3 11:22:47 CEST 2008


From c9b90fa28c12a3d6cfece51687c368302dc71719 Mon Sep 17 00:00:00 2001
From: Holger Freyther <zecke at openmoko.org>
Date: Thu, 29 May 2008 00:47:22 +0200
Subject: [PATCH] [pmu] Add a PCF50633 charging source event system and use it 
in the bq27000
     We want to sent uevent's from the power_supply device kobject on charging
     changes. We can only get this information from the pcf50633, we have to 
add
     a generic mechanism to get plug events from it. There is an overlap with
     the pmu_cb which needs to be resolved. The pmu_cb gets set before the pmu
     is actually properly set up (and a pcf50633 is available), this won't 
work
     for the battery driver and we will need multiple callbacks.

---
 drivers/i2c/chips/pcf50633.c    |   60 ++++++++++++++++++++++++++++++++++++--
 drivers/power/bq27000_battery.c |   14 +++++++++
 include/linux/pcf50633.h        |   14 +++++++++
 3 files changed, 84 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/chips/pcf50633.c b/drivers/i2c/chips/pcf50633.c
index 2878baa..2e5d3ff 100644
--- a/drivers/i2c/chips/pcf50633.c
+++ b/drivers/i2c/chips/pcf50633.c
@@ -152,6 +152,14 @@ struct pcf50633_data {
 		} ldo[__NUM_PCF50633_REGS];
 	} standby_regs;
 #endif
+
+	struct list_head event_handler;
+};
+
+struct pcf50633_event_handler_data {
+	pcf50633_event_handler handler;
+	void *data;
+	struct list_head entry;
 };
 
 static struct i2c_driver pcf50633_driver;
@@ -464,6 +472,49 @@ void pcf50633_go_standby(void)
 }
 EXPORT_SYMBOL_GPL(pcf50633_go_standby);
 
+static void pcf50633_report_event(struct pcf50633_data *pcf, enum 
pcf50633_plug_event event, int plug)
+{
+	struct list_head *element;
+
+	list_for_each(element, &pcf->event_handler) {
+	    struct pcf50633_event_handler_data *event_data = 
+				container_of(element, struct pcf50633_event_handler_data, entry);
+	    (*event_data->handler)(pcf, event, plug, event_data->data);
+	}
+}
+
+void pcf50633_add_event_handler(struct pcf50633_data *pcf, 
pcf50633_event_handler handler, void *token)
+{
+	struct pcf50633_event_handler_data *data;
+
+	if (!(data = kmalloc(sizeof(*data), GFP_KERNEL)))
+		return;
+
+	INIT_LIST_HEAD(&data->entry);
+	data->handler = handler;
+	data->data = token;
+
+	list_add(&pcf->event_handler, &data->entry);
+}
+EXPORT_SYMBOL_GPL(pcf50633_add_event_handler);
+
+void pcf50633_remove_event_handler(struct pcf50633_data *pcf, 
pcf50633_event_handler _handler)
+{
+	struct list_head *element;
+
+	list_for_each(element, &pcf->event_handler) {
+	    struct pcf50633_event_handler_data *event_data = 
+			container_of(element, struct pcf50633_event_handler_data, entry);
+
+		if (_handler == event_data->handler) {
+			list_del(element);
+			kfree(element);
+			return;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(pcf50633_remove_event_handler);
+
 void pcf50633_gpio_set(struct pcf50633_data *pcf, enum pcf50633_gpio gpio,
 			int on)
 {
@@ -651,8 +702,7 @@ static void pcf50633_work(struct work_struct *work)
 		if (pcf->pdata->cb)
 			pcf->pdata->cb(&pcf->client.dev,
 				       PCF50633_FEAT_MBC, PMU_EVT_INSERT);
-		/* FIXME: signal this to userspace */
-		//kobject_uevent( ,KOBJ_ADD);
+		pcf50633_report_event(pcf, PCF50633_PLUG_EVENT_CHARGER, 1);
 	}
 	if (pcfirq[0] & PCF50633_INT1_ADPREM) {
 		/* Charger removed */
@@ -663,8 +713,7 @@ static void pcf50633_work(struct work_struct *work)
 		if (pcf->pdata->cb)
 			pcf->pdata->cb(&pcf->client.dev,
 				       PCF50633_FEAT_MBC, PMU_EVT_REMOVE);
-		/* FIXME: signal this to userspace */
-		//kobject_uevent( ,KOBJ_ADD);
+		pcf50633_report_event(pcf, PCF50633_PLUG_EVENT_CHARGER, 0);
 	}
 	if (pcfirq[0] & PCF50633_INT1_USBINS) {
 		DEBUGPC("USBINS ");
@@ -677,6 +726,7 @@ static void pcf50633_work(struct work_struct *work)
 		/* completion irq will figure out our charging stance */
 		add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
 				     PCF50633_ADCC1_AVERAGE_16);
+		pcf50633_report_event(pcf, PCF50633_PLUG_EVENT_USB, 1);
 	}
 	if (pcfirq[0] & PCF50633_INT1_USBREM) {
 		DEBUGPC("USBREM ");
@@ -691,6 +741,7 @@ static void pcf50633_work(struct work_struct *work)
 			/* completion irq will figure out our charging stance */
 			add_request_to_adc_queue(pcf, PCF50633_ADCC1_MUX_ADCIN1,
 					PCF50633_ADCC1_AVERAGE_16);
+			pcf50633_report_event(pcf, PCF50633_PLUG_EVENT_USB, 0);
 		}
 	}
 	if (pcfirq[0] & PCF50633_INT1_ALARM) {
@@ -1713,6 +1764,7 @@ static int pcf50633_detect(struct i2c_adapter *adapter, 
int address, int kind)
 	mutex_init(&data->lock);
 	mutex_init(&data->working_lock);
 	INIT_WORK(&data->work, pcf50633_work);
+	INIT_LIST_HEAD(&data->event_handler);
 	data->irq = irq;
 	data->working = 0;
 	data->onkey_seconds = -1;
diff --git a/drivers/power/bq27000_battery.c b/drivers/power/bq27000_battery.c
index cf57dcf..8b7f81c 100644
--- a/drivers/power/bq27000_battery.c
+++ b/drivers/power/bq27000_battery.c
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
 #include <linux/bq27000_battery.h>
+#include <linux/pcf50633.h>
 
 enum bq27000_regs {
 	/* RAM regs */
@@ -121,6 +122,14 @@ struct bq27000_device_info {
 	int (*hdq_write)(int, u8); /* from platform */
 };
 
+static void bq2700_battery_event_handler(struct pcf50633_data *data,
+	    enum pcf50633_plug_event event, int insert, void *di)
+{
+	struct bq27000_device_info *device = (struct bq27000_device_info *)di;
+
+	kobject_uevent(&device->bat.dev->kobj, KOBJ_CHANGE);
+}
+
 /*
  * reading 16 bit values over HDQ has a special hazard where the
  * hdq device firmware can update the 16-bit register during the time we
@@ -311,6 +320,9 @@ static int bq27000_battery_probe(struct platform_device 
*pdev)
 		goto batt_failed;
 	}
 
+	pcf50633_add_event_handler(pcf50633_global,
+			bq2700_battery_event_handler, di);
+
 	return 0;
 
 batt_failed:
@@ -323,6 +335,8 @@ static int bq27000_battery_remove(struct platform_device 
*pdev)
 {
 	struct bq27000_device_info *di = platform_get_drvdata(pdev);
 
+	pcf50633_remove_event_handler(pcf50633_global,
+			bq2700_battery_event_handler);
 	power_supply_unregister(&di->bat);
 
 	return 0;
diff --git a/include/linux/pcf50633.h b/include/linux/pcf50633.h
index 837037e..cc551c1 100644
--- a/include/linux/pcf50633.h
+++ b/include/linux/pcf50633.h
@@ -20,6 +20,11 @@ enum pcf50633_regulator_id {
 	__NUM_PCF50633_REGULATORS
 };
 
+enum pcf50633_plug_event {
+	PCF50633_PLUG_EVENT_CHARGER,
+	PCF50633_PLUG_EVENT_USB
+};
+
 enum pcf50633_reg_int1 {
 	PCF50633_INT1_ADPINS	= 0x01,	/* Adapter inserted */
 	PCF50633_INT1_ADPREM	= 0x02,	/* Adapter removed */
@@ -77,6 +82,9 @@ enum pcf50633_reg_int5 {
 struct pcf50633_data;
 extern struct pcf50633_data *pcf50633_global;
 
+typedef void (*pcf50633_event_handler)(struct pcf50633_data *data,
+		enum pcf50633_plug_event event, int insert, void *token);
+
 extern void
 pcf50633_go_standby(void);
 
@@ -124,6 +132,12 @@ pcf50633_battvolt(struct pcf50633_data *pcf);
 extern int
 pcf50633_report_resumers(struct pcf50633_data *pcf, char *buf);
 
+extern void
+pcf50633_add_event_handler(struct pcf50633_data *pcf, pcf50633_event_handler 
handler, void *data);
+
+extern void
+pcf50633_remove_event_handler(struct pcf50633_data *pcf, 
pcf50633_event_handler handler);
+
 
 #define PCF50633_FEAT_EXTON	0x00000001	/* not yet supported */
 #define PCF50633_FEAT_MBC	0x00000002
-- 
1.5.4.3






More information about the openmoko-kernel mailing list