1. 程式人生 > >android電池充電以及電量檢測驅動分析

android電池充電以及電量檢測驅動分析

http://www.cnblogs.com/riskyer/p/3275632.html

   前段時間比較煩躁,各種不想學習不想工作,於是休息了幾天。這幾天又下來任務了--除錯充電電路和電池電量檢測電路,於是又開始工作,順便把除錯過程記錄下來。

  平臺: cpu        飛思卡爾imx6q 4核

        充電晶片     MAX8903

        電量檢測晶片  MAX11801

        android版本  android4.0

一、電量檢測

   我們用的電池電量檢測晶片MAX11801其實是一款電阻觸控式螢幕的驅動晶片,它外帶一個AD採集引腳,因此我們用這個引腳來檢測電池電壓。MAX11801電源為3.3V而電池電壓範圍可能是0~4.2V,因此我們需要給電池電壓分壓。我們所用的電路如下



  知道了硬體電路下面來 新增這個晶片的驅動,這是一個i2c的晶片,因此首先在board檔案中新增i2c裝置

		I2C_BOARD_INFO("max11801", 0x48),
		.platform_data = (void *)&max11801_mode,
		.irq = gpio_to_irq(SABRESD_TS_INT),
	},

  然後新增這個晶片的驅動檔案放在/drivers/input/touchiscreen/max11801_ts.c

  對於這個驅動檔案我們只要讀取出AD的值就可以了,對於觸控式螢幕部分我們並不需要,因此主要是下面幾個函式

static u32 max11801_dcm_sample_aux(struct i2c_client *client)
{
	u8 temp_buf;
	int ret;
	int aux = 0;
	u32 sample_data = 0;
	/* AUX_measurement*/
	max11801_dcm_write_command(client, AUX_measurement);//傳送AD採集命令
	mdelay(5);
	ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_MSB, //讀取高位元組資料
						1, &temp_buf);
	if (ret < 1)
		printk(KERN_DEBUG "FIFO_RD_AUX_MSB read fails\n");
	else
		aux_buf[0] = temp_buf;
	mdelay(5);
	ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_LSB,    //讀取低位元組資料
						1, &temp_buf);
	if (ret < 1)
		printk(KERN_DEBUG "FIFO_RD_AUX_LSB read fails\n");
	else
		aux_buf[1] = temp_buf;
	aux = (aux_buf[0] << 4) +           //視最低4位無效並去掉
					(aux_buf[1] >> 4);

	/*
	10k和18.7k並聯後電阻 
	R=18.7*10/(18.7+10)=6.516
	V(aux) = V(bat)*6.516/(6.516+18.7)
	V(aux) = aux*3300/0xfff
	V(bat) = aux*1386880/444717
	*/
	sample_data = (aux*1386880)/444717;	//計算出電池電壓
	return sample_data;
}

u32  max11801_read_adc(void)
{
	u32 adc_data;
	adc_data = max11801_dcm_sample_aux(max11801_client);
//	printk("----%s %d\n",__func__,adc_data);	//lijianzhang
	return adc_data;
}
EXPORT_SYMBOL_GPL(max11801_read_adc);

由於電池電量檢測的驅動非常簡單,而且和充電驅動關係非常密切,因此一般都解除安裝充電驅動裡面,我們也是這麼做的。下面的程式碼都是從充電驅動中摘出來的,因此當大家看到,一些裝置檔案和函式引數型別 都是充電驅動中的  時候不要太奇怪。

通過上面的max11801_read_adc函式我們已經得到了理論計算的電池的電壓,但實際應用中由於分壓電阻誤差,焊接問題等,這個電壓會有一定的誤差因此需要一個校正函式

