From c9b90fa28c12a3d6cfece51687c368302dc71719 Mon Sep 17 00:00:00 2001
From: Holger Freyther <[EMAIL PROTECTED]>
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



Reply via email to