Roverbook steel. Проект Debian вместо Android.

Назад Главная


Roverbook steel. Проект Debian вместо Android.

roverbooksteel_battery drivers\power\rk28_battery.c
/* arch/arm/mach-rockchip/rk28_battery.c
 *
 * Copyright (C) 2009 Rockchip Corporation.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/power_supply.h>
#include <linux/platform_device.h>
#include <linux/debugfs.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <asm/types.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/mach/time.h>
#include <asm/arch/gpio.h>
#include <asm/arch/iomux.h>
#include <asm/uaccess.h>

//#include <linux/wakelock.h>
//#include <asm/gpio.h>

/* Debug */
#define BAT_DBG 0
#if BAT_DBG
#define DBG(x...)	printk(KERN_INFO x)
ktime_t ktime_now,ktime_pre,ktime_start;

#else
#define DBG(x...)
#endif

/*use adc sample battery capacity - Использование АЦП образца емкость батареи*/
#define AC_INSERT_VALUE     220
#define BATT_1V2_MODIFY	100
//#define BATT_1V2_VALUE		1338*BATT_1V2_MODIFY/100
#define BATT_1V2_VALUE		1420*BATT_1V2_MODIFY/100
#define BATT_3V05_VALUE		3120//3050
#define BATT_3V00_VALUE		3090//3050

#define BATT_FULL_VALUE	       4200
#define BATT_STEP_FULL_VALUE  4000
#define BATT_EMPTY_VALUE	3500
#define PERCENT				100
#define BATT_LEVEL_FULL		100
#define BATT_LEVEL_EMPTY	0
#define BATT_PRESENT_TRUE	 1
#define BATT_PRESENT_FALSE  0
#define BATT_NOMAL_VOL_VALUE	4000
#define BATT_VOLTAGE_MAX	4200
#define BATT_VOLTAGE_MIN	3400//3300//3500
#define AD_SAMPLE_TIMES	6
#define AC_OFFSET     500
#define PER_MINUTE	600//(60*1000*1000*1000/(TS_POLL_DELAY))
#define CHARGE_FULL_GATE 4140//4100

#define AD_NO_BATT_VALE       200
#define AD_NO_DC_VALE         200

#define TS_POLL_DELAY		(100*1000*1000)
#define SEC_NUM				2  ///8
#define PER_SEC_NUM		20  ///10

static int bat_vol_cnt = 0;  
static int bat_vol_up_cnt = 0; 
static int bat_vol_no_power_cnt = 0;  
static int bat_status =  POWER_SUPPLY_STATUS_UNKNOWN;
static int bat_health = POWER_SUPPLY_HEALTH_GOOD;
static int bat_capacity = BATT_LEVEL_EMPTY;
static int bat_present = BATT_PRESENT_TRUE;
static int bat_voltage =  BATT_NOMAL_VOL_VALUE;
static int ad_sample_current_time = 0;
unsigned int sample_times = 0;			/*count times (report batter status)*/
static int charger_change_cnt = 0;
//static int g_charge_full_cnt = 0;
/* 
 * Примечание [XJH]:
 *  Интерфейс отображает процент емкости аккумулятора,
 *  Вместо того, чтобы в процентах от текущего напряжения батареи в диапазоне напряжений от литиевой батареи рабочих
 * Емкость аккумулятора и напряжение батареи не прямо пропорциональна
 * 
 *  Литий характеристики разряда батареи:
 * После полной зарядки, разрядки литиевые батареи напряжение падает ранних драматических ( Но не значит, что емкость батареи также резкое снижение)
 * Затем введите стабильный период, снизился очень значительно в стабильную фазу напряжения
 *  Когда батарея почти разряжена, есть резкое падение напряжения, это может повредить аккумулятор, если он продолжает выполнять.
 * *
 *  Литиевая батарея зарядки характеристиками:
 * В начале зарядки постоянным током, напряжение растет быстрее.
 *  При достижении предела напряжения, постоянного напряжения зарядки ручеек.
* /

#if 1
//Массив из разряда батареи
static int batt_step_table[56]={
    /*
    3400,3420,3430,3440,3450,3465,3480,3495,3510,3520,
	3530,3545,3560,3575,3590,3600,3610,3620,3630,3640,
	3650,3660,3670,3680,3690,3700,3710,3720,3735,3750,
	3765,3780,3790,3805,3820,3835,3850,3865,3880,3895,
	3910,3925,3940,3955,3970,3985,4000,4015,4030,4045,
	4060,4075,4100,4130,4150,4200	
	*/
	//Увеличиваем напряжение выключения
	3490,3510,3520,3530,3545,3560,3575,3590,3600,3610,
	3620,3630,3640,3650,3660,3670,3680,3690,3700,3710,
	3720,3735,3750,3765,3780,3790,3805,3820,3835,3850,
	3865,3880,3895,3910,3925,3940,3955,3970,3985,4000,
	4015,4030,4045,4060,4075,4100,4130,4150,4200,4200,	
	4200,4200,4200,4200,4200,4200
};

//Зарядки аккумулятора массива
static int batt_no_current_step_table[56]={
	/*
	3410,3440,3665,3680,3695,3705,3720,3735,3750,3765,
	3780,3795,3810,3820,3830,3840,3850,3860,3870,3880,
	3890,3900,3910,3920,3925,3930,3940,3950,3960,3970,
	3980,3990,4000,4010,4020,4030,4040,4050,4060,4070,
	4080,4090,4100,4110,4120,4125,4130,4135,4140,4145,
	4150,4155,4165,4180,4190,4200
	*/
	
	3490,3510,3765,3780,3795,3810,3820,3830,3840,3850,
	3860,3870,3880,3890,3900,3910,3920,3925,3930,3940,
	3950,3960,3970,3980,3990,4000,4010,4020,4030,4040,
	4050,4060,4070,4080,4090,4100,4105,4110,4115,4120,
	4125,4130,4145,4150,4155,4165,4180,4190,4200,4200,
	4200,4200,4200,4200,4200,4200
};

static int batt_disp_table[56]={
	/*
	 0, 1, 3, 5, 7, 9, 11,13,15,17,
	19,21,23,25,27,29,31,33,35,37,
	39,41,43,45,47,49,51,53,55,57,
	59,61,63,65,67,69,71,73,75,77,
	79,81,83,85,87,89,90,91,93,94,
	95,97,100,100,100,100	
	*/
	
	0, 1, 3, 5, 7, 9, 11,13,15,17,
	19,21,23,25,27,29,31,33,35,37,
	39,41,43,45,47,50,53,56,59,62,
	65,68,71,74,77,80,83,86,89,92,
	95,99,99,99,99,99,99,99,100,100,
	100,100,100,100,100,100	
};

static int batt_disp_table_no_current[56]={
	/*
	 0, 1, 3, 5, 7, 9, 11,13,15,17,
	19,21,23,25,27,29,31,33,35,37,
	39,41,43,45,47,49,51,53,55,57,
	59,61,63,65,67,69,71,73,75,77,
	79,81,83,85,87,90,92,95,97,98,
	99,99,99,99,99,100	
	*/
	 0, 1, 3, 5, 7, 9, 11,13,15,17,
	19,21,23,25,27,29,31,33,35,37,
	39,41,43,45,47,50,53,56,59,62,
	65,68,71,74,77,80,83,86,89,92,
	95,99,99,99,99,99,99,99,100,100,
	100,100,100,100,100,100
};


#else
static int batt_step_table[56]={
/*
    3400,3420,3470,3500,3540,3545,3555,3560,3580,3600,3615,3630,3640,3650,3660,3670,3680,3690,
    3700,3710,3720,3730,3740,3750,3760,3770,3780,3790,3800,3810,3815,3830,3845,3860,3875,3890,
    3900,3910,3920,3930,3940,3950,3960,3970,3985,4000,4005,4010,4015,4020,40300,40400,4050,
    4060,4070,4200
    */
     3400,3420,3470,3500,3540,3545,3555,3560,3580,3600,3615,3630,3640,3650,3660,3670,3680,3690,
    3700,3710,3720,3730,3740,3750,3760,3770,3780,3790,3800,3810,3815,3830,3845,3860,3875,3890,
    3900,3910,3920,3930,3940,3950,3960,3970,3985,4000,4005,4010,4015,4020,4030,4040,4050,
    4060,4070,4200
}; //Соответствующий массив} / / разряда

static int ac_batt_step_table[56]={
3880,3886,3892,3898,3904,3910,3916,3922,3928,3934,
3940,3946,3952,3958,3964,3970,3976,3982,3988,3994,
4000,4006,4012,4018,4024,4030,4036,4042,4048,4054,
4060,4066,4072,4078,4084,4090,4096,4102,4108,4114,
4120,4126,4132,4138,4144,4150,4156,4162,4168,4174,
4180,4186,4192,4198,4204,4210};

static int batt_no_current_step_table[56]={
	3410,3440,3600,3650,3680,3690,3700,3715,3725,3740,3745,3755,3765,3770,3778,3784,3790,3800,3810,
	3820,3835,3845,3855,3870,3880,3890,3898,3905,3913,3920,3930,3940,3950,3960,3970,3980,3988,3995,
	4002,4010,4018,4025,3035,4042,4051,4060,4065,4070,4075,4080,4085,4090,4095,4100,4105,4200
/*	3980,3986,3992,3998,4004,4010,4016,4022,4028,4034,
4040,4046,4052,4058,4064,4070,4076,4082,4088,4094,
4100,4106,4112,4118,4124,4130,4136,4142,4148,4154,
4160,4166,4172,4178,4184,4190,4196,4202,4208,4214,
4220,4226,4232,4238,4244,4250,4256,4262,4268,4274,
4280,4286,4292,4298,4304,4310*/
};//Charge соответствующий массив
static int batt_disp_table[56]={
    0,3,5,8,10,12,14,15,18,20,23,26,28,30,33,37,40,43,47,
    50,52,54,57,60,62,64,66,68,69,70,72,74,76,78,79,
    80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
    96,97,98,99,100	
};
#endif
static u16 g_adcref = 0;
static u16 g_adcbat = 0;	//adccharge;
static int ac_power_off = 0;   // 0 is not power down,1 is power down enter sleep level2
static int full_flag = 0;
static int full_time_cnt = 0;
static int adj_cnt = 0;
extern	u16 get_rock_adc0(void);	/*battery capacity*/
extern	u16 get_rock_adc1(void);	/*battery charge status*/
extern    u16  get_rock_adc2(void);       /*ac charge status */
extern	u16 get_rock_adc3(void);	/*battery vref*/
extern       int get_msc_connect_flag( void );

struct rk28_battery_data {
	spinlock_t lock;

	struct power_supply 	battery;
	struct power_supply	usb;
	struct power_supply	ac;
	struct hrtimer  timer;	
};


#define APP_BATT_PDEV_NAME		"rockchip_battery"
#define DRV_VER 			"1.0"
typedef enum {
	CHARGER_BATTERY = 0,
	CHARGER_USB,
	CHARGER_AC
} charger_type_t;


static int rockchip_usb_get_property(struct power_supply *psy, 
				    enum power_supply_property psp,
				    union power_supply_propval *val);

static int rockchip_battery_get_property(struct power_supply *psy, 
				    enum power_supply_property psp,
				    union power_supply_propval *val);
static int rockchip_ac_get_property(struct power_supply *psy, 
					enum power_supply_property psp,
					union power_supply_propval *val);
static int get_ac_charge_status(void);


static enum power_supply_property rockchip_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 rockchip_power_properties[] = {
	POWER_SUPPLY_PROP_ONLINE,
};

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


static struct power_supply rockchip_power_supplies[] = {
	{
		.name = "battery",
		.type = POWER_SUPPLY_TYPE_BATTERY,
		.properties = rockchip_battery_properties,
		.num_properties = ARRAY_SIZE(rockchip_battery_properties),
		.get_property = rockchip_battery_get_property,
	},
	{
		.name = "usb",
		.type = POWER_SUPPLY_TYPE_USB,
		.supplied_to = supply_list,
		.num_supplicants = ARRAY_SIZE(supply_list),
		.properties = rockchip_power_properties,
		.num_properties = ARRAY_SIZE(rockchip_power_properties),
		.get_property = rockchip_usb_get_property,
	},
	{
		.name = "ac",
		.type = POWER_SUPPLY_TYPE_AC,
		.supplied_to = supply_list,
		.num_supplicants = ARRAY_SIZE(supply_list),
		.properties = rockchip_power_properties,
		.num_properties = ARRAY_SIZE(rockchip_power_properties),
		.get_property = rockchip_ac_get_property,
	},
};

static void record_battery_log(char *buf)
{
	struct file *fp;
	char buf1[500]= "battery test";
	mm_segment_t fs;
//	struct timespec ts;
//	struct rtc_time tm;


	/*
	getnstimeofday(&ts);
	rtc_time_to_tm(ts.tv_sec, &tm);
	//printk("%s--->%d\n",__FUNCTION__,__LINE__);
	if((strncmp(buf,"start",5)==0)||(strncmp(buf,"stop",4) == 0) ||strncmp(buf,"error", 5)==0)
		snprintf(buf1,sizeof(buf1)," browser %s -->(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",buf ,
				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
	else
		snprintf(buf1,sizeof(buf1),"Set arm freq %s -->(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",buf ,
				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
	*/
	fp = filp_open("/flash/battery.txt",O_RDWR|O_APPEND |O_CREAT  ,0644);
	if(IS_ERR(fp)){
		printk("create file error!\n");
		return;
	}
	fs = get_fs();
	set_fs(KERNEL_DS);
	//vfs_read(fp,buf1,sizeof(buf1),&pos);
	vfs_write(fp,buf,strlen(buf),&fp->f_pos);
	set_fs(fs);
	filp_close(fp,NULL);
	//printk("%s--->%d\n",__FUNCTION__,__LINE__);
	return;
}


static int rockchip_usb_get_property(struct power_supply *psy, 
				    enum power_supply_property psp,
				    union power_supply_propval *val)
{
	charger_type_t charger;
	
	//todo 
	charger =  CHARGER_USB;
//	DBG("--------%s-->%s-->%d\n",__FILE__,__FUNCTION__,__LINE__);
	switch (psp) {
	case POWER_SUPPLY_PROP_ONLINE:
		#if 1 
		if (psy->type == POWER_SUPPLY_TYPE_AC)
			val->intval = (charger ==  CHARGER_AC ? 1 : 0);
		else if (psy->type == POWER_SUPPLY_TYPE_USB)
			val->intval = get_msc_connect_flag();//GPIOGetPinLevel(GPIOPortB_Pin1) ;
		else
	         val->intval = 0;
		 #else 
		  val->intval = 0;
		 #endif
		break;
	default:
		return -EINVAL;
	}
	
	return 0;

}
static int rockchip_ac_get_property(struct power_supply *psy, 
					enum power_supply_property psp,
					union power_supply_propval *val)
{
	charger_type_t charger;
	
	//todo 
	charger =  CHARGER_USB;
	switch (psp) {
	case POWER_SUPPLY_PROP_ONLINE: 
		val->intval = get_ac_charge_status();
		break;
	default:
		return -EINVAL;
	}
	
	return 0;

}

#if 0
 static void rk28_power_off(void)
{
	GPIOSetPinLevel(GPIOPortF_Pin1,GPIO_LOW);	/*power down*/
}
#else
extern void rk28_power_off(void);

 #endif

 static int get_ac_charge_status(void)
 {
 	if(get_rock_adc2() >= AC_INSERT_VALUE)
		  return 1;
	else 
	{
		full_flag = 0;
	 	return 0;
	}
 }
static int get_battery_charge_status( void )
{

		return 0;//(!get_msc_connect_flag() );
	/*
	      if(get_rock_adc2() >= AC_INSERT_VALUE)
		  return 1;
	      else 
	 	  return 0;
         */
}


extern void rk28_send_wakeup_key( void );
static int rockchip_get_battery_status(void)
{
	//u16 adcref,adcbat;	//adccharge;
	int  current_vol,i;
#if 1 //add by cst	
	if(ac_power_off == 1) 
	{
		rk28_send_wakeup_key();
		//GPIOSetPinLevel(GPIOPortF_Pin1,GPIO_LOW);       /*power down*/
		rk28_power_off();
	
	}
#endif

	if((get_battery_charge_status()||get_ac_charge_status()) 
		/*&& (bat_capacity !=  BATT_LEVEL_FULL) */)    /*the battery charge*/

		bat_status =POWER_SUPPLY_STATUS_CHARGING ;
	else 
		bat_status =POWER_SUPPLY_STATUS_NOT_CHARGING ;	/*no charge*/

	if(full_flag)
		bat_status =POWER_SUPPLY_STATUS_NOT_CHARGING ;//избежать зарядки мигает символ	

	ad_sample_current_time++;
    g_adcbat = (g_adcbat + get_rock_adc0())/2;
   	g_adcref = (g_adcref + get_rock_adc3())/2;
	if(ad_sample_current_time < AD_SAMPLE_TIMES) return 1;
#if defined (M710_LED_CONTROL)
	if (bat_status == POWER_SUPPLY_STATUS_CHARGING)
	{
		if(GPIOGetPinLevel(KEY_LED_IOPIN) == (KEY_GREEN_LED_EFFECTIVE_LEVEL&(0x01)))
			GPIOSetPinLevel(KEY_LED_IOPIN, ~KEY_LED_EFFECTIVE_LEVEL);
	}
#endif
	ad_sample_current_time = 0;		
	if(g_adcbat < AD_NO_BATT_VALE)	/*haven't battery*/ 
	{
		bat_present = BATT_PRESENT_FALSE;	
		goto nobattery;
	}
	bat_present = BATT_PRESENT_TRUE;	/*have battery*/
	/*get charge status*/

#if 0
//	 if(get_battery_charge_status()||get_ac_charge_status())	/*the battery charge*/
	if((get_battery_charge_status()||get_ac_charge_status()) 
		/*&& (bat_capacity !=  BATT_LEVEL_FULL) */)    /*the battery charge*/

		bat_status =POWER_SUPPLY_STATUS_CHARGING ;
	else 
		bat_status =POWER_SUPPLY_STATUS_NOT_CHARGING ;	/*no charge*/

	if(full_flag)
		bat_status =POWER_SUPPLY_STATUS_NOT_CHARGING ;//избежать зарядки мигает символ
#endif

	/*get present voltage*/
//	current_vol = ((u32)g_adcbat * 2UL * BATT_1V2_VALUE)/((u32)g_adcref);		/*current voltage*/
	if(bat_voltage > 3700)
		current_vol = (g_adcbat * 2UL * BATT_3V05_VALUE)/1024;		/*current voltage*/
	else if(bat_voltage > 3500)
		current_vol = (g_adcbat * 2UL * (BATT_3V05_VALUE - 15))/1024;		/*current voltage*/
	else //3400~3500
		current_vol = (g_adcbat * 2UL * (BATT_3V05_VALUE - 30))/1024;		/*current voltage*/
	
	current_vol -= 50;		/*Некоторые доски выборки будет высоким, меньше о 50mv */

/*	if(bat_status == POWER_SUPPLY_STATUS_NOT_CHARGING) 
		{
			current_vol = current_vol - AC_OFFSET;
		}*/
	bat_voltage = current_vol;
	
	/*get battery health status*/
	if(batt_step_table[0]>=current_vol)
	{
	#ifdef M710_LED_CONTROL
		if(GPIOGetPinLevel(KEY_GREEN_LED_IOPIN) == (KEY_GREEN_LED_EFFECTIVE_LEVEL&(0x01)))
			GPIOSetPinLevel(KEY_GREEN_LED_IOPIN, ~KEY_GREEN_LED_EFFECTIVE_LEVEL);
	#endif
	//	if(!GPIOGetPinLevel(CHG_OK_IOPIN))
		if((get_battery_charge_status()||get_ac_charge_status()) )
		{
			bat_health = POWER_SUPPLY_HEALTH_GOOD;	/*current voltage too poor*/
			bat_capacity =  1;
			bat_vol_no_power_cnt = 0;	
			
		}
		else
		{
			//printk("POWER_SUPPLY_HEALTH_GOOD bat_vol_no_power_cnt%d\n",bat_vol_no_power_cnt);
			bat_vol_no_power_cnt++;
			if(bat_vol_no_power_cnt< 80){
			    bat_capacity = 1;
			    return 1;
			}
			bat_vol_no_power_cnt = 0;
			bat_health = POWER_SUPPLY_HEALTH_GOOD;	/*current voltage too poor*/
			bat_capacity =	0;   ///9;
			printk("battery is too poor>>power down!!!");
			//rk28_power_off();		/* диск не является автоматически жесткого закрытия, он будет разрушать система, управляемая система выключения */
		}
		return 1;
	}
//	else if(batt_step_table[55]<=current_vol)
	else if(CHARGE_FULL_GATE <=current_vol)
	{
			if(GPIOGetPinLevel(CHG_OK_IOPIN)) /* current voltage full */							/*xxm*/
			{
			
				bat_health = POWER_SUPPLY_HEALTH_GOOD;
				bat_vol_no_power_cnt = 0;
				bat_capacity =  BATT_LEVEL_FULL;
				//printk("battery charge ok\n");
				full_flag = 1;
				full_time_cnt = 0;
			}else
				{
					bat_health = POWER_SUPPLY_HEALTH_GOOD;
					bat_vol_no_power_cnt = 0;
					bat_capacity =  99;
				}
		return 1;
	}
#ifdef	M710_LED_CONTROL
	if(GPIOGetPinLevel(KEY_GREEN_LED_IOPIN) == (KEY_GREEN_LED_EFFECTIVE_LEVEL&(0x01)))
		GPIOSetPinLevel(KEY_GREEN_LED_IOPIN, ~KEY_GREEN_LED_EFFECTIVE_LEVEL);
#endif
	bat_vol_no_power_cnt = 0;
#if 1
	if(get_ac_charge_status()){
		for(i=0; i<55; i++){		
		    if((batt_no_current_step_table[i]<=current_vol)&&(batt_no_current_step_table[i+1]>current_vol))break;		
	    }
		bat_capacity = batt_disp_table_no_current[i];
	}else{
	    for(i=0; i<55; i++){		
		    if((batt_step_table[i]<=current_vol)&&(batt_step_table[i+1]>current_vol))break;		
	    }
		bat_capacity = batt_disp_table[i];
	}
#endif
//	bat_capacity = batt_disp_table[i];
	bat_health = POWER_SUPPLY_HEALTH_GOOD;
	return 1;
nobattery:
	if( (!get_msc_connect_flag()) || get_ac_charge_status() )	/*the battery charge*/
		bat_status =POWER_SUPPLY_STATUS_CHARGING ;
	else 
		bat_status =POWER_SUPPLY_STATUS_NOT_CHARGING ;	/*no charge*/
	bat_health = POWER_SUPPLY_HEALTH_GOOD;
	/*haven't battery  but have usb supply*/
	//if((GPIOGetPinLevel(GPIOPortB_Pin1))&&(bat_capacity  < 15))	
	//	bat_capacity = 1;
	return 0;

}

