Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android2.3電池驅動優化

android2.3電池驅動優化

編輯:關於Android編程

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 <[email protected]>");   MODULE_DESCRIPTION("S3C battery driver for SMDK Board");   MODULE_LICENSE("GPL");   加入了AD相關的代碼,因為電池接在AD0上,通過采集AD0上的數據來判斷電量,改動不是很大,僅供大家參考。 源碼下載地址:點擊打開鏈接 積分多的可以給我點
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved