android2.3电池驱动优化

android2.3内核版本2.6.35.7,内核中已经自带了电池驱动,做项目是不能用的,下面是我修改过后的驱动源码:

/*
* linux/drivers/power/s3c_fake_battery.c
*
* Battery measurement code for S3C platform.
*
* based on palmtx_battery.c
*
* Copyright (C) 2009 Samsung Electronics.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/

#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/power_supply.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/irq.h>
#include <linux/wakelock.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <plat/gpio-cfg.h>

#define DRIVER_NAME        "sec-fake-battery"

#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <mach/regs-clock.h>
#include <mach/regs-adc.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
static void __iomem *base_addr;

typedef struct {
        wait_queue_head_t wait;
        int channel;
        int prescale;
} ADC_DEV;

static int __ADC_locked = 0;

static ADC_DEV adcdev;
static volatile int ev_adc = 0;
static int adc_data;

static struct clk        *adc_clock;


static int old_flag = 0;
#define __ADCREG(name)        (*(volatile unsigned long *)(base_addr + name))
#define ADCCON                        __ADCREG(S3C_ADCCON)        // ADC control
#define ADCTSC                        __ADCREG(S3C_ADCTSC)        // ADC touch screen control
#define ADCDLY                        __ADCREG(S3C_ADCDLY)        // ADC start or Interval Delay
#define ADCDAT0                        __ADCREG(S3C_ADCDAT0)        // ADC conversion data 0
#define ADCDAT1                        __ADCREG(S3C_ADCDAT1)        // ADC conversion data 1
#define ADCUPDN                        __ADCREG(S3C_ADCUPDN)        // Stylus Up/Down interrupt status

#define PRESCALE_DIS                (0 << 14)
#define PRESCALE_EN                        (1 << 14)
#define PRSCVL(x)                        ((x) << 6)
#define ADC_INPUT(x)                ((x) << 3)
#define ADC_START                        (1 << 0)
#define ADC_ENDCVT                        (1 << 15)

#define START_ADC_AIN(ch, prescale) \
        do { \
                ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
                ADCCON |= ADC_START; \
        } while (0)

#include <linux/workqueue.h>
struct delayed_work monitor_work;
struct workqueue_struct *monitor_wqueue;

struct delayed_work ad_work;
struct workqueue_struct *ad_wqueue;
static int ad_value=0;
static int times = 0;
#define ACIRQ                                IRQ_EINT(0)

#define ACIRQSTA                        S5PV210_GPH0(0)

static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{
#if        1
        if (__ADC_locked) {
                adc_data = ADCDAT0 & 0x3ff;

                ev_adc = 1;
                wake_up_interruptible(&adcdev.wait);

                /* clear interrupt */
                __raw_writel(0x0, base_addr + S3C_ADCCLRINT);
        }
#endif

        return IRQ_HANDLED;
}

static struct wake_lock vbus_wake_lock;

/* Prototypes */
extern int s3c_adc_get_adc_data(int channel);

static ssize_t s3c_bat_show_property(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf);
static ssize_t s3c_bat_store(struct device *dev,
                         struct device_attribute *attr,
                         const char *buf, size_t count);

#define FAKE_BAT_LEVEL        80

static struct device *dev;
static int s3c_battery_initial;
static int force_update;

static char *status_text[] = {
        [POWER_SUPPLY_STATUS_UNKNOWN] =                "Unknown",
        [POWER_SUPPLY_STATUS_CHARGING] =        "Charging",
        [POWER_SUPPLY_STATUS_DISCHARGING] =        "Discharging",
        [POWER_SUPPLY_STATUS_NOT_CHARGING] =        "Not Charging",
        [POWER_SUPPLY_STATUS_FULL] =                "Full",
};

typedef enum {
        CHARGER_BATTERY = 0,
        CHARGER_USB,
        CHARGER_AC,
        CHARGER_DISCHARGE
} charger_type_t;