u32 calibration_voltage(struct max8903_data *data)
{
	int volt[ADC_SAMPLE_COUNT];
	u32 voltage_data;
	int i;
		for (i = 0; i < ADC_SAMPLE_COUNT; i++) {    //多次取樣,防止AD誤差
			if (data->charger_online == 0 && data->usb_charger_online == 0) {
				/* ADC offset when battery is discharger*/
				volt[i] = max11801_read_adc()-offset_discharger;    //沒有充電情況下 電壓誤差
				} else {
						if (data->charger_online == 1)
						volt[i] = max11801_read_adc()-offset_charger;//DC充電式 電壓誤差
						else if (data->usb_charger_online == 1)
						volt[i] = max11801_read_adc()-offset_usb_charger;//usb充電  電壓誤差
						else if (data->charger_online == 1 && data->usb_charger_online == 1)
						volt[i] = max11801_read_adc()-offset_charger;
				}
		
	}
	sort(volt, i, 4, cmp_func, NULL);//對電壓排序
	for (i = 0; i < ADC_SAMPLE_COUNT; i++)
		pr_debug("volt_sorted[%2d]: %d\n", i, volt[i]);
	/* get the average of second max/min of remained. */
	voltage_data = (volt[2] + volt[ADC_SAMPLE_COUNT - 3]) / 2;//去掉最大值最小值 並對剩餘資料求平均
	return voltage_data;
}

從上面函式我們讀取到了正確的電壓值。電池電壓是隨時變化的,我們要檢測電池電量,必須隨時採集,因此用一個定時器來做這件事情,程式碼如下:

INIT_DELAYED_WORK(&data->work, max8903_battery_work);
	schedule_delayed_work(&data->work, data->interval);

電壓採集完成後就是將電壓上報出去,上報的過程是:我們讀取到電壓變化->告訴android端電池電壓變化了->android會通過power_supply裝置檔案來讀取具體的電壓值。
我們來看定時器回撥函式

static void max8903_battery_work(struct work_struct *work)
{
	struct max8903_data *data;
	data = container_of(work, struct max8903_data, work.work);
	data->interval = HZ * BATTERY_UPDATE_INTERVAL;
	max8903_charger_update_status(data);    //檢測充電狀態
	max8903_battery_update_status(data);    //檢測電池狀態
	/* reschedule for the next time */
	schedule_delayed_work(&data->work, data->interval);//定時器繼續
}

檢測電池狀態函式

static void max8903_battery_update_status(struct max8903_data *data)
{
	int temp;
	static int temp_last;
	bool changed_flag;
	changed_flag = false;
	mutex_lock(&data->work_lock);
	temp = calibration_voltage(data);
	if (temp_last == 0) {
		data->voltage_uV = temp;
		temp_last = temp;
	}
	if (data->charger_online == 0 && temp_last != 0) {//DC充電狀態
		if (temp < temp_last) {
		temp_last = temp;
		data->voltage_uV = temp;
		} else {
		data->voltage_uV = temp_last;
		}
	}
	if (data->charger_online == 1 || data->usb_charger_online == 1) {//USB充電狀態和DC充電狀態
		data->voltage_uV = temp;
		temp_last = temp;
	}
	data->percent = calibrate_battery_capability_percent(data);//計算電量的百分比
	if (data->percent != data->old_percent) {   //電池電壓有變化
		data->old_percent = data->percent;
		changed_flag = true;
	}
	if (changed_flag) {         //如果有變化
		changed_flag = false;
		power_supply_changed(&data->bat);//告訴android端 電池電量改變了
	}
	/*
	    because boot time gap between led framwork and charger
	    framwork,when system boots with charger attatched, charger
	    led framwork loses the first charger online event,add once extra
	    power_supply_changed can fix this issure
	*/
	if (data->first_delay_count < 200) {
		data->first_delay_count = data->first_delay_count + 1 ;
		power_supply_changed(&data->bat);
	}

	mutex_unlock(&data->work_lock);
}

這裡我們看到了 power_supply_changed(&data->bat);告訴android端 電池電量改變了,那麼下一步android來讀取具體電壓,就涉及到了power_supply裝置檔案。
來看裝置檔案的建立過程

	data->bat.name = "max8903-charger";
	data->bat.type = POWER_SUPPLY_TYPE_BATTERY;
	data->bat.properties = max8903_battery_props;
	data->bat.num_properties = ARRAY_SIZE(max8903_battery_props);
	data->bat.get_property = max8903_battery_get_property;
	data->bat.use_for_apm = 1;
	retval = power_supply_register(&pdev->dev, &data->bat);//註冊裝置檔案
	if (retval) {
		dev_err(data->dev, "failed to register battery\n");
		goto battery_failed;
	}

這裡註冊了一個名為max8903-charger的 power_supply裝置檔案,這個裝置檔案包含了ARRAY_SIZE(max8903_battery_props)個操作分別為

static enum power_supply_property max8903_battery_props[] = {
	POWER_SUPPLY_PROP_VOLTAGE_NOW,//當前電壓
	POWER_SUPPLY_PROP_STATUS,       //當前充電狀態
	POWER_SUPPLY_PROP_PRESENT,      //不太清除
	POWER_SUPPLY_PROP_CAPACITY,     //電量百分比
	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,//電池極限電壓 最大值
	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,//電池極限電壓 最小值
	POWER_SUPPLY_PROP_HEALTH,       //電池健康狀態
	POWER_SUPPLY_PROP_CAPACITY_LEVEL,//電量水平,low或者normal
};

這些狀態是通過max8903_battery_get_property()這個函式來讀取的

static int max8903_battery_get_property(struct power_supply *bat,
				       enum power_supply_property psp,
				       union power_supply_propval *val)
{
	struct max8903_data *di = container_of(bat,
			struct max8903_data, bat);
	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
				if (gpio_get_value(di->pdata->chg) == 0) {
					di->battery_status = POWER_SUPPLY_STATUS_CHARGING;  //正在充電
				} else if (di->ta_in &&
					gpio_get_value(di->pdata->chg) == 1) {
					if (di->percent >= 99)
						di->battery_status = POWER_SUPPLY_STATUS_FULL;//電量大於99就充滿了
					else
						di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
					}
				  else if (di->usb_in &&
					gpio_get_value(di->pdata->chg) == 1) {
					if (di->percent >= 99)
					    di->battery_status = POWER_SUPPLY_STATUS_FULL;
					else
					  di->battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
					}
		val->intval = di->battery_status;
		return 0;
	default:
		break;
	}

	switch (psp) {
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
		val->intval = di->voltage_uV;
		break;
	case POWER_SUPPLY_PROP_CHARGE_NOW:
		val->intval = 0;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
		val->intval = HIGH_VOLT_THRESHOLD;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
		val->intval = LOW_VOLT_THRESHOLD;
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		val->intval = 1;
		break;
	case POWER_SUPPLY_PROP_CAPACITY:
		val->intval = di->percent < 0 ? 0 :
				(di->percent > 100 ? 100 : di->percent);
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		val->intval = POWER_SUPPLY_HEALTH_GOOD;
		if (di->fault)
			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
		break;
	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
		if (di->battery_status == POWER_SUPPLY_STATUS_FULL)
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
		else if (di->percent <= 15)
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;//電量小於15%就報低電量
		else
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;//否則就報正常
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

當我們註冊裝置檔案以後,可以在/sys/devices/platform/max8903-charger.1/power_supply/max8903-charger目錄下找到其裝置檔案如下


我們通過cat命令就可以隨時檢視電池狀態。

二、電池電壓校正引數

   上面我們知道根據硬體實際情況不同,AD採集出來的電池電壓需要校正引數。也就是

   static int offset_discharger;
   static int offset_charger;
   static int offset_usb_charger;

對於這三個引數,當然我們可以在驅動力寫死,但是為了以後的相容性我們可以通過android上層來設定,當我們裝置出廠時候,通過一配置檔案方便的來修改這三個引數,下面我們就來介紹一下,怎麼用裝置檔案和指令碼,來修改者三個引數:

我們用的是sys檔案系統的裝置檔案,建立程式碼為

	ret = device_create_file(&pdev->dev, &max8903_discharger_dev_attr);
	if (ret)
		dev_err(&pdev->dev, "create device file failed!\n");
	ret = device_create_file(&pdev->dev, &max8903_charger_dev_attr);
	if (ret)
		dev_err(&pdev->dev, "create device file failed!\n");
	ret = device_create_file(&pdev->dev, &max8903_usb_charger_dev_attr);
	if (ret)
		dev_err(&pdev->dev, "create device file failed!\n");

裝置檔案的實現程式碼為

static ssize_t max8903_voltage_offset_discharger_show(struct device *dev,
			    struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "read offset_discharger:%04d\n",
		offset_discharger);
}

