add battery module on 100520
author罗伟 <lw@rock-chips.com>
Wed, 19 May 2010 12:19:14 +0000 (12:19 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:35:14 +0000 (13:35 +0800)
.config
arch/arm/mach-rk2818/adc.c
arch/arm/mach-rk2818/board-midsdk.c
arch/arm/mach-rk2818/devices.c
arch/arm/mach-rk2818/devices.h
drivers/input/keyboard/Kconfig
drivers/input/keyboard/rk2818_adckey.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/rk2818_battery.c [new file with mode: 0644]

diff --git a/.config b/.config
index 721e216f185821dd6cf25fa1a68bcf1332f64697..93dd88c4b0ba75439800b28b323a570f98d8f20a 100644 (file)
--- a/.config
+++ b/.config
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.32.9
-# Tue May 18 22:11:51 2010
+# Wed May 19 19:32:08 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -819,6 +819,7 @@ CONFIG_POWER_SUPPLY=y
 # CONFIG_BATTERY_DS2782 is not set
 # CONFIG_BATTERY_BQ27x00 is not set
 # CONFIG_BATTERY_MAX17040 is not set
+CONFIG_BATTERY_RK2818=y
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
 # CONFIG_WATCHDOG is not set
index 9b770e2b3f32e2d924f4b9cb000b95dd94a892b2..f3e762cfc01a9518be9fa06d00d91b270b00b09d 100644 (file)
@@ -376,7 +376,7 @@ static int rk28_adc_probe(struct platform_device *pdev)
        
        rk28_adc_int_disable(adc);
        pAdcDev = adc;
-       printk("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);
+       printk(KERN_INFO "rk2818 adc: driver initialized\n");
        return 0;
 
  err_clk:
@@ -452,7 +452,6 @@ static int __init adc_init(void)
        ret = platform_driver_register(&rk28_adc_driver);
        if (ret)
                printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
-       printk("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);
        return ret;
 }
 
index 9e709645c7492909e4d41096fecf5b188c0a4701..85fe4c1d8e42508470d471b115940b1a9b8225d1 100644 (file)
@@ -291,6 +291,7 @@ static struct platform_device *devices[] __initdata = {
        &rk2818_device_pmem,
        &rk2818_device_adc,
        &rk2818_device_adckey,
+       &rk2818_device_battery,
     &rk2818_device_fb,    
     &rk2818_device_backlight,
        &rk2818_device_dsp,
index c85174224f1b6c056bda742e70f4c640d150ec8b..d5f70bbeb3800000f4e80fd55350fb8a68d763fb 100644 (file)
@@ -279,6 +279,11 @@ struct platform_device rk2818_device_adckey = {
        .dev.parent     = &rk2818_device_adc.dev,
 };
 
+struct platform_device rk2818_device_battery = {
+               .name   = "rk2818-battery",
+               .id     = -1,
+};
+
 
 /*
  * rk2818 dsp device
index fb31f0cf66361418bb39c5cba495a4b5273e4003..fdfda9e564c45a3c752dd3017db2f85ec66ec21d 100644 (file)
@@ -30,6 +30,7 @@ extern struct platform_device rk2818_device_pmem;
 extern struct platform_device rk2818_device_fb;
 extern struct platform_device rk2818_device_adc;
 extern struct platform_device rk2818_device_adckey;
+extern struct platform_device rk2818_device_battery;
 extern struct platform_device rk2818_device_backlight;
 extern struct platform_device rk2818_device_dsp;
 #endif
index 5003bda21d01cd67fb8e0b3bc776a7de3a8116ea..7f51714d1772adfd3eedc86e08d43cc993034f67 100644 (file)
@@ -424,7 +424,7 @@ config KEYBOARD_W90P910
          module will be called w90p910_keypad.
 config KEYBOARD_RK28ADC         
        tristate "RK2818 ADC Keypad support"
-       depends on ARCH_RK2818
+       depends on RK28_ADC
        default y
        help
          Say Y here to enable the adc keypad on SDK board
index fbdd066d8d63d884309ed13d063c82879c775340..e8e2a82c392d769e07838bd941729617a580a827 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-
+#include <mach/gpio.h>
 #include <mach/adc.h>
 
-#if 0
+#if 1
 #define DBG(x...)   printk(x)
 #else
 #define DBG(x...)
 
 //ROCKCHIP AD KEY CODE ,for demo board
 //      key            --->    EV      
-#define AD2KEY1                        114   ///VOLUME_DOWN 
-#define AD2KEY2                115   ///VOLUME_UP
-#define AD2KEY3                59    ///MENU
-#define AD2KEY4                102   ///HOME
-#define AD2KEY5                158   ///BACK
-#define AD2KEY6                61    ///CALL
-
-#define KEYMENU                        AD2KEY6
+#define AD2KEY1                 114   ///VOLUME_DOWN
+#define AD2KEY2                 115   ///VOLUME_UP
+#define AD2KEY3                 59    ///MENU
+#define AD2KEY4                 102   ///HOME
+#define AD2KEY5                 158   ///BACK
+#define AD2KEY6                 61    ///CALL
+
+#define        KEYSTART                28                      //ENTER
+#define KEYMENU                        AD2KEY6         ///CALL
+#define KEY_PLAYON_PIN RK2818_PIN_PE1
 #define ENDCALL                        62
 
 #define Valuedrift             50
@@ -56,6 +58,7 @@
 volatile int gADSampleTimes = 0;
 volatile int gAdcChanel = 0;
 volatile int gAdcValue[4]={0, 0, 0, 0};        //0->ch0 1->ch1 2->ch2 3->ch3
+volatile int gStatePlaykey = 0;
 
 volatile unsigned int gCodeCount = 0;
 volatile unsigned int gThisCode = 0;
@@ -94,7 +97,6 @@ struct rk28_adckey
        struct input_dev *input_dev;
        struct timer_list timer;
        unsigned char keycodes[ADKEYNUM];
-       struct clk *clk;
        void __iomem *mmio_base;
 };
 
@@ -112,6 +114,17 @@ unsigned int rk28_get_keycode(unsigned int advalue,pADC_keyst ptab)
        return 0;
 }
 
+static irqreturn_t rk2818_playkey_irq(int irq, void *handle)
+{ 
+       input_report_key(pRk28AdcKey->input_dev,KEYSTART,1);
+       input_sync(pRk28AdcKey->input_dev);
+       input_report_key(pRk28AdcKey->input_dev,KEYSTART,0);
+       input_sync(pRk28AdcKey->input_dev);
+       printk("Enter::%s,LINE=%d,KEYSTART=%d,0\n",__FUNCTION__,__LINE__,KEYSTART);
+       
+       return IRQ_HANDLED;
+}
+
 static int rk28_adckey_open(struct input_dev *dev)
 {
        //struct rk28_adckey *adckey = input_get_drvdata(dev);
@@ -128,26 +141,20 @@ static void rk28_adckey_close(struct input_dev *dev)
 #ifdef CONFIG_PM
 static int rk28_adckey_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct rk28_adckey *adckey = platform_get_drvdata(pdev);
+       //struct rk28_adckey *adckey = platform_get_drvdata(pdev);
 
-       clk_disable(adckey->clk);
        return 0;
 }
 
 static int rk28_adckey_resume(struct platform_device *pdev)
 {
-       struct rk28_adckey *adckey = platform_get_drvdata(pdev);
-       struct input_dev *input_dev = adckey->input_dev;
-
+       //struct rk28_adckey *adckey = platform_get_drvdata(pdev);
+       //struct input_dev *input_dev = adckey->input_dev;
+#if 0
        mutex_lock(&input_dev->mutex);
 
-       if (input_dev->users) {
-               /* Enable unit clock */
-               clk_enable(adckey->clk);
-       }
-
        mutex_unlock(&input_dev->mutex);
-
+#endif
        return 0;
 }
 #else
@@ -267,7 +274,7 @@ static int __devinit rk28_adckey_probe(struct platform_device *pdev)
        if (!input_dev) {
                dev_err(&pdev->dev, "failed to allocate input device\n");
                error = -ENOMEM;
-               goto failed_put_clk;
+               goto failed_free;
        }
 
        input_dev->name = pdev->name;
@@ -314,17 +321,33 @@ static int __devinit rk28_adckey_probe(struct platform_device *pdev)
                goto failed_free_dev;
        }
 