struct battery_info {
        u32 batt_id;                /* Battery ID from ADC */
        u32 batt_vol;                /* Battery voltage from ADC */
        u32 batt_vol_adc;        /* Battery ADC value */
        u32 batt_vol_adc_cal;        /* Battery ADC value (calibrated)*/
        u32 batt_temp;                /* Battery Temperature (C) from ADC */
        u32 batt_temp_adc;        /* Battery Temperature ADC value */
        u32 batt_temp_adc_cal;        /* Battery Temperature ADC value (calibrated) */
        u32 batt_current;        /* Battery current from ADC */
        u32 level;                /* formula */
        u32 charging_source;        /* 0: no cable, 1:usb, 2:AC */
        u32 charging_enabled;        /* 0: Disable, 1: Enable */
        u32 batt_health;        /* Battery Health (Authority) */
        u32 batt_is_full; /* 0 : Not full 1: Full */
};

/* lock to protect the battery info */
static DEFINE_MUTEX(work_lock);

struct s3c_battery_info {
        int present;
        int polling;
        unsigned long polling_interval;

        struct battery_info bat_info;
};
static struct s3c_battery_info s3c_bat_info;

static int s3c_adc_read(void)
{
        int value;
        __ADC_locked = 1;

        START_ADC_AIN(adcdev.channel, adcdev.prescale);

        wait_event_interruptible(adcdev.wait, ev_adc);
        ev_adc = 0;
        value = adc_data;
        __ADC_locked = 0;
        return value;
}

static int s3c_get_bat_level(struct power_supply *bat_ps)
{
        int level;
        int voltage;
        //level = s3c_adc_read();
        //printk("times is %d\n",times);
        level = ad_value / times;
        ad_value = 0;
        times = 0;
        //printk("read ad is +++++++++++++++++++++++++ %d\n",level);

        voltage = (level * 3300) / 10230;
        //printk("voltage is +++++++++++++++++++++++++ %d\n",voltage);
        if(voltage < 185)
                level = 0;
        else if(voltage > 210)
                level = 100;
        else
                level = (voltage - 185) * 4;
        //printk("report level is %d\n",level);
        return level;
}

static int s3c_get_bat_vol(struct power_supply *bat_ps)
{
        int bat_vol = 0;

        return bat_vol;
}

static u32 s3c_get_bat_health(void)
{
        return s3c_bat_info.bat_info.batt_health;
}

static int s3c_get_bat_temp(struct power_supply *bat_ps)
{
        int temp = 0;

        return temp;
}

static int s3c_bat_get_charging_status(void)
{
        charger_type_t charger = CHARGER_BATTERY;
        int ret = 0;
        
        charger = s3c_bat_info.bat_info.charging_source;
        
        switch (charger) {
        case CHARGER_BATTERY:
                ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
                break;
        case CHARGER_USB:
        case CHARGER_AC:
                if (s3c_bat_info.bat_info.level == 100
                        && s3c_bat_info.bat_info.batt_is_full) {
                        ret = POWER_SUPPLY_STATUS_FULL;
                } else {
                        ret = POWER_SUPPLY_STATUS_CHARGING;
                }
                break;
        case CHARGER_DISCHARGE:
                ret = POWER_SUPPLY_STATUS_DISCHARGING;
                break;
        default:
                ret = POWER_SUPPLY_STATUS_UNKNOWN;
        }
        dev_dbg(dev, "%s : %s\n", __func__, status_text[ret]);

        return ret;
}

static int s3c_bat_get_property(struct power_supply *bat_ps,
                enum power_supply_property psp,
                union power_supply_propval *val)
{
        dev_dbg(bat_ps->dev, "%s : psp = %d\n", __func__, psp);

        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
                val->intval = s3c_bat_get_charging_status();
                break;
        case POWER_SUPPLY_PROP_HEALTH:
                val->intval = s3c_get_bat_health();
                break;
        case POWER_SUPPLY_PROP_PRESENT:
                val->intval = s3c_bat_info.present;
                break;
        case POWER_SUPPLY_PROP_TECHNOLOGY:
                val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
                val->intval = s3c_bat_info.bat_info.level;
                dev_dbg(dev, "%s : level = %d\n", __func__,
                                val->intval);
                break;
        case POWER_SUPPLY_PROP_TEMP:
                val->intval = s3c_bat_info.bat_info.batt_temp;
                dev_dbg(bat_ps->dev, "%s : temp = %d\n", __func__,
                                val->intval);
                break;
        default:
                return -EINVAL;
        }
        return 0;
}