static ssize_t max8903_voltage_offset_discharger_store(struct device *dev,
			     struct device_attribute *attr, const char *buf,
			     size_t count)
{
	offset_discharger = simple_strtoul(buf, NULL, 10);
	pr_info("read offset_discharger:%04d\n", offset_discharger);
	return count;
}

static ssize_t max8903_voltage_offset_charger_show(struct device *dev,
			    struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "read offset_charger:%04d\n",
		offset_charger);
}

static ssize_t max8903_voltage_offset_charger_store(struct device *dev,
			     struct device_attribute *attr, const char *buf,
			     size_t count)
{
	offset_charger = simple_strtoul(buf, NULL, 10);
	pr_info("read offset_charger:%04d\n", offset_charger);
	return count;
}

static ssize_t max8903_voltage_offset_usb_charger_show(struct device *dev,
			    struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "read offset_usb_charger:%04d\n",
		offset_usb_charger);
}

static ssize_t max8903_voltage_offset_usb_charger_store(struct device *dev,
			     struct device_attribute *attr, const char *buf,
			     size_t count)
{
	offset_usb_charger = simple_strtoul(buf, NULL, 10);
	pr_info("read offset_charger:%04d\n", offset_usb_charger);
	return count;
}

static struct device_attribute max8903_discharger_dev_attr = {
	.attr = {
		 .name = "max8903_ctl_offset_discharger",
		 .mode = S_IRUSR | S_IWUSR,
		 },
	.show = max8903_voltage_offset_discharger_show,
	.store = max8903_voltage_offset_discharger_store,
};

static struct device_attribute max8903_charger_dev_attr = {
	.attr = {
		 .name = "max8903_ctl_offset_charger",
		 .mode = S_IRUSR | S_IWUSR,
		 },
	.show = max8903_voltage_offset_charger_show,
	.store = max8903_voltage_offset_charger_store,
};

static struct device_attribute max8903_usb_charger_dev_attr = {
	.attr = {
		 .name = "max8903_ctl_offset_usb_charger",
		 .mode = S_IRUSR | S_IWUSR,
		 },
	.show = max8903_voltage_offset_usb_charger_show,
	.store = max8903_voltage_offset_usb_charger_store,
};

這樣,我們就可以在/sys/devices/platform/max8903-charger.1目錄下看到這樣三個裝置檔案


我們用cat命令可以讀出當前值,
用echo "500">>max8903_ctl_offset_charger 可以修改當前值

這樣我們就可以在系統啟動的時候,用指令碼來自動修改者三個值,我用的辦法是在init.rc的on boot階段增加這麼三行

#battery charge
    write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_charger 150
    write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_discharger 200
    write /sys/devices/platform/max8903-charger.1/max8903_ctl_offset_usb_charger 250

當然大家也可以把這三行命令寫在另外一個腳本里,然後init.rc中呼叫

三、電池充電

電池充電的電路


一共有4個引腳輸出到cpu中:

CHG_FLT1_B    電池檢測錯誤

UOK_B              usb插入

DOK_BDC插入

CHG_STATUS1_B 充電狀態

對於充電狀態的檢測過程,和電量檢測基本相同, 檢測到狀態變化->告訴android層發生變化->android層通過裝置檔案來讀取變化值

知道了這些我們來看驅動,首先在board檔案中新增max8903裝置

static struct max8903_pdata charger1_data = {
	.dok = SABRESD_CHARGE_DOK_B,
	.uok = SABRESD_CHARGE_UOK_B,
	.chg = CHARGE_STATE2,
	.flt = CHARGE_STATE1,
	.dcm_always_high = true,
	.dc_valid = true,
	.usb_valid = true, 
};