static int rockchip_battery_get_property(struct power_supply *psy, 
				    enum power_supply_property psp,
				    union power_supply_propval *val)
{
	//DBG("--------%s-->%s-->property_psp%d\n",__FILE__,__FUNCTION__,psp);
	switch (psp) {
	case POWER_SUPPLY_PROP_ONLINE:
		val->intval = bat_present;
		break;
	case POWER_SUPPLY_PROP_STATUS:
		val->intval = bat_status;
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		val->intval = bat_health;
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		/* get power supply */
		val->intval = bat_present;
		break;
	case POWER_SUPPLY_PROP_TECHNOLOGY:
		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
		break;
	case POWER_SUPPLY_PROP_CAPACITY:
		/* Todo return battery level */	
		val->intval = bat_capacity;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
		val ->intval = bat_voltage;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
		val->intval = BATT_VOLTAGE_MAX;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
		val->intval = BATT_VOLTAGE_MIN;
		break;
	default:		
		return -EINVAL;
	}
	
	return 0;
}


 static enum hrtimer_restart rk28_battery_dostimer(struct hrtimer *handle)
{

	struct rk28_battery_data *data = container_of(handle, struct rk28_battery_data, timer);
	int old_bat_status = bat_status;
	int old_bat_capacity = bat_capacity;
	unsigned long flags;
	#if BAT_DBG
	char bat_info[500];
	
	#endif
	spin_lock_irqsave(&data->lock, flags);
#ifdef	M710_LED_CONTROL
	if(!get_ac_charge_status())
	{
		//GPIOSetPinLevel(KEY_LED_IOPIN,GPIO_LOW);
		if(GPIOGetPinLevel(KEY_GREEN_LED_IOPIN) == (KEY_GREEN_LED_EFFECTIVE_LEVEL&(0x01)))
			GPIOSetPinLevel(KEY_GREEN_LED_IOPIN, ~KEY_GREEN_LED_EFFECTIVE_LEVEL);
	}
#endif
	rockchip_get_battery_status();		/*have battery*/
	full_time_cnt ++;
	if(full_time_cnt >= 2 * PER_MINUTE) 
	{
		full_flag = 0;
		full_time_cnt = 0;
	}

	
	/*if have usb supply power*/		
	//printk("get_adc2() return %d \n",get_rock_adc2());
	if((bat_present == BATT_PRESENT_TRUE)&&(old_bat_status != bat_status))
	{
		
		charger_change_cnt = 80;
		printk("charge status changed::charger_change_cnt %d old_bat_status %d bat_status %d\n",
			charger_change_cnt,old_bat_capacity,bat_capacity);
		bat_capacity = old_bat_capacity;
		
		/*set charge status*/
//		if(GPIOGetPinLevel(GPIOPortB_Pin1) && !get_msc_connect_flag())	/*the battery charge*/
//	 		GPIOSetPinLevel(GPIOPortB_Pin0,GPIO_HIGH);
//		else 
//			GPIOSetPinLevel(GPIOPortB_Pin0,GPIO_LOW);	/*no charge*/
		//if((GPIOGetPinLevel(GPIOPortB_Pin1))&&(bat_capacity<14)){
		//	bat_capacity = 1;
		//}	
		DBG("\n----usbchange----->%s:  old_bat_status==%i  ->bat_status==%i\n",data->battery.name,old_bat_status,bat_status);
		DBG("---->battery adcbat = %d adcref=%d\n",g_adcbat,g_adcref);
		DBG("---->battery present = %d\n",bat_present);
		DBG("---->battery status  = %d\n",bat_status);
		DBG("---->pb0 status = %d pb1 status = %d  usbchargestatus== %d\n",
		GPIOGetPinLevel(GPIOPortB_Pin0),GPIOGetPinLevel(GPIOPortB_Pin1),!get_msc_connect_flag());
		DBG("---->battery current voltage = %d\n",bat_voltage);
		DBG("---->battery capacity = %d\n",bat_capacity);
		power_supply_changed(&data->battery);
		goto next;
	}

	
	if(charger_change_cnt) { // избежать замены видеоадаптера власти плавающие
		//printk("charge status changed2::charger_change_cnt %d old_bat_status %d bat_status %d\n",
		//	charger_change_cnt,old_bat_capacity,bat_capacity);
		charger_change_cnt--;
		bat_capacity = old_bat_capacity;
		goto update;
	}
	
