From dc799500f170a6e60c312504a9b1401c2bc9ad71 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E7=BD=97=E4=BC=9F?= Date: Fri, 21 May 2010 07:20:28 +0000 Subject: [PATCH] luowei modify battery driver on 100521 --- arch/arm/mach-rk2818/adc.c | 56 ++++++- drivers/input/keyboard/rk2818_adckey.c | 37 +---- drivers/power/Kconfig | 2 +- drivers/power/rk2818_battery.c | 210 ++++++++++++++++++++++--- 4 files changed, 247 insertions(+), 58 deletions(-) diff --git a/arch/arm/mach-rk2818/adc.c b/arch/arm/mach-rk2818/adc.c index f3e762cfc01a..46e34fe9c4a4 100644 --- a/arch/arm/mach-rk2818/adc.c +++ b/arch/arm/mach-rk2818/adc.c @@ -29,12 +29,17 @@ * 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); diff --git a/drivers/input/keyboard/rk2818_adckey.c b/drivers/input/keyboard/rk2818_adckey.c index e8e2a82c392d..4b33162010ad 100644 --- a/drivers/input/keyboard/rk2818_adckey.c +++ b/drivers/input/keyboard/rk2818_adckey.c @@ -26,7 +26,7 @@ #include #include -#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); diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index c91ed7f7e27f..f909f2f8f9fc 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -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 diff --git a/drivers/power/rk2818_battery.c b/drivers/power/rk2818_battery.c index 31921f3342cb..97b4bdb5c23f 100644 --- a/drivers/power/rk2818_battery.c +++ b/drivers/power/rk2818_battery.c @@ -1,9 +1,6 @@ /* drivers/power/rk2818_battery.c * - * Power supply driver for the rk2818 emulator - * - * Copyright (C) 2008 Google, Inc. - * Author: Mike Lockwood + * 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 @@ -26,13 +23,13 @@ #include #include -#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"); -- 2.34.1