static struct platform_device sabresd_max8903_charger_1 = {
	.name	= "max8903-charger",
	.id	= 1,
	
	.dev	= {
		.platform_data = &charger1_data,
	},
};
platform_device_register(&sabresd_max8903_charger_1);

然後在/derivers/power/目錄下新增驅動檔案。充電狀態的變化都是IO電平的變化,我們來看驅動是怎麼處理這4個io的,首先在probe函式中

申請IO

if (pdata->dc_valid) {
		if (pdata->dok && gpio_is_valid(pdata->dok)) {
			gpio = pdata->dok; /* PULL_UPed Interrupt */
			/* set DOK gpio input */
			ret = gpio_request(gpio, "max8903-DOK");
			if (ret) {
				printk(KERN_ERR"request max8903-DOK error!!\n");
				goto err;
			} else {
				gpio_direction_input(gpio);
			}
			ta_in = gpio_get_value(gpio) ? 0 : 1;
		} else if (pdata->dok && gpio_is_valid(pdata->dok) && pdata->dcm_always_high) {
			ta_in = pdata->dok; /* PULL_UPed Interrupt */
			ta_in = gpio_get_value(gpio) ? 0 : 1;
		} else {
			dev_err(dev, "When DC is wired, DOK and DCM should"
					" be wired as well."
					" or set dcm always high\n");
			ret = -EINVAL;
			goto err;
		}
	}
	if (pdata->usb_valid) {
		if (pdata->uok && gpio_is_valid(pdata->uok)) {
			gpio = pdata->uok;
			/* set UOK gpio input */
			ret = gpio_request(gpio, "max8903-UOK");
			if (ret) {
				printk(KERN_ERR"request max8903-UOK error!!\n");
				goto err;
			} else {
				gpio_direction_input(gpio);
			}
			usb_in = gpio_get_value(gpio) ? 0 : 1;
		} else {
			dev_err(dev, "When USB is wired, UOK should be wired."
					"as well.\n");
			ret = -EINVAL;
			goto err;
		}
	}
	if (pdata->chg) {
		if (!gpio_is_valid(pdata->chg)) {
			dev_err(dev, "Invalid pin: chg.\n");
			ret = -EINVAL;
			goto err;
		}
		/* set CHG gpio input */
		ret = gpio_request(pdata->chg, "max8903-CHG");
		if (ret) {
			printk(KERN_ERR"request max8903-CHG error!!\n");
			goto err;
		} else {
			gpio_direction_input(pdata->chg);
		}
	}
	if (pdata->flt) {
		if (!gpio_is_valid(pdata->flt)) {
			dev_err(dev, "Invalid pin: flt.\n");
			ret = -EINVAL;
			goto err;
		}
		/* set FLT gpio input */
		ret = gpio_request(pdata->flt, "max8903-FLT");
		if (ret) {
			printk(KERN_ERR"request max8903-FLT error!!\n");
			goto err;
		} else {
			gpio_direction_input(pdata->flt);
		}
	}
	if (pdata->usus) {
		if (!gpio_is_valid(pdata->usus)) {
			dev_err(dev, "Invalid pin: usus.\n");
			ret = -EINVAL;
			goto err;
		}
	}

註冊DC充電的裝置檔案

mutex_init(&data->work_lock);
	data->fault = false;
	data->ta_in = ta_in;
	data->usb_in = usb_in;
	data->psy.name = "max8903-ac";
	data->psy.type = POWER_SUPPLY_TYPE_MAINS;
	data->psy.get_property = max8903_get_property;
	data->psy.properties = max8903_charger_props;
	data->psy.num_properties = ARRAY_SIZE(max8903_charger_props);
	ret = power_supply_register(dev, &data->psy);
	if (ret) {
		dev_err(dev, "failed: power supply register.\n");
		goto err_psy;
	}

註冊USB充電的裝置檔案

data->usb.name = "max8903-usb";
	data->usb.type = POWER_SUPPLY_TYPE_USB;
	data->usb.get_property = max8903_get_usb_property;
	data->usb.properties = max8903_charger_props;
	data->usb.num_properties = ARRAY_SIZE(max8903_charger_props);
	ret = power_supply_register(dev, &data->usb);
	if (ret) {
		dev_err(dev, "failed: power supply register.\n");
		goto err_psy;
	}

