zoukankan      html  css  js  c++  java
  • android电池充电以及电量检测驱动分析

       前段时间比较烦躁,各种不想学习不想工作,于是休息了几天。这几天又下来任务了--调试充电电路和电池电量检测电路,于是又开始工作,顺便把调试过程记录下来。

      平台: 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
    ");
    	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
    ");
    	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
    ",__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
    ", 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
    ");
    		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!
    ");
    	ret = device_create_file(&pdev->dev, &max8903_charger_dev_attr);
    	if (ret)
    		dev_err(&pdev->dev, "create device file failed!
    ");
    	ret = device_create_file(&pdev->dev, &max8903_usb_charger_dev_attr);
    	if (ret)
    		dev_err(&pdev->dev, "create device file failed!
    ");

    设备文件的实现代码为

    static ssize_t max8903_voltage_offset_discharger_show(struct device *dev,
    			    struct device_attribute *attr, char *buf)
    {
    	return sprintf(buf, "read offset_discharger:%04d
    ",
    		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
    ", 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
    ",
    		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
    ", 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
    ",
    		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
    ", 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!!
    ");
    				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
    ");
    			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!!
    ");
    				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.
    ");
    			ret = -EINVAL;
    			goto err;
    		}
    	}
    	if (pdata->chg) {
    		if (!gpio_is_valid(pdata->chg)) {
    			dev_err(dev, "Invalid pin: chg.
    ");
    			ret = -EINVAL;
    			goto err;
    		}
    		/* set CHG gpio input */
    		ret = gpio_request(pdata->chg, "max8903-CHG");
    		if (ret) {
    			printk(KERN_ERR"request max8903-CHG error!!
    ");
    			goto err;
    		} else {
    			gpio_direction_input(pdata->chg);
    		}
    	}
    	if (pdata->flt) {
    		if (!gpio_is_valid(pdata->flt)) {
    			dev_err(dev, "Invalid pin: flt.
    ");
    			ret = -EINVAL;
    			goto err;
    		}
    		/* set FLT gpio input */
    		ret = gpio_request(pdata->flt, "max8903-FLT");
    		if (ret) {
    			printk(KERN_ERR"request max8903-FLT error!!
    ");
    			goto err;
    		} else {
    			gpio_direction_input(pdata->flt);
    		}
    	}
    	if (pdata->usus) {
    		if (!gpio_is_valid(pdata->usus)) {
    			dev_err(dev, "Invalid pin: usus.
    ");
    			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.
    ");
    		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.
    ");
    		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)
    ",
    					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)
    ",
    					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)
    ",
    					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)
    ",
    					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.
    ", 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.
    ", 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.
    ");
    	else
    		dev_err(data->dev, "Charger recovered from a fault.
    ");
    	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;
    }

    到了这里电池充电的流程就走完了。









  • 相关阅读:
    BZOJ2241 [SDOI2011]打地鼠 【模拟】
    K-D tree入门
    BZOJ1924 [Sdoi2010]所驼门王的宝藏 【建图 + tarjan】
    BZOJ1925 [Sdoi2010]地精部落 【dp】
    BZOJ1926 [Sdoi2010]粟粟的书架 【主席树 + 二分 + 前缀和】
    BZOJ2457 [BeiJing2011]双端队列 【贪心】
    二进制集合枚举子集
    BZOJ1923 [Sdoi2010]外星千足虫 【高斯消元】
    BZOJ1922 [Sdoi2010]大陆争霸 【最短路】
    HDU3157:Crazy Circuits——题解
  • 原文地址:https://www.cnblogs.com/riskyer/p/3275632.html
Copyright © 2011-2022 走看看