luowei modify battery driver on 100521
author罗伟 <lw@rock-chips.com>
Fri, 21 May 2010 07:20:28 +0000 (07:20 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:35:15 +0000 (13:35 +0800)
arch/arm/mach-rk2818/adc.c
drivers/input/keyboard/rk2818_adckey.c
drivers/power/Kconfig
drivers/power/rk2818_battery.c

index f3e762cfc01a9518be9fa06d00d91b270b00b09d..46e34fe9c4a4e59e94c2749ff2a996582f9a6641 100644 (file)
  * and stores information such as the necessary functions to callback when
  * action is required.
  */
+#if 1
+#define DBG(x...)   printk(x)
+#else
+#define DBG(x...)
+#endif
 
 struct rk28_adc_client {
        struct platform_device  *pdev;
        struct list_head         pend;
        wait_queue_head_t       *wait;
-
        unsigned int             nr_samples;
        int                      result;
        unsigned char            is_ts;
@@ -47,18 +52,22 @@ struct rk28_adc_client {
 };
 
 struct adc_device {
+       struct semaphore        lock;
        struct platform_device  *pdev;
        struct platform_device  *owner;
        struct clk              *clk;
+       struct rk28_adc_client  *client;
        struct rk28_adc_client  *cur;
        struct rk28_adc_client  *ts_pend;
        void __iomem            *regs;
-
+       struct timer_list timer;
        unsigned int             pre_con;
        int                      irq;
 };
 
 static struct adc_device *pAdcDev;
+volatile int gAdcChanel = 0;
+volatile int gAdcValue[4]={0, 0, 0, 0};        //0->ch0 1->ch1 2->ch2 3->ch3
 
 static LIST_HEAD(adc_pending);
 
@@ -278,6 +287,34 @@ void rk28_adc_release(struct rk28_adc_client *client)
 }
 EXPORT_SYMBOL_GPL(rk28_adc_release);
 
+
+//read four ADC chanel
+static int rk28_read_adc(struct adc_device *adc)
+{
+       int ret = 0,i;
+       
+       ret = down_interruptible(&adc->lock);
+       if (ret < 0)
+               return ret;     
+
+       for(i=0; i<4; i++)
+       {
+               gAdcValue[i] = rk28_adc_read(adc->client, i);
+               //DBG("gAdcValue[%d]=%d\n",i,gAdcValue[i]);
+       }
+
+       up(&adc->lock);
+       return ret;
+}
+
+static void rk28_adcscan_timer(unsigned long data)
+{
+       pAdcDev->timer.expires  = jiffies + msecs_to_jiffies(30);
+       add_timer(&pAdcDev->timer);
+
+       rk28_read_adc(pAdcDev);
+}
+
 static irqreturn_t rk28_adc_irq(int irq, void *pw)
 {
        struct adc_device *adc = pw;
@@ -373,9 +410,23 @@ static int rk28_adc_probe(struct platform_device *pdev)
        dev_info(dev, "attached adc driver\n");
        
        platform_set_drvdata(pdev, adc);
+
+       init_MUTEX(&adc->lock);
        
+       /* Register with the core ADC driver. */
+       adc->client = rk28_adc_register(pdev, NULL, NULL, 0);
+       if (IS_ERR(adc->client)) {
+               dev_err(dev, "cannot register adc\n");
+               ret = PTR_ERR(adc->client);
+               goto err_clk;
+       }
+
        rk28_adc_int_disable(adc);
        pAdcDev = adc;
+       
+       setup_timer(&adc->timer, rk28_adcscan_timer, (unsigned long)adc);
+       adc->timer.expires  = jiffies + 50;
+       add_timer(&adc->timer);
        printk(KERN_INFO "rk2818 adc: driver initialized\n");
        return 0;
 
@@ -394,6 +445,7 @@ static int rk28_adc_remove(struct platform_device *pdev)
 {
        struct adc_device *adc = platform_get_drvdata(pdev);
        rk28_adc_power_down(adc);
+       rk28_adc_release(adc->client);
        iounmap(adc->regs);
        free_irq(adc->irq, adc);
        clk_disable(adc->clk);
index e8e2a82c392d769e07838bd941729617a580a827..4b33162010ad2600ae77eabc376b8326351c55a9 100644 (file)
@@ -26,7 +26,7 @@
 #include <mach/gpio.h>
 #include <mach/adc.h>
 
-#if 1
+#if 0
 #define DBG(x...)   printk(x)
 #else
 #define DBG(x...)
@@ -56,8 +56,6 @@
 #define KEY_PHYS_NAME  "rk2818_adckey/input0"
 
 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;
@@ -161,24 +159,6 @@ static int rk28_adckey_resume(struct platform_device *pdev)
 #define rk28_adckey_suspend    NULL
 #define rk28_adckey_resume     NULL
 #endif
-
-//read four ADC chanel
-static int rk28_read_adc(struct rk28_adckey *adckey)
-{
-       int ret;
-
-       ret = down_interruptible(&adckey->lock);
-       if (ret < 0)
-               return ret;     
-       if(gAdcChanel > 3)
-               gAdcChanel = 0;
-       gAdcValue[gAdcChanel] = rk28_adc_read(adckey->client, gAdcChanel);
-       //DBG("Enter::%s,LINE=%d,gAdcValue[%d]=%d\n",__FUNCTION__,__LINE__,gAdcChanel,gAdcValue[gAdcChanel]);
-       gAdcChanel++;
-       up(&adckey->lock);
-       return ret;
-}
-
 static void rk28_adkeyscan_timer(unsigned long data)
 {
        unsigned int adcvalue = -1, code;
@@ -194,7 +174,7 @@ static void rk28_adkeyscan_timer(unsigned long data)
        
        gADSampleTimes = 0;
 
-       rk28_read_adc(pRk28AdcKey);     
+       //rk28_read_adc(pRk28AdcKey);   
        adcvalue = gAdcValue[ADKEYCH];
        if((adcvalue > ADEmpty) || (adcvalue < ADInvalid))
        {
@@ -297,21 +277,11 @@ static int __devinit rk28_adckey_probe(struct platform_device *pdev)
        adckey->input_dev = input_dev;
        input_set_drvdata(input_dev, adckey);
 
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) ;
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
 
 //     rk28_adckey_build_keycode(adckey);
        platform_set_drvdata(pdev, adckey);
 
-       init_MUTEX(&adckey->lock);
-
-       /* Register with the core ADC driver. */
-       adckey->client = rk28_adc_register(pdev, NULL, NULL, 0);
-       if (IS_ERR(adckey->client)) {
-               dev_err(&pdev->dev, "cannot register adc\n");
-               error = PTR_ERR(adckey->client);
-               goto failed_free;
-       }
-
        pRk28AdcKey = adckey;
 
        /* Register the input device */
@@ -360,7 +330,6 @@ static int __devexit rk28_adckey_remove(struct platform_device *pdev)
        input_unregister_device(adckey->input_dev);
        input_free_device(adckey->input_dev);
        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);
index c91ed7f7e27fd48644262eec585a97a7915c44d2..f909f2f8f9fc575a15f9d1ec298a3590249a28b7 100644 (file)
@@ -112,7 +112,7 @@ config CHARGER_PCF50633
 
 config BATTERY_RK2818
        tristate "RK2818 battery"
-       depends on KEYBOARD_RK28ADC
+       depends on RK28_ADC
        help
          Say Y to enable support for the battery on the RK2818.
 endif # POWER_SUPPLY
index 31921f3342cbbbdeccd27c1122f2101fa3d81412..97b4bdb5c23fa42ef34d88a0db8824f65e6ab1da 100644 (file)
@@ -1,9 +1,6 @@
 /* drivers/power/rk2818_battery.c
  *
- * Power supply driver for the rk2818 emulator
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
+ * battery detect driver for the rk2818 
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #include <asm/io.h>
 #include <mach/adc.h>
 
-#if 1
+#if 0
 #define DBG(x...)   printk(x)
 #else
 #define DBG(x...)
 #endif
 
-#define CHN_BAT_ADC    0
+#define CHN_BAT_ADC    3
 #define CHN_USB_ADC    2
 #define BATT_LEVEL_EMPTY       0
 #define BATT_PRESENT_TRUE       1
@@ -44,6 +41,85 @@ 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;
+
+#if 0
+#define NUM_BAT        3
+#define NUM_ELECTRICITY        10
+
+#define BAT_CAP_1500MAH                0
+#define BAT_CAP_1200MAH                1
+#define BAT_CAP_1100MAH                2
+
+#define ELECTRICITY_1000MA     0
+#define ELECTRICITY_900MA      1
+#define ELECTRICITY_800MA      2
+#define ELECTRICITY_700MA      3
+#define ELECTRICITY_600MA      4
+#define ELECTRICITY_500MA      5
+#define ELECTRICITY_400MA      6
+#define ELECTRICITY_300MA      7
+#define ELECTRICITY_200MA      8
+#define ELECTRICITY_100MA      9
+
+#define BAT_SELECT     BAT_CAP_1200MAH
+#define ELECTRICITY_SELECT     ELECTRICITY_200MA
+
+//about 10 minutes before battery is exhaust for different bat and electricity
+static int BatMinVoltage[NUM_BAT][NUM_ELECTRICITY] = 
+{
+{3410, 3450, 3480, 3460, 3480, 3500, 3510, 3470, 3420, 3430},
+{3360, 3400, 3410, 3400, 3430, 3430, 3460, 3480, 3440, 3330},
+{3360, 3400, 3410, 3410, 3440, 3460, 3480, 3470, 3440, 3360},
+};
+
+int gBatZeroVol        = BatMinVoltage[BAT_SELECT][ELECTRICITY_SELECT];
+int gBatMaxVol = 4300;
+
+#else
+int gBatMaxVol = 4300;
+int gBatZeroVol        = 3400;
+
+#endif
+
+/*******************ÒÔϲÎÊý¿ÉÒÔÐÞ¸Ä******************************/
+#define        TIMER_MS_COUNTS         50              //¶¨Ê±Æ÷µÄ³¤¶Èms
+#define        SLOPE_SECOND_COUNTS     60              //ͳ¼ÆµçѹбÂʵÄʱ¼ä¼ä¸ôs
+#define        TIME_UPDATE_STATUS      3000    //¸üÐÂµç³Ø×´Ì¬µÄʱ¼ä¼ä¸ôms
+#define        THRESHOLD_VOLTAGE_HIGH          3900
+#define        THRESHOLD_VOLTAGE_MID           3550
+#define        THRESHOLD_VOLTAGE_LOW           gBatZeroVol
+#define        THRESHOLD_SLOPE_HIGH            8       //ÕæÊµÐ±ÂÊÖµ
+#define        THRESHOLD_SLOPE_MID                     3               
+#define        THRESHOLD_SLOPE_LOW                     0
+
+/*************************************************************/
+#define LODER_HIGH_LEVEL               0       //¸ººÉ״̬µÈ¼¶
+#define        LODER_MID_LEVEL                 1
+#define        LODER_LOW_LEVEL                 2
+#define        LOADER_RELEASE_LEVEL    3       //µç³Ø¼´½«ºÄ¾¡×´Ì¬
+
+#define        SLOPE_HIGH_LEVEL                0       //µçѹ±ä»¯Ð±Âʵȼ¶
+#define        SLOPE_MID_LEVEL                 1
+#define        SLOPE_LOW_LEVEL                 2
+
+#define        VOLTAGE_HIGH_LEVEL              0       //µçѹ¸ßµÍµÈ¼¶
+#define        VOLTAGE_MID_LEVEL               1
+#define        VOLTAGE_LOW_LEVEL               2
+#define        VOLTAGE_RELEASE_LEVEL   3
+
+#define        NUM_VOLTAGE_SAMPLE      ((1000*SLOPE_SECOND_COUNTS) / TIMER_MS_COUNTS)  //´æ´¢µÄ²ÉÑùµã¸öÊý
+int gBatVoltageSamples[NUM_VOLTAGE_SAMPLE];
+int gBatSlopeValue = 0;
+int    gBatVoltageValue[2];
+int *pSamples = &gBatVoltageSamples[0];                //²ÉÑùµãÖ¸Õë
+int gFlagLoop = 0;             //Ñ­»·±êÖ¾
+int gNumSamples = 0;
+
+int gBatSlopeLevel = SLOPE_LOW_LEVEL;
+int gBatVoltageLevel = VOLTAGE_MID_LEVEL;
+int gBatLoaderLevel = LODER_MID_LEVEL; 
+
+
 extern int dwc_vbus_status(void);
 
 struct rk2818_battery_data {
@@ -59,8 +135,6 @@ struct rk2818_battery_data {
        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;
@@ -113,19 +187,106 @@ static void rk2818_get_bat_present(struct rk2818_battery_data *bat)
 static void rk2818_get_bat_voltage(struct rk2818_battery_data *bat)
 {
        unsigned long value;
+       int i,*pSamp,*pStart = &gBatVoltageSamples[0];
+       int temp[2] = {0,0};
        value = gAdcValue[CHN_BAT_ADC];
-       gBatVoltage = value * 1000000 / bat->adc_bat_divider;
+       gBatVoltage = (value * 5000)>>10;       // 3.3v to 5v
+       *pSamples = gBatVoltage;
+       if((++pSamples - pStart) > NUM_VOLTAGE_SAMPLE)
+       {
+               pSamples = pStart;
+               gFlagLoop = 1;
+       }
+
+       //compute the average voltage after samples-count is larger than NUM_VOLTAGE_SAMPLE
+       if(gFlagLoop)
+       {
+               pSamp = pSamples;
+               for(i=0; i<(NUM_VOLTAGE_SAMPLE >> 1); i++)
+               {
+                       temp[0] += *pSamp;
+                       if((++pSamp - pStart) > NUM_VOLTAGE_SAMPLE)
+                       pSamp = pStart;
+               }
+               
+               gBatVoltageValue[0] = temp[0] / (NUM_VOLTAGE_SAMPLE >> 1);
+               for(i=0; i<(NUM_VOLTAGE_SAMPLE >> 1); i++)
+               {
+                       temp[1] += *pSamp;
+                       if((++pSamp - pStart) > NUM_VOLTAGE_SAMPLE)
+                       pSamp = pStart;
+               }
+               
+               gBatVoltageValue[1] = temp[1] / (NUM_VOLTAGE_SAMPLE >> 1);
+               //DBG("gBatVoltageValue[0]=%d,gBatVoltageValue[1]=%d\n",gBatVoltageValue[0],gBatVoltageValue[1]);
+
+               gBatSlopeValue = gBatVoltageValue[0] - gBatVoltageValue[1];     
+               
+               if(gBatSlopeValue >= 0) //Óõç״̬
+               {
+
+                       if(gBatVoltageValue[1] >= THRESHOLD_VOLTAGE_HIGH)
+                       gBatVoltageLevel =      VOLTAGE_HIGH_LEVEL;     
+                       else if((gBatVoltageValue[1] >= THRESHOLD_VOLTAGE_MID) && (gBatVoltageValue[1] < THRESHOLD_VOLTAGE_HIGH))
+                       gBatVoltageLevel =      VOLTAGE_MID_LEVEL;
+                       else if((gBatVoltageValue[1] >= THRESHOLD_VOLTAGE_LOW) && (gBatVoltageValue[1] < THRESHOLD_VOLTAGE_MID))
+                       gBatVoltageLevel = VOLTAGE_LOW_LEVEL;
+                       else
+                       gBatVoltageLevel = VOLTAGE_RELEASE_LEVEL;
+
+                       if(gBatSlopeValue >= THRESHOLD_SLOPE_HIGH)
+                       gBatSlopeLevel = SLOPE_HIGH_LEVEL;      
+                       else if((gBatSlopeValue >= THRESHOLD_SLOPE_MID) && (gBatSlopeValue < THRESHOLD_SLOPE_HIGH))
+                       gBatSlopeLevel = SLOPE_MID_LEVEL;       
+                       else if(gBatSlopeValue >= THRESHOLD_SLOPE_LOW)
+                       gBatSlopeLevel = SLOPE_LOW_LEVEL;
+                       
+                       /*µçѹÖÐÇÒбÂʸߡ¢ µçѹ¸ßÇÒбÂʸ߻òÖÐ*/
+                       if(((gBatVoltageLevel == VOLTAGE_MID_LEVEL) && (gBatSlopeLevel == SLOPE_HIGH_LEVEL)) \
+                               || ((gBatVoltageLevel == VOLTAGE_HIGH_LEVEL) && ((gBatSlopeLevel == SLOPE_HIGH_LEVEL) || (gBatSlopeLevel == SLOPE_MID_LEVEL))))
+                       {
+                               gBatLoaderLevel = LODER_HIGH_LEVEL;
+                               DBG("gBatLoaderLevel = LODER_HIGH_LEVEL\n");
+                       }
+                       
+                       /*µçѹÖÐÇÒбÂÊÖлòµÍ¡¢µçѹ¸ßÇÒбÂʵ͡¢ µçѹµÍÇÒбÂʵÍ*/
+                       else if(((gBatVoltageLevel != VOLTAGE_RELEASE_LEVEL) && (gBatSlopeLevel == SLOPE_LOW_LEVEL)) \
+                               || ((gBatVoltageLevel == VOLTAGE_MID_LEVEL) && (gBatSlopeLevel == SLOPE_MID_LEVEL)))
+                       {
+                               gBatLoaderLevel = LODER_MID_LEVEL;
+                               DBG("gBatLoaderLevel = LODER_MID_LEVEL\n");
+                       }
+                       
+                       /*µçѹµÍÇÒбÂʸ߻òÖС¢ µçѹ³¬µÍ*/
+                       else if(((gBatVoltageLevel == VOLTAGE_LOW_LEVEL) && ((gBatSlopeLevel == SLOPE_MID_LEVEL) || (gBatSlopeLevel == SLOPE_MID_LEVEL))) \
+                               || (gBatVoltageLevel == VOLTAGE_RELEASE_LEVEL))
+                       {
+                               gBatLoaderLevel = LOADER_RELEASE_LEVEL; //µç³ØÒѺľ¡
+                               DBG("gBatLoaderLevel = LOADER_RELEASE_LEVEL\n");
+                       }
+
+               }
+               else    //³äµç״̬
+               {
+                       //to do
+               }
+               
+       }
+       
 }
 
 static void rk2818_get_bat_capacity(struct rk2818_battery_data *bat)
 {
-       gBatCapacity = (gBatVoltage * 100) / bat->bat_max;
+       if(gFlagLoop)
+       gBatCapacity = ((gBatVoltageValue[1] - bat->bat_min) * 100) / (bat->bat_max - bat->bat_min);
+       else
+       gBatCapacity = ((gBatVoltage - bat->bat_min) * 100) / (bat->bat_max - bat->bat_min);
 }
 
 
 static void rk2818_batscan_timer(unsigned long data)
 {
-       gBatteryData->timer.expires  = jiffies + msecs_to_jiffies(20);
+       gBatteryData->timer.expires  = jiffies + msecs_to_jiffies(TIMER_MS_COUNTS);
        add_timer(&gBatteryData->timer);        
        rk2818_get_bat_status(gBatteryData);
        rk2818_get_bat_health(gBatteryData);
@@ -133,6 +294,15 @@ static void rk2818_batscan_timer(unsigned long data)
        rk2818_get_bat_voltage(gBatteryData);
        rk2818_get_bat_capacity(gBatteryData);
 
+       if(++gNumSamples > TIME_UPDATE_STATUS/TIMER_MS_COUNTS)
+       {
+               gNumSamples = 0;
+               if(gBatSlopeValue != 0) //if voltage has changed
+               {
+                       power_supply_changed(&gBatteryData->battery);
+                       DBG("voltage has changed\n");
+               }
+       }
 }
 
 
@@ -141,7 +311,6 @@ static int rk2818_usb_get_property(struct power_supply *psy,
                                    union power_supply_propval *val)
 {
        charger_type_t charger;
-       //todo 
        charger =  CHARGER_USB;
 
        switch (psp) {
@@ -168,7 +337,6 @@ static int rk2818_ac_get_property(struct power_supply *psy,
 //             struct rk2818_battery_data, ac);
        int ret = 0;
        charger_type_t charger;
-       //todo 
        charger =  CHARGER_USB;
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
@@ -217,7 +385,7 @@ static int rk2818_battery_get_property(struct power_supply *psy,
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
                val->intval = gBatCapacity;
-               DBG("gBatCapacity=0x%x\n",val->intval);
+               DBG("gBatCapacity=%d%\n",val->intval);
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
                val->intval = data->bat_max;
@@ -290,16 +458,17 @@ static int rk2818_battery_probe(struct platform_device *pdev)
        }
        spin_lock_init(&data->lock);
 
+       memset(gBatVoltageSamples, 0, sizeof(gBatVoltageSamples));
+       
        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->bat_max = gBatMaxVol;
+       data->bat_min = gBatZeroVol;
+       DBG("bat_min = %d\n",data->bat_min);
 
        data->usb.properties = rk2818_usb_props;
        data->usb.num_properties = ARRAY_SIZE(rk2818_ac_props);
@@ -351,7 +520,6 @@ static int rk2818_battery_probe(struct platform_device *pdev)
        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;
 
@@ -404,7 +572,7 @@ static void __exit rk2818_battery_exit(void)
 module_init(rk2818_battery_init);
 module_exit(rk2818_battery_exit);
 
-MODULE_AUTHOR("Mike Lockwood lockwood@android.com");
+MODULE_DESCRIPTION("Battery detect driver for the rk2818");
+MODULE_AUTHOR("luowei lw@rock-chips.com");
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Battery driver for the Goldfish emulator");