+       error = gpio_request(KEY_PLAYON_PIN, "play key gpio");
+       if (error) {
+               dev_err(&pdev->dev, "failed to request play key gpio\n");
+               goto free_gpio;
+       }
+       
+       gpio_pull_updown(KEY_PLAYON_PIN,GPIOPullUp);
+       error = request_irq(gpio_to_irq(KEY_PLAYON_PIN),rk2818_playkey_irq,IRQF_TRIGGER_FALLING,NULL,NULL);  
+       if(error)
+       {
+               printk("unable to request play key irq\n");
+               goto free_gpio_irq;
+       }       
+
        setup_timer(&adckey->timer, rk28_adkeyscan_timer, (unsigned long)adckey);
        adckey->timer.expires  = jiffies+50;
        add_timer(&adckey->timer);
-       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);
+       printk(KERN_INFO "rk2818_adckey: driver initialized\n");
        return 0;
-
+       
+free_gpio_irq:
+       free_irq(gpio_to_irq(KEY_PLAYON_PIN),NULL);
+free_gpio:     
+       gpio_free(KEY_PLAYON_PIN);
 failed_free_dev:
        platform_set_drvdata(pdev, NULL);
        input_free_device(input_dev);
-failed_put_clk:
-       //clk_put(adckey->clk);
 failed_free:
        kfree(adckey);
        return error;