static int s3c_power_get_property(struct power_supply *bat_ps,
                enum power_supply_property psp,
                union power_supply_propval *val)
{
        charger_type_t charger;
        
        dev_dbg(bat_ps->dev, "%s : psp = %d\n", __func__, psp);

        charger = s3c_bat_info.bat_info.charging_source;
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
                if (bat_ps->type == POWER_SUPPLY_TYPE_MAINS)
                        val->intval = (charger == CHARGER_AC ? 1 : 0);
                else if (bat_ps->type == POWER_SUPPLY_TYPE_USB)
                        val->intval = (charger == CHARGER_USB ? 1 : 0);
                else
                        val->intval = 0;
                break;
        default:
                return -EINVAL;
        }
        
        return 0;
}

#define SEC_BATTERY_ATTR(_name)                                                                \
{                                                                                        \
        .attr = { .name = #_name, .mode = S_IRUGO | S_IWUGO, .owner = THIS_MODULE },        \
        .show = s3c_bat_show_property,                                                        \
        .store = s3c_bat_store,                                                                \
}

static struct device_attribute s3c_battery_attrs[] = {
        SEC_BATTERY_ATTR(batt_vol),
        SEC_BATTERY_ATTR(batt_vol_adc),
        SEC_BATTERY_ATTR(batt_vol_adc_cal),
        SEC_BATTERY_ATTR(batt_temp),
        SEC_BATTERY_ATTR(batt_temp_adc),
        SEC_BATTERY_ATTR(batt_temp_adc_cal),
};

enum {
        BATT_VOL = 0,
        BATT_VOL_ADC,
        BATT_VOL_ADC_CAL,
        BATT_TEMP,
        BATT_TEMP_ADC,
        BATT_TEMP_ADC_CAL,
};

static int s3c_bat_create_attrs(struct device * dev)
{
        int i, rc;

        for (i = 0; i < ARRAY_SIZE(s3c_battery_attrs); i++) {
                rc = device_create_file(dev, &s3c_battery_attrs[i]);
                if (rc)
                goto s3c_attrs_failed;
        }
        goto succeed;

s3c_attrs_failed:
        while (i--)
        device_remove_file(dev, &s3c_battery_attrs[i]);
succeed:
        return rc;
}

static ssize_t s3c_bat_show_property(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf)
{
        int i = 0;
        const ptrdiff_t off = attr - s3c_battery_attrs;

        switch (off) {
        case BATT_VOL:
                i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
                                 s3c_bat_info.bat_info.batt_vol);
        break;
        case BATT_VOL_ADC:
                i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
                                 s3c_bat_info.bat_info.batt_vol_adc);
                break;
        case BATT_VOL_ADC_CAL:
                i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
                                 s3c_bat_info.bat_info.batt_vol_adc_cal);
                break;
        case BATT_TEMP:
                i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
                                 s3c_bat_info.bat_info.batt_temp);
                break;
        case BATT_TEMP_ADC:
                i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
                                 s3c_bat_info.bat_info.batt_temp_adc);
                break;        
        case BATT_TEMP_ADC_CAL:
                i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
                                 s3c_bat_info.bat_info.batt_temp_adc_cal);
                break;
        default:
                i = -EINVAL;
        }

        return i;
}

static ssize_t s3c_bat_store(struct device *dev,
                         struct device_attribute *attr,
                         const char *buf, size_t count)
{
        int x = 0;
        int ret = 0;
        const ptrdiff_t off = attr - s3c_battery_attrs;

        switch (off) {
        case BATT_VOL_ADC_CAL:
                if (sscanf(buf, "%d\n", &x) == 1) {
                        s3c_bat_info.bat_info.batt_vol_adc_cal = x;
                        ret = count;
                }
                dev_info(dev, "%s : batt_vol_adc_cal = %d\n", __func__, x);
                break;
        case BATT_TEMP_ADC_CAL:
                if (sscanf(buf, "%d\n", &x) == 1) {
                        s3c_bat_info.bat_info.batt_temp_adc_cal = x;
                        ret = count;
                }
                dev_info(dev, "%s : batt_temp_adc_cal = %d\n", __func__, x);
                break;
        default:
                ret = -EINVAL;
        }

        return ret;
}