這兩個裝置檔案都只有一個操作:檢測充電器是否線上

static enum power_supply_property max8903_charger_props[] = {
	POWER_SUPPLY_PROP_ONLINE,
};

操作函式也很簡單

static int max8903_get_property(struct power_supply *psy,
		enum power_supply_property psp,
		union power_supply_propval *val)
{
	struct max8903_data *data = container_of(psy,
			struct max8903_data, psy);

	switch (psp) {
	case POWER_SUPPLY_PROP_ONLINE:
		val->intval = 0;
		if (data->ta_in)
			val->intval = 1;
		data->charger_online = val->intval;
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
static int max8903_get_usb_property(struct power_supply *usb,
		enum power_supply_property psp,
		union power_supply_propval *val)
{
	struct max8903_data *data = container_of(usb,
			struct max8903_data, usb);

	switch (psp) {
	case POWER_SUPPLY_PROP_ONLINE:
		val->intval = 0;
		if (data->usb_in)
			val->intval = 1;
		data->usb_charger_online = val->intval;
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

我們可以通過/sys/devices/platform/max8903-charger.1/power_supply/max8903-ac 目錄和/sys/devices/platform/max8903-charger.1/power_supply/max8903-usb目錄下的裝置檔案來訪問充電器的狀態



接下來是IO中斷

if (pdata->dc_valid) {
		ret = request_threaded_irq(gpio_to_irq(pdata->dok),
				NULL, max8903_dcin,
				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
				"MAX8903 DC IN", data);
		if (ret) {
			dev_err(dev, "Cannot request irq %d for DC (%d)\n",
					gpio_to_irq(pdata->dok), ret);
			goto err_usb_irq;
		}
	}

	if (pdata->usb_valid) {
		ret = request_threaded_irq(gpio_to_irq(pdata->uok),
				NULL, max8903_usbin,
				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
				"MAX8903 USB IN", data);
		if (ret) {
			dev_err(dev, "Cannot request irq %d for USB (%d)\n",
					gpio_to_irq(pdata->uok), ret);
			goto err_dc_irq;
		}
	}

	if (pdata->flt) {
		ret = request_threaded_irq(gpio_to_irq(pdata->flt),
				NULL, max8903_fault,
				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
				"MAX8903 Fault", data);
		if (ret) {
			dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
					gpio_to_irq(pdata->flt), ret);
			goto err_flt_irq;
		}
	}

	if (pdata->chg) {
		ret = request_threaded_irq(gpio_to_irq(pdata->chg),
				NULL, max8903_chg,
				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
				"MAX8903 Fault", data);
		if (ret) {
			dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
					gpio_to_irq(pdata->flt), ret);
			goto err_chg_irq;
		}
	}

這4個IO的中斷處理函式很類似

static irqreturn_t max8903_dcin(int irq, void *_data)
{
	struct max8903_data *data = _data;
	struct max8903_pdata *pdata = data->pdata;
	bool ta_in;

	ta_in = gpio_get_value(pdata->dok) ? false : true;   //儲存當前dok值

	if (ta_in == data->ta_in)
		return IRQ_HANDLED;

	data->ta_in = ta_in;
	pr_info("TA(DC-IN) Charger %s.\n", ta_in ?
			"Connected" : "Disconnected");
	max8903_charger_update_status(data);    
	max8903_battery_update_status(data);    
	power_supply_changed(&data->psy);   //報告狀態改變
	power_supply_changed(&data->bat);
	return IRQ_HANDLED;
}
static irqreturn_t max8903_usbin(int irq, void *_data)
{
	struct max8903_data *data = _data;
	struct max8903_pdata *pdata = data->pdata;
	bool usb_in;
	usb_in = gpio_get_value(pdata->uok) ? false : true; //儲存當前uok值
	if (usb_in == data->usb_in)
		return IRQ_HANDLED;

	data->usb_in = usb_in;
	max8903_charger_update_status(data);
	max8903_battery_update_status(data);
	pr_info("USB Charger %s.\n", usb_in ?
			"Connected" : "Disconnected");
	power_supply_changed(&data->bat);
	power_supply_changed(&data->usb);  //報告狀態改變
	return IRQ_HANDLED;
}

static irqreturn_t max8903_fault(int irq, void *_data)
{
	struct max8903_data *data = _data;
	struct max8903_pdata *pdata = data->pdata;
	bool fault;

	fault = gpio_get_value(pdata->flt) ? false : true;  //儲存當前電池錯誤值

	if (fault == data->fault)
		return IRQ_HANDLED;

	data->fault = fault;

	if (fault)
		dev_err(data->dev, "Charger suffers a fault and stops.\n");
	else
		dev_err(data->dev, "Charger recovered from a fault.\n");
	max8903_charger_update_status(data);
	max8903_battery_update_status(data);
	power_supply_changed(&data->psy);
	power_supply_changed(&data->bat);
	power_supply_changed(&data->usb);   //報告狀態改變
	return IRQ_HANDLED;
}

static irqreturn_t max8903_chg(int irq, void *_data)
{
	struct max8903_data *data = _data;
	struct max8903_pdata *pdata = data->pdata;
	int chg_state;

	chg_state = gpio_get_value(pdata->chg) ? false : true;//儲存電池充電狀態

	if (chg_state == data->chg_state)
		return IRQ_HANDLED;

	data->chg_state = chg_state;
	max8903_charger_update_status(data);
	max8903_battery_update_status(data);
	power_supply_changed(&data->psy);
	power_supply_changed(&data->bat);
	power_supply_changed(&data->usb);//報告狀態改變
	return IRQ_HANDLED;
}

到了這裡電池充電的流程就走完了。

相關推薦

android電池充電以及電量檢測驅動分析

http://www.cnblogs.com/riskyer/p/3275632.html    前段時間比較煩躁,各種不想學習不想工作,於是休息了幾天。這幾天又下來任務了--除錯充電電路和電池電量檢測電路,於是又開始工作,順便把除錯過程記錄下來。   平臺: cpu  

SSD人臉檢測以及FDDB檢測結果分析

前段時間使用caffe版本的SSD訓練人臉檢測,效果還不錯,在FDDB上測試了下結果最終只有89%的準確率,但是誤判率很低,結果如下: 為了分析訓練的SSD在FDDB上對於哪些型別的人臉檢測結果較差,結果如下:藍色的橢圓為FDDB的原始標註,紅色的矩形為現

MTK Android O 充電狀態下電池電量100%時不顯示閃電圖示

需求: android 8.1.1版本google原生充電的時候都會顯示一個閃電的形狀,客戶要求在百分之百電量的時候不顯示閃電 修改: frameworks\base\packages\SettingsLib\src\com\android\settingslib\graph\Bat

android 4.4 電池電量管理底層分析(C\C++層)

參考文獻:http://blog.csdn.net/wlwl0071986/article/details/38778897 簡介: Linux電池驅動用於和PMIC互動、負責監聽電池產生的相關事件,例如低電報警、電量發生變化、高溫報警、USB插拔等等。 Android電池

android 獲取充電狀態 電池電量

public class MainActivity extends Activity { /** * 先宣告一個 IntentFilter 物件 */ private IntentFilter mIntentFilter; private TextVie

Android 電池關機充電

基本 系統 art 基本原理 關機 ron tar href csdn android 電池(一):鋰電池基本原理篇 android 電池(二):android關機充電流程、充電畫面顯示 android 電池(三):android電池系統 android電池(四):電

N76E003之ADC電量檢測(程式、分析、電路)

模數轉換器即A/D轉換器,或簡稱ADC,通常是指一個將模擬訊號轉變為數字訊號的電子元件。 先來看看N76E003 ADC工作方式 再看下相關暫存器,方便理解上圖 現在我們只需要配置好以上幾個暫存器,就可以開始使用ADC了,為了保證程式的及時性,我們採取A

電池驅動除錯總結,電池服務+電量驅動+除錯方法

1.概述: Android電池服務,用來監聽核心上報的電池事件,並將最新的電池資料上報給系統,系統收到新資料後會去更新電池顯示狀態、剩餘電量等資訊。如果收到過溫報警和低電報警,系統會自動觸發關機流程,保護電池和機器不受到危害。 Android電池服務的啟動和執行流程: And

Android 音訊驅動分析--A10

 A10+Android4.0 音訊驅動(樹莓派II 原始碼) linux-3.0目錄 make ARCH=arm menuconfig 進到核心配置介面,可以看到  知道我們的配置項名字,然後進 目錄 :\lichee\linux-3.0\sound\soc  看Kcon

Android Handler 機制以及各方法所線上程原理分析

Handler 的定義及作用: 因為有的文章已經說得比較清楚了,就直接引用下。這裡借鑑http://mobile.51cto.com/aprogram-442833.htm 一、Handler的定義: 主要接受子執行緒傳送的資料, 並用此資料配合主執行緒更新UI。

Android 用Batterystats和電池歷史描畫電量使用圖

Contents 用Batterystats和電池歷史描畫電量使用圖... 1 安裝電池歷史... 1 從BatteryStats裡獲得資料... 3 從電池歷史圖表中檢視資料... 4 更多BatteryStats輸出... 5   用Batterystats

Android webView與js 互動以及jsbridge框架原始碼分析

1.簡單篇 如何實現簡單的android 呼叫js 與js呼叫android 讓webview做一下操作 private void init(Context context){ WebSettings setting =

Android USB 驅動分析與開發----程式設計

一、USB驅動程式碼架構和使用     1、程式碼簡介        USB驅動程式碼在/drivers/usb/gadget下,有三個檔案:android.c,f_adb.c,        f_mass_storage.c;g_android.ko 是由這三個檔案編譯

Android電池架構分析

此文基於博文 http://wangzhigang2.iteye.com/blog/1270925稍作補充,主要新增 kernel流程的分析  BatteryService實現了一個UevenObserver mUEventObserver。 uevent是Linux核

深度理解Android InstantRun原理以及原始碼分析

Instant Run官方介紹 簡單介紹一下Instant Run,它是Android Studio2.0以後新增的一個執行機制,能夠顯著減少你第二次及以後的構建和部署時間。簡單通俗的解釋就是,當你在Android Studio中改了你的程式碼,Instant Ru

android-進階(3)-自定義view(2)-Android中View繪製流程以及相關方法的分析

最近正在學自定義view,這篇文章主要講view的繪製流程和一些相關的方法,淺顯易懂,寫的非常好,忍不住就轉載了。             前言: 本文是我讀《Android核心剖析》第13章----View工作原理總結而成的,在此膜拜下作者 。

Android 耗時程式碼(ANR)的查詢檢測分析解決 TraceView的使用手冊

DALVIK THREADS (21): "main" prio=5 tid=1 Sleeping   | group="main" sCount=1 dsCount=0 obj=0x76af9fb0 self=0x7f9b49a000   | sysTid=4423 nice=0 cgrp=default

android 電池(二):android關機充電流程、充電畫面顯示

上一篇我們講了鋰電池的充放電的流程和電池的一些特性,這一節我們重點說一下android關機充電是怎麼、充電畫面顯示是怎麼實現的,這個在工作中也比較有用,我們開始做這一塊的時候也走了不少的彎路。我記得我們做adnroid2.3的時候,關機狀態和充電logo顯示是在uboot

MTK平臺下Battery驅動分析充電流程

轉自:http://blog.csdn.net/baidu_34021173/article/details/51105223主要涉及程式碼:Kernel:kernel-3.10\drivers\power\mediatek\kernel-3.10\drivers\misc\

Android中Preference的使用以及監聽事件分析

                  在Android系統原始碼中,絕大多數應用程式的UI佈局採用了Preference的佈局結構,而不是我們平時在模擬器中構建應用程式時使用的View佈局結構,例如,Setting模組中佈局。當然,凡事都有例外,FMRadio應用程式中