@@ -339,6 +362,9 @@ static int __devexit rk28_adckey_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
        rk28_adc_release(adckey->client);
        kfree(adckey);
+       free_irq(gpio_to_irq(KEY_PLAYON_PIN),NULL);
+       gpio_free(KEY_PLAYON_PIN);
+       
        return 0;
 }
 
@@ -356,7 +382,6 @@ static struct platform_driver rk28_adckey_driver =
 
  int __init rk28_adckey_init(void)
 {
-       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);
        return platform_driver_register(&rk28_adckey_driver);
 }
 
index cea6cef27e893f36f96d168724e6befa5429e085..c91ed7f7e27fd48644262eec585a97a7915c44d2 100644 (file)
@@ -110,4 +110,9 @@ config CHARGER_PCF50633
        help
         Say Y to include support for NXP PCF50633 Main Battery Charger.
 
+config BATTERY_RK2818
+       tristate "RK2818 battery"
+       depends on KEYBOARD_RK28ADC
+       help
+         Say Y to enable support for the battery on the RK2818.
 endif # POWER_SUPPLY
index b96f29d91c284b3719075d4995f3b5d0f20598fc..10caf2200b8501bee35ecf5565c0c789a3084371 100644 (file)
@@ -29,3 +29,4 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)   += da9030_battery.o
 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
 obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+obj-$(CONFIG_BATTERY_RK2818)   += rk2818_battery.o