static enum power_supply_property s3c_battery_properties[] = {
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_HEALTH,
        POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_TECHNOLOGY,
        POWER_SUPPLY_PROP_CAPACITY,
};

static enum power_supply_property s3c_power_properties[] = {
        POWER_SUPPLY_PROP_ONLINE,
};

static char *supply_list[] = {
        "battery",
};

static struct power_supply s3c_power_supplies[] = {
        {
                .name = "battery",
                .type = POWER_SUPPLY_TYPE_BATTERY,
                .properties = s3c_battery_properties,
                .num_properties = ARRAY_SIZE(s3c_battery_properties),
                .get_property = s3c_bat_get_property,
        },
        {
                .name = "usb",
                .type = POWER_SUPPLY_TYPE_USB,
                .supplied_to = supply_list,
                .num_supplicants = ARRAY_SIZE(supply_list),
                .properties = s3c_power_properties,
                .num_properties = ARRAY_SIZE(s3c_power_properties),
                .get_property = s3c_power_get_property,
        },
        {
                .name = "ac",
                .type = POWER_SUPPLY_TYPE_MAINS,
                .supplied_to = supply_list,
                .num_supplicants = ARRAY_SIZE(supply_list),
                .properties = s3c_power_properties,
                .num_properties = ARRAY_SIZE(s3c_power_properties),
                .get_property = s3c_power_get_property,
        },
};

static int s3c_cable_status_update(int status)
{
        int ret = 0;
        charger_type_t source = CHARGER_BATTERY;

        dev_dbg(dev, "%s\n", __func__);

        if(!s3c_battery_initial)
                return -EPERM;

        switch(status) {
        case CHARGER_BATTERY:
                dev_dbg(dev, "%s : cable NOT PRESENT\n", __func__);
                s3c_bat_info.bat_info.charging_source = CHARGER_BATTERY;
                break;
        case CHARGER_USB:
                dev_dbg(dev, "%s : cable USB\n", __func__);
                s3c_bat_info.bat_info.charging_source = CHARGER_USB;
                break;
        case CHARGER_AC:
                dev_dbg(dev, "%s : cable AC\n", __func__);
                s3c_bat_info.bat_info.charging_source = CHARGER_AC;
                break;
        case CHARGER_DISCHARGE:
                dev_dbg(dev, "%s : Discharge\n", __func__);
                s3c_bat_info.bat_info.charging_source = CHARGER_DISCHARGE;
                break;
        default:
                dev_err(dev, "%s : Nat supported status\n", __func__);
                ret = -EINVAL;
        }
        source = s3c_bat_info.bat_info.charging_source;

        if (source == CHARGER_USB || source == CHARGER_AC) {
                wake_lock(&vbus_wake_lock);
        } else {
                /* give userspace some time to see the uevent and update
                 * LED state or whatnot...
                 */
                wake_lock_timeout(&vbus_wake_lock, HZ / 2);
        }

        /* if the power source changes, all power supplies may change state */
        power_supply_changed(&s3c_power_supplies[CHARGER_BATTERY]);
        /*
        power_supply_changed(&s3c_power_supplies[CHARGER_USB]);
        power_supply_changed(&s3c_power_supplies[CHARGER_AC]);
        */
        dev_dbg(dev, "%s : call power_supply_changed\n", __func__);
        return ret;
}

