* 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;
};
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);
}
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;
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;
{
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);
#include <mach/gpio.h>
#include <mach/adc.h>
-#if 1
+#if 0
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#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;
#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;
gADSampleTimes = 0;
- rk28_read_adc(pRk28AdcKey);
+ //rk28_read_adc(pRk28AdcKey);
adcvalue = gAdcValue[ADKEYCH];
if((adcvalue > ADEmpty) || (adcvalue < ADInvalid))
{
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 */
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);
/* 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
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 {
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;
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);
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");
+ }
+ }
}
union power_supply_propval *val)
{
charger_type_t charger;
- //todo
charger = CHARGER_USB;
switch (psp) {
// struct rk2818_battery_data, ac);
int ret = 0;
charger_type_t charger;
- //todo
charger = CHARGER_USB;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
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;
}
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);
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;
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");