diff --git a/drivers/power/rk2818_battery.c b/drivers/power/rk2818_battery.c
new file mode 100644 (file)
index 0000000..31921f3
--- /dev/null
@@ -0,0 +1,410 @@
+/* drivers/power/rk2818_battery.c
+ *
+ * Power supply driver for the rk2818 emulator
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <mach/adc.h>
+
+#if 1
+#define DBG(x...)   printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define CHN_BAT_ADC    0
+#define CHN_USB_ADC    2
+#define BATT_LEVEL_EMPTY       0
+#define BATT_PRESENT_TRUE       1
+#define BATT_PRESENT_FALSE  0
+#define BATT_NOMAL_VOL_VALUE   4000
+
+static int gBatStatus =  POWER_SUPPLY_STATUS_UNKNOWN;
+static int gBatHealth = POWER_SUPPLY_HEALTH_GOOD;
+static int gBatCapacity = BATT_LEVEL_EMPTY;
+static int gBatPresent = BATT_PRESENT_TRUE;
+static int gBatVoltage =  BATT_NOMAL_VOL_VALUE;
+extern int dwc_vbus_status(void);
+
+struct rk2818_battery_data {
+       int irq;
+       spinlock_t lock;
+       struct timer_list timer;
+       struct power_supply battery;
+       struct power_supply usb;
+       struct power_supply ac;
+       
+       int adc_bat_divider;
+       int bat_max;
+       int bat_min;
+};
+
+#define RK2818_BATTERY_WRITE(data, addr, x)   (writel(x, data->reg_base + addr))
+
+
+/* temporary variable used between rk2818_battery_probe() and rk2818_battery_open() */
+static struct rk2818_battery_data *gBatteryData;
+
+enum {
+       BATTERY_STATUS          = 0,
+       BATTERY_HEALTH          = 1,
+       BATTERY_PRESENT         = 2,
+       BATTERY_CAPACITY        = 3,
+       BATTERY_AC_ONLINE       = 4,
+       BATTERY_STATUS_CHANGED  = 5,
+       AC_STATUS_CHANGED       = 6,
+       BATTERY_INT_STATUS          = 7,
+       BATTERY_INT_ENABLE          = 8,
+};
+
+typedef enum {
+       CHARGER_BATTERY = 0,
+       CHARGER_USB,
+       CHARGER_AC
+} charger_type_t;
+
+static int rk2818_get_charge_status(void)
+{
+       //return dwc_vbus_status();
+       return 1;
+}
+
+static void rk2818_get_bat_status(struct rk2818_battery_data *bat)
+{
+       if(rk2818_get_charge_status() == 1)
+       gBatStatus = POWER_SUPPLY_STATUS_CHARGING;
+       else
+       gBatStatus = POWER_SUPPLY_STATUS_NOT_CHARGING;  
+}
+
+static void rk2818_get_bat_health(struct rk2818_battery_data *bat)
+{
+       gBatHealth = POWER_SUPPLY_HEALTH_GOOD;
+}
+
+static void rk2818_get_bat_present(struct rk2818_battery_data *bat)
+{
+       if(gBatVoltage < bat->bat_min)
+       gBatPresent = 0;
+       else
+       gBatPresent = 1;
+}
+
+static void rk2818_get_bat_voltage(struct rk2818_battery_data *bat)
+{
+       unsigned long value;
+       value = gAdcValue[CHN_BAT_ADC];
+       gBatVoltage = value * 1000000 / bat->adc_bat_divider;
+}
+
+static void rk2818_get_bat_capacity(struct rk2818_battery_data *bat)
+{
+       gBatCapacity = (gBatVoltage * 100) / bat->bat_max;
+}
+
+
+static void rk2818_batscan_timer(unsigned long data)
+{
+       gBatteryData->timer.expires  = jiffies + msecs_to_jiffies(20);
+       add_timer(&gBatteryData->timer);        
+       rk2818_get_bat_status(gBatteryData);
+       rk2818_get_bat_health(gBatteryData);
+       rk2818_get_bat_present(gBatteryData);
+       rk2818_get_bat_voltage(gBatteryData);
+       rk2818_get_bat_capacity(gBatteryData);
+
+}
+
+
+static int rk2818_usb_get_property(struct power_supply *psy, 
+                                   enum power_supply_property psp,
+                                   union power_supply_propval *val)
+{
+       charger_type_t charger;
+       //todo 
+       charger =  CHARGER_USB;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               if (psy->type == POWER_SUPPLY_TYPE_USB)
+                       val->intval = (charger ==  CHARGER_AC ? 1 : 0);
+               else
+                       val->intval = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       
+       return 0;
+
+}
+
+
+static int rk2818_ac_get_property(struct power_supply *psy,
+                       enum power_supply_property psp,
+                       union power_supply_propval *val)
+{
+//     struct rk2818_battery_data *data = container_of(psy,
+//             struct rk2818_battery_data, ac);
+       int ret = 0;
+       charger_type_t charger;
+       //todo 
+       charger =  CHARGER_USB;
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+                       val->intval = (charger ==  CHARGER_AC ? 1 : 0);
+               else if (psy->type == POWER_SUPPLY_TYPE_USB)
+                       val->intval = (charger ==  CHARGER_USB ? 1 : 0);
+               else
+                       val->intval = 0;
+               //val->intval = RK2818_BATTERY_READ(data, BATTERY_AC_ONLINE);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static int rk2818_battery_get_property(struct power_supply *psy,
+                                enum power_supply_property psp,
+                                union power_supply_propval *val)
+{
+       struct rk2818_battery_data *data = container_of(psy,
+               struct rk2818_battery_data, battery);
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = gBatStatus;
+               DBG("gBatStatus=0x%x\n",val->intval);
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               val->intval = gBatHealth;
+               DBG("gBatHealth=0x%x\n",val->intval);
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = gBatPresent;
+               DBG("gBatPresent=0x%x\n",val->intval);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val ->intval = gBatVoltage;
+               DBG("gBatVoltage=0x%x\n",val->intval);
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;     
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               val->intval = gBatCapacity;
+               DBG("gBatCapacity=0x%x\n",val->intval);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               val->intval = data->bat_max;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = data->bat_min;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static enum power_supply_property rk2818_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+};
+
+static enum power_supply_property rk2818_usb_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+};
+
+
+static enum power_supply_property rk2818_ac_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+};
+#if 0
+static irqreturn_t rk2818_battery_interrupt(int irq, void *dev_id)
+{
+
+       unsigned long irq_flags;
+       struct rk2818_battery_data *data = dev_id;
+       uint32_t status;
+
+       spin_lock_irqsave(&data->lock, irq_flags);
+       /* read status flags, which will clear the interrupt */
+       //status = RK2818_BATTERY_READ(data, BATTERY_INT_STATUS);
+       status &= BATTERY_INT_MASK;
+
+       if (status & BATTERY_STATUS_CHANGED)
+               power_supply_changed(&data->battery);
+       if (status & AC_STATUS_CHANGED)
+               power_supply_changed(&data->ac);
+
+       spin_unlock_irqrestore(&data->lock, irq_flags);
+       return status ? IRQ_HANDLED : IRQ_NONE;
+
+       return IRQ_HANDLED;
+}
+#endif
+
+static int rk2818_battery_probe(struct platform_device *pdev)
+{
+       int ret;
+       //struct resource *r;
+       struct rk2818_battery_data *data;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL) {
+               ret = -ENOMEM;
+               goto err_data_alloc_failed;
+       }
+       spin_lock_init(&data->lock);
+
+       data->battery.properties = rk2818_battery_props;
+       data->battery.num_properties = ARRAY_SIZE(rk2818_battery_props);
+       data->battery.get_property = rk2818_battery_get_property;
+       data->battery.name = "battery";
+       data->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+       //data->adc_bat_divider = gAdcValue[3];
+       data->adc_bat_divider = 414;
+       DBG("adc_bat_divider=%d\n",data->adc_bat_divider);
+       data->bat_max = 4310000;
+       data->bat_min = 1551 * 1000000 / 414;
+
+       data->usb.properties = rk2818_usb_props;
+       data->usb.num_properties = ARRAY_SIZE(rk2818_ac_props);
+       data->usb.get_property = rk2818_usb_get_property;
+       data->usb.name = "usb";
+       data->usb.type = POWER_SUPPLY_TYPE_USB;
+
+       data->ac.properties = rk2818_ac_props;
+       data->ac.num_properties = ARRAY_SIZE(rk2818_ac_props);
+       data->ac.get_property = rk2818_ac_get_property;
+       data->ac.name = "ac";
+       data->ac.type = POWER_SUPPLY_TYPE_MAINS;
+       
+#if 0
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               printk(KERN_ERR "%s: platform_get_resource failed\n", pdev->name);
+               ret = -ENODEV;
+               goto err_no_io_base;
+       }
+
+       data->irq = platform_get_irq(pdev, 0);
+       if (data->irq < 0) {
+               printk(KERN_ERR "%s: platform_get_irq failed\n", pdev->name);
+               ret = -ENODEV;
+               goto err_no_irq;
+       }
+
+       ret = request_irq(data->irq, rk2818_battery_interrupt, IRQF_SHARED, pdev->name, data);
+       if (ret)
+               goto err_request_irq_failed;
+#endif
+       ret = power_supply_register(&pdev->dev, &data->ac);
+       if (ret)
+               goto err_ac_failed;
+
+       ret = power_supply_register(&pdev->dev, &data->usb);
+       if (ret)
+               goto err_usb_failed;
+
+       ret = power_supply_register(&pdev->dev, &data->battery);
+       if (ret)
+               goto err_battery_failed;
+
+       platform_set_drvdata(pdev, data);
+       gBatteryData = data;
+
+       setup_timer(&data->timer, rk2818_batscan_timer, (unsigned long)data);
+       data->timer.expires  = jiffies+50;
+       add_timer(&data->timer);
+       printk(KERN_INFO "rk2818_battery: driver initialized\n");
+       //RK2818_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK);
+       
+       return 0;
+
+err_battery_failed:
+       power_supply_unregister(&data->usb);
+err_usb_failed:
+       power_supply_unregister(&data->ac);
+err_ac_failed:
+       //free_irq(data->irq, data);
+//err_request_irq_failed:
+//err_no_irq:
+//err_no_io_base:
+       kfree(data);
+err_data_alloc_failed:
+       return ret;
+}
+
+static int rk2818_battery_remove(struct platform_device *pdev)
+{
+       struct rk2818_battery_data *data = platform_get_drvdata(pdev);
+
+       power_supply_unregister(&data->battery);
+       power_supply_unregister(&data->ac);
+
+       free_irq(data->irq, data);
+       kfree(data);
+       gBatteryData = NULL;
+       return 0;
+}
+
+static struct platform_driver rk2818_battery_device = {
+       .probe          = rk2818_battery_probe,
+       .remove         = rk2818_battery_remove,
+       .driver = {
+               .name = "rk2818-battery",
+               .owner  = THIS_MODULE,
+       }
+};
+
+static int __init rk2818_battery_init(void)
+{
+       return platform_driver_register(&rk2818_battery_device);
+}
+
+static void __exit rk2818_battery_exit(void)
+{
+       platform_driver_unregister(&rk2818_battery_device);
+}
+
+module_init(rk2818_battery_init);
+module_exit(rk2818_battery_exit);
+
+MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");
+