	//Чтобы избежать избиения любом случае, такой установлен на удерживайте клавишу выборки батареи высокого напряжения будет 0.2v, то это вызовет много плавающих
	if(((old_bat_capacity-bat_capacity)>10) || ((bat_capacity-old_bat_capacity)>10))
	{
		adj_cnt++;
		if(adj_cnt< 80)
			bat_capacity = old_bat_capacity;
		else {
			adj_cnt = 0;
			old_bat_capacity = bat_capacity;
		}
		goto update;	
	}

		
	/*fine set battery capacity*/
//	if((bat_status == POWER_SUPPLY_STATUS_CHARGING)&&(bat_capacity < old_bat_capacity)){	
	if((get_ac_charge_status())&&(bat_capacity < old_bat_capacity)){	

		if((old_bat_capacity-bat_capacity)<10){
		    bat_capacity = old_bat_capacity;
		    bat_vol_up_cnt = 0;
		}else{
		    bat_vol_up_cnt++;
			if(bat_vol_up_cnt > 80 /*20*/)
			    bat_vol_up_cnt = 0;
			else	
			    bat_capacity = old_bat_capacity;
	    }
	}	
//	if((bat_status != POWER_SUPPLY_STATUS_CHARGING)&&(bat_capacity > old_bat_capacity)){		
		if((!get_ac_charge_status())&&(bat_capacity > old_bat_capacity)){		
		if((bat_capacity-old_bat_capacity)<10){
			bat_capacity = old_bat_capacity;
			bat_vol_cnt = 0;
		}else{
			bat_vol_cnt++;
			if(bat_vol_cnt > 80)
			    bat_vol_cnt = 0;
			else	
			    bat_capacity = old_bat_capacity;
		}	
	}
	#if 0
	bat_status =  POWER_SUPPLY_STATUS_NOT_CHARGING;
	bat_health = POWER_SUPPLY_HEALTH_GOOD;
	bat_capacity = 20;
	bat_present = BATT_PRESENT_TRUE;
	#endif
update:	
	sample_times ++;						/*count times (report batter status)*/
	if((bat_present == BATT_PRESENT_TRUE)&&(sample_times > SEC_NUM * PER_SEC_NUM) )
	{
		sample_times = 0;
	//	if((GPIOGetPinLevel(GPIOPortB_Pin1))&&(bat_capacity == 0)){
	//		bat_capacity = 1;
	//	}
		
		#if BAT_DBG
	//	spin_unlock_irqrestore(&data->lock, flags);
		ktime_now = ktime_get();
		DBG("\ntime at %Lu nanosec(interal: %Lu)\n" ,ktime_to_ns( ktime_now),ktime_to_ns( ktime_sub( ktime_now,ktime_pre )) );
		

	//	if((!ktime_start.tv.sec) && (!ktime_start.tv.nsec))
	//		ktime_start = ktime_now;
	//		printk("record battery info\n");
	//		snprintf(bat_info,sizeof(bat_info),"time at %Lu nanosec(interal: %Lu)\n" ,
	//				ktime_to_ns( ktime_now),ktime_to_ns( ktime_sub( ktime_now,ktime_pre )) );
	//		record_battery_log(bat_info);
	//	spin_lock_irqsave(&data->lock, flags);
		
		ktime_pre = ktime_now;
		#endif
		DBG("****>battery adcbat = %d adcref=%d\n",g_adcbat,g_adcref);
		DBG("---->battery present = %d\n",bat_present);
		DBG("---->battery status  = %d\n",bat_status);
		DBG("---->pb0 status = %d pb1 status = %d  usbchargestatus== %d\n",
		GPIOGetPinLevel(GPIOPortB_Pin0),GPIOGetPinLevel(GPIOPortB_Pin1),!get_msc_connect_flag());
		DBG("---->battery current voltage = %d\n",bat_voltage);
		DBG("---->battery capacity = %d\n",bat_capacity);
#ifdef	M710_LED_CONTROL		
		if(get_ac_charge_status()&&(bat_capacity!=BATT_LEVEL_FULL))
			GPIOSetPinLevel(KEY_LED_IOPIN, KEY_LED_EFFECTIVE_LEVEL);
		else if(get_ac_charge_status()&&(bat_capacity==BATT_LEVEL_FULL))
			GPIOSetPinLevel(KEY_LED_IOPIN, ~KEY_LED_EFFECTIVE_LEVEL);
		if(!get_ac_charge_status())
			GPIOSetPinLevel(KEY_LED_IOPIN, KEY_LED_EFFECTIVE_LEVEL);
#endif
		power_supply_changed(&data->battery);
	}
next:
	spin_unlock_irqrestore(&data->lock, flags);
	handle->expires = ktime_add(handle->expires, ktime_set(0,TS_POLL_DELAY));
	return HRTIMER_RESTART;

 }