static void s3c_bat_status_update(struct power_supply *bat_ps)
{
        int old_level, old_temp, old_is_full;
        dev_dbg(dev, "%s ++\n", __func__);

        if(!s3c_battery_initial)
                return;

        mutex_lock(&work_lock);
        old_temp = s3c_bat_info.bat_info.batt_temp;
        old_level = s3c_bat_info.bat_info.level;
        old_is_full = s3c_bat_info.bat_info.batt_is_full;
        s3c_bat_info.bat_info.batt_temp = s3c_get_bat_temp(bat_ps);
        s3c_bat_info.bat_info.level = s3c_get_bat_level(bat_ps);
        s3c_bat_info.bat_info.batt_vol = s3c_get_bat_vol(bat_ps);

        if (old_level != s3c_bat_info.bat_info.level
                        || old_temp != s3c_bat_info.bat_info.batt_temp
                        || old_is_full != s3c_bat_info.bat_info.batt_is_full
                        || force_update) {
                force_update = 0;
                power_supply_changed(bat_ps);
                dev_dbg(dev, "%s : call power_supply_changed\n", __func__);
        }

        mutex_unlock(&work_lock);
        dev_dbg(dev, "%s --\n", __func__);
}

void s3c_cable_check_status(int flag)
{
    charger_type_t status = 0;
    
#ifdef        USB_CHARG
#else
    if(flag == 1) //usb not supports charging
        return;
#endif
    switch(flag) {
        case 0: // Battery
                status = CHARGER_BATTERY;
                break;
            case 1:
                status = CHARGER_USB;
                break;
        case 2:
                status = CHARGER_AC;
                break;
        default:
                status = CHARGER_BATTERY;
                break;
    }
#ifdef        USB_CHARG
#else
#endif
    if(!gpio_get_value(ACIRQSTA)) {
        status = CHARGER_AC;
        flag = 2;
    }
    s3c_cable_status_update(status);
    old_flag = flag;
}
EXPORT_SYMBOL(s3c_cable_check_status);

#ifdef CONFIG_PM
static int s3c_bat_suspend(struct platform_device *pdev,
                pm_message_t state)
{
        dev_info(dev, "%s\n", __func__);

        return 0;
}

static int s3c_bat_resume(struct platform_device *pdev)
{
        dev_info(dev, "%s\n", __func__);

        return 0;
}
#else
#define s3c_bat_suspend NULL
#define s3c_bat_resume NULL
#endif /* CONFIG_PM */
static irqreturn_t ac_status(int irq, void *dev_id)
{
        int status;
        disable_irq_nosync(irq);
        status = gpio_get_value(ACIRQSTA);
        if(status)
                s3c_cable_check_status(CHARGER_BATTERY);
        else
                s3c_cable_check_status(CHARGER_AC);
        enable_irq(irq);
        return IRQ_HANDLED;
}

static void s3c_battery_work(struct work_struct *work)
{
        const int interval = HZ * 60;
        s3c_bat_status_update(&s3c_power_supplies[CHARGER_BATTERY]);
        queue_delayed_work(monitor_wqueue, &monitor_work, interval);
}

static void s3c_ad_work(struct work_struct *work)
{
        const int interval = HZ * 1;
        ad_value += s3c_adc_read();
        times ++;
        queue_delayed_work(ad_wqueue, &ad_work, interval);
}

