[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