static int rockchip_battery_probe(struct platform_device *pdev)
{
	int  rc,i;
	struct rk28_battery_data  *data;
	
	DBG("RockChip battery driver %s\n",DRV_VER);
	/* init power supplier framework */
	#if 0 
	for (i = 0; i < ARRAY_SIZE(rockchip_power_supplies); i++) {
		rc = power_supply_register(&pdev->dev, &rockchip_power_supplies[i]);
		if (rc)
			printk(KERN_ERR "Failed to register power supply (%d)\n", rc);	
	}
	#endif 
	data=kzalloc(sizeof(*data), GFP_KERNEL);
	spin_lock_init(&data->lock);
	hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	data->timer.function = rk28_battery_dostimer;
	data ->battery = rockchip_power_supplies[0];
	data ->usb	  = rockchip_power_supplies[1];
	data ->ac        = rockchip_power_supplies[2];
	DBG("test %s-->%s-->%s\n",data->battery.name,data->usb.name,data->ac.name);
	rc = power_supply_register(&pdev->dev, &data ->battery);
	if (rc)
	{
		printk(KERN_ERR "Failed to register battery power supply (%d)\n", rc);
		goto err_battery_fail;
	}

	rc = power_supply_register(&pdev->dev, &data ->usb);
	if (rc)
	{
		printk(KERN_ERR "Failed to register usb power supply (%d)\n", rc);
		goto err_usb_fail;
	}
#if 1
	rc = power_supply_register(&pdev->dev, &data ->ac);
	if (rc)
	{
		printk(KERN_ERR "Failed to register ac power supply (%d)\n", rc);
		goto err_ac_fail;
	}
	DBG("--------cur time:0x%Lx\n",__FILE__,__FUNCTION__,ktime_get() );
#endif
   	 bat_vol_no_power_cnt = 81;
	g_adcbat = get_rock_adc0();
	g_adcref = get_rock_adc3();
	/*get originally battery stauts*/
	for(i=0;i<AD_SAMPLE_TIMES;i++)
	{
		rockchip_get_battery_status( );	
		mdelay(15);
	}
	/*low battery low need power down*/
	DBG("---->battery adcbat = %d adcref=%d\n",g_adcbat,g_adcref);
	DBG("---->battery present = %d\n",bat_present);
	DBG("---->battery status  = %d\n",bat_status);
	DBG("---->pb1 status = %d  usbchargestatus== %d\n",GPIOGetPinLevel(GPIOPortB_Pin1),!get_msc_connect_flag());
	DBG("---->battery current voltage = %d\n",bat_voltage);
	DBG("---->battery capacity = %d\n",bat_capacity);
	//if((bat_capacity == 0 )&&(GPIOGetPinLevel(GPIOPortB_Pin1)))
	//	bat_capacity = 1;
	if((bat_capacity == 0 )/*&&(GPIOGetPinLevel(GPIOPortB_Pin1) == 0)*/)
		 rk28_power_off();
	hrtimer_start(&data->timer,ktime_set(10,TS_POLL_DELAY),HRTIMER_MODE_REL);
	
	return 0;
err_battery_fail:
	power_supply_unregister(&data->battery);
	
err_usb_fail:
	power_supply_unregister(&data->usb);

err_ac_fail:
	power_supply_unregister(&data->ac);
 
	return rc;
		
}

#if 1   //add by cst 
static ssize_t ac_power_mode_show(struct device_driver *_drv,char *_buf)
{
        int count;

        count = sprintf(_buf,"%d",ac_power_off);
        return count;
}

static ssize_t ac_power_mode_store(struct device_driver *_drv,const char *_buf,size_t _count)
{
          
          ac_power_off  = (int)simple_strtol(_buf, NULL, 10);

          return _count;

}

static DRIVER_ATTR(ac_power_off,0666,ac_power_mode_show,ac_power_mode_store);

#endif

static struct platform_driver rockchip_battery_driver = {
	.probe	= rockchip_battery_probe,
	.driver	= {
		.name	= APP_BATT_PDEV_NAME,
		.owner	= THIS_MODULE,
	},
};


static int __init rockchip_battery_init(void)
{
	printk("%s::========================================\n",__func__);
	int ret = platform_driver_register(&rockchip_battery_driver);
	if (ret == 0)
	{
		ret = driver_create_file(&rockchip_battery_driver.driver, &driver_attr_ac_power_off);
	}
	return ret;
	//return 0;
}
module_init(rockchip_battery_init);
MODULE_DESCRIPTION("Rockchip Battery Driver");
MODULE_LICENSE("GPL");

Сайт создан в системе uCoz