static int __devinit s3c_bat_probe(struct platform_device *pdev)
{
        int i;
        int ret = 0;

        dev = &pdev->dev;
        dev_info(dev, "%s\n", __func__);

        s3c_bat_info.present = 1;

        s3c_bat_info.bat_info.batt_id = 0;
        s3c_bat_info.bat_info.batt_vol = 0;
        s3c_bat_info.bat_info.batt_vol_adc = 0;
        s3c_bat_info.bat_info.batt_vol_adc_cal = 0;
        s3c_bat_info.bat_info.batt_temp = 0;
        s3c_bat_info.bat_info.batt_temp_adc = 0;
        s3c_bat_info.bat_info.batt_temp_adc_cal = 0;
        s3c_bat_info.bat_info.batt_current = 0;
        s3c_bat_info.bat_info.level = 0;
        s3c_bat_info.bat_info.charging_source = CHARGER_BATTERY;
        s3c_bat_info.bat_info.charging_enabled = 0;
        s3c_bat_info.bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD;

        /* init power supplier framework */
        for (i = 0; i < ARRAY_SIZE(s3c_power_supplies); i++) {
                ret = power_supply_register(&pdev->dev,
                                &s3c_power_supplies[i]);
                if (ret) {
                        dev_err(dev, "Failed to register"
                                        "power supply %d,%d\n", i, ret);
                        goto __end__;
                }
        }

        /* create sec detail attributes */
        s3c_bat_create_attrs(s3c_power_supplies[CHARGER_BATTERY].dev);

        s3c_battery_initial = 1;
        force_update = 0;

        //s3c_bat_status_update(
                        //&s3c_power_supplies[CHARGER_BATTERY]);

        base_addr = ioremap(SAMSUNG_PA_ADC, 0x20);
        if (base_addr == NULL) {
                printk(KERN_ERR "Failed to remap register block\n");
                return -ENOMEM;
        }
        adc_clock = clk_get(NULL, "adc");
        if (!adc_clock) {
                printk(KERN_ERR "failed to get adc clock source\n");
                return -ENOENT;
        }
        clk_enable(adc_clock);
        
        /* normal ADC */
        ADCTSC = 0;

        ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DRIVER_NAME, &adcdev);
        if (ret) {
                printk("request IRQ %d failed for adc, %d\n", IRQ_ADC, ret);
                iounmap(base_addr);
                return ret;
        }

        init_waitqueue_head(&(adcdev.wait));

        if(!gpio_get_value(ACIRQSTA))
                s3c_cable_check_status(CHARGER_AC);

        ret = request_irq(IRQ_EINT(0), ac_status, IRQ_TYPE_EDGE_BOTH, DRIVER_NAME, &dev);
        if (ret) {
                printk("request IRQ %d failed for adc, %d\n", IRQ_EINT(0), ret);
                iounmap(base_addr);
                return ret;
        }

        adcdev.channel=0;
        adcdev.prescale=0xff;

        INIT_DELAYED_WORK(&ad_work, s3c_ad_work);
        ad_wqueue = create_singlethread_workqueue(dev_name(&pdev->dev));
        queue_delayed_work(ad_wqueue, &ad_work, HZ * 1);

        INIT_DELAYED_WORK(&monitor_work, s3c_battery_work);
        monitor_wqueue = create_singlethread_workqueue(dev_name(&pdev->dev));
        queue_delayed_work(monitor_wqueue, &monitor_work, HZ * 2);

__end__:
        return ret;
}

static int __devexit s3c_bat_remove(struct platform_device *pdev)
{
        int i;
        dev_info(dev, "%s\n", __func__);

        for (i = 0; i < ARRAY_SIZE(s3c_power_supplies); i++) {
                power_supply_unregister(&s3c_power_supplies[i]);
        }
 
        free_irq(IRQ_ADC, &adcdev);
        iounmap(base_addr);

        if (adc_clock) {
                clk_disable(adc_clock);
                clk_put(adc_clock);
                adc_clock = NULL;
        }
        return 0;
}

static struct platform_driver s3c_bat_driver = {
        .driver.name        = DRIVER_NAME,
        .driver.owner        = THIS_MODULE,
        .probe                = s3c_bat_probe,
        .remove                = __devexit_p(s3c_bat_remove),
        .suspend        = s3c_bat_suspend,
        .resume                = s3c_bat_resume,
};

/* Initailize GPIO */
static void s3c_bat_init_hw(void)
{
}

static int __init s3c_bat_init(void)
{
        pr_info("%s\n", __func__);

        s3c_bat_init_hw();

        wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");

        return platform_driver_register(&s3c_bat_driver);
}

static void __exit s3c_bat_exit(void)
{
        pr_info("%s\n", __func__);
        platform_driver_unregister(&s3c_bat_driver);
}

module_init(s3c_bat_init);
module_exit(s3c_bat_exit);

MODULE_AUTHOR("HuiSung Kang <hs1218.kang@samsung.com>");
MODULE_DESCRIPTION("S3C battery driver for SMDK Board");
MODULE_LICENSE("GPL");

加入了AD相关的代码,因为电池接在AD0上,通过采集AD0上的数据来判断电量,改动不是很大,仅供大家参考。

源码下载地址:点击打开链接 积分多的可以给我点


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值