📄 ds2786_battery.c
字号:
di->full_counter = 0; } else if (di->current_uA < 10*1000 && di->charge_status != POWER_SUPPLY_STATUS_FULL) { /* Don't consider the battery to be full unless * we've seen the current < 10 mA at least two * consecutive times. **/ //POWER_SUPPLY_STATUS_NOT_CHARGING di->full_counter++; if (di->full_counter < 2) di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;//POWER_SUPPLY_STATUS_CHARGING; else di->charge_status = POWER_SUPPLY_STATUS_FULL; } if (di->charge_status != old_charge_status) power_supply_changed(&di->bat);}static void ds2786_battery_work(struct work_struct *work){ //struct ds2786_device_info *di = container_of(work, //struct ds2786_device_info, monitor_work.work); const int interval = HZ * 60; //DBG("\n"); //dev_dbg(di->dev, "%s\n", __FUNCTION__); ds2786_battery_update_status(di); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);}#define to_ds2786_device_info(x) container_of((x), struct ds2786_device_info, \ bat);static void ds2786_battery_external_power_changed(struct power_supply *psy){ //struct ds2786_device_info *di = to_ds2786_device_info(psy); DBG("\n"); //dev_dbg(di->dev, "%s\n", __FUNCTION__); cancel_delayed_work(&di->monitor_work); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);}static int ds2786_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val){ //struct ds2786_device_info *di = to_ds2786_device_info(psy); DBG("\n"); ds2786_battery_update_status(di); switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = di->charge_status; return 0; default: break; } switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = di->voltage_uV; break; case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = di->current_uA; break; case POWER_SUPPLY_PROP_CAPACITY: val->intval = di->rem_capacity; break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: val->intval = di->rated_capacity; break; case POWER_SUPPLY_PROP_CHARGE_FULL: val->intval = di->full_active_uAh; break; case POWER_SUPPLY_PROP_CHARGE_EMPTY: val->intval = di->empty_uAh; break; case POWER_SUPPLY_PROP_CHARGE_NOW: val->intval = di->accum_current_uAh; break; case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: val->intval = di->life_sec; break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: val->intval = di->life_sec; break; case POWER_SUPPLY_PROP_TEMP: val->intval = di->temp_C; break; case POWER_SUPPLY_PROP_ONLINE: printk(KERN_ALERT"POWER_SUPPLY_PROP_ONLINE\n"); break; default: return -EINVAL; } dprintk(KERN_ALERT"val->intval=%d\n",val->intval); return 0;}static enum power_supply_property ds2786_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_EMPTY, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_TEMP,};static int ds2786_init(void){ char buf[8]; DBG("\n"); i2c_ds2786_read(di->client,buf,DS2786_STATUS_CONFIG,1); i2c_ds2786_read(di->client,buf+1,DS2786_RELATIVE_CAP,1); if (buf[1]==0) { dprintk(KERN_ALERT"what's worry?\n"); buf[0] = DS2786_COMMAND; buf[1] = 0x80; i2c_ds2786_write(di->client, buf,1); goto init_cap; } if (buf[0]&DS2786_PROF) {init_cap: dprintk(KERN_ALERT"ds2786 init\n"); buf[0] = DS2786_INITIAL_CAP; buf[1] = 0x1d;//4400mAh buf[2] = 0x08;//20mA buf[3] = 0x04;//4.88mV/15min buf[4] = 0x60;//I2c addr buf[5] = 0x78;//60% i2c_ds2786_write(di->client, buf,5); i2c_ds2786_read(di->client,buf,DS2786_INITIAL_CAP,1); printk(KERN_ALERT"ds2786_initial_cap=%d\n",(int)buf[0]); buf[0] = DS2786_CURRENT_OFFSET_BIAS; buf[1] = 0x02;//5mA i2c_ds2786_write(di->client, buf,1); buf[0]=DS2786_STATUS_CONFIG; i2c_ds2786_read(di->client,buf+1,DS2786_STATUS_CONFIG,1); buf[1]&=~((DS2786_SMOD) | (DS2786_PROF)) | DS2786_VODIS; i2c_ds2786_write(di->client, buf,1); i2c_ds2786_read(di->client,buf,DS2786_STATUS_CONFIG,1); printk(KERN_ALERT"ds2786_status_config=%d\n",(int)buf[0]); buf[0]=DS2786_COMMAND; i2c_ds2786_read(di->client,buf+1,DS2786_COMMAND,1); buf[1]|=DS2786_SOCV; i2c_ds2786_write(di->client, buf,1); udelay(20); i2c_ds2786_read(di->client,buf,DS2786_COMMAND,1); dprintk(KERN_ALERT"ds2786_command=%d\n",(int)buf[0]); } buf[0]=DS2786_INITIAL_CAP; if (i2c_ds2786_read(di->client,buf,DS2786_INITIAL_CAP,1)==1); di->rated_capacity = 128*1000000L/(long)buf[0]; printk(KERN_INFO"Initializing ds2786\n");}static irqreturn_t pwr_chang_irq(int irqno, void *dev_id){ ds2786_battery_external_power_changed(NULL); printk(KERN_ALERT"PWR\n"); return IRQ_HANDLED;}static int ds2786_battery_probe(struct platform_device *pdev){ int retval = 0; DBG("\n"); di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) { retval = -ENOMEM; goto di_alloc_failed; } platform_set_drvdata(pdev, di); di->client==NULL; di->ds2786_driver.id=I2C_DRIVERID_I2CDEV; di->ds2786_driver.attach_adapter=ds2786_attach_adapter; di->ds2786_driver.detach_client=ds2786_detach_client; di->ds2786_driver.driver.name="ds2786"; retval=i2c_add_driver(&di->ds2786_driver); if (retval | di->client==NULL) goto batt_failed; printk(KERN_ALERT"%retval: addr:%d\n",retval,di->client->addr); if (di->client->addr!=0x36) return -1; ds2786_init(); //return 0; di->dev = &pdev->dev; di->bat.name = pdev->dev.bus_id; di->bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bat.properties = ds2786_battery_props; di->bat.num_properties = ARRAY_SIZE(ds2786_battery_props); di->bat.get_property = ds2786_battery_get_property; di->bat.external_power_changed = ds2786_battery_external_power_changed; di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; di->update_time=0; retval = power_supply_register(&pdev->dev, &di->bat); if (retval) { dev_err(di->dev, "failed to register battery\n"); goto batt_failed; } INIT_DELAYED_WORK(&di->monitor_work, ds2786_battery_work); di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id); if (!di->monitor_wqueue) { retval = -ESRCH; goto workqueue_failed; } queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1); request_irq(IRQ_EINT3,pwr_chang_irq,0,"PWR_MON",0); //s3c_irqext_type(IRQ_EINT3,0x03); goto success;workqueue_failed: power_supply_unregister(&di->bat);batt_failed: kfree(di); printk(KERN_ALERT"there is no DS2786\n");di_alloc_failed:success: return retval;}static int ds2786_battery_remove(struct platform_device *pdev){ struct ds2786_device_info *di = platform_get_drvdata(pdev); cancel_rearming_delayed_workqueue(di->monitor_wqueue, &di->monitor_work); destroy_workqueue(di->monitor_wqueue); power_supply_unregister(&di->bat); i2c_del_driver(&di->ds2786_driver); return 0;}#ifdef CONFIG_PMstatic int ds2786_battery_suspend(struct platform_device *pdev, pm_message_t state){ struct ds2786_device_info *di = platform_get_drvdata(pdev); cancel_delayed_work(&di->monitor_work); di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; printk(KERN_ALERT"ds2786_battery_suspend\n"); return 0;}static int ds2786_battery_resume(struct platform_device *pdev){ struct ds2786_device_info *di = platform_get_drvdata(pdev); di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; power_supply_changed(&di->bat); //cancel_delayed_work(&di->monitor_work); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ*60); printk(KERN_ALERT"ds2786_battery_resume\n"); return 0;}#else#define ds2786_battery_suspend NULL#define ds2786_battery_resume NULL#endif /* CONFIG_PM */static struct platform_driver ds2786_battery_driver = { .driver = { .name = "ds2786-battery", }, .probe = ds2786_battery_probe, .remove = ds2786_battery_remove, .suspend = ds2786_battery_suspend, .resume = ds2786_battery_resume,};static int __init ds2786_battery_init(void){ return platform_driver_register(&ds2786_battery_driver);}static void __exit ds2786_battery_exit(void){ platform_driver_unregister(&ds2786_battery_driver);}module_init(ds2786_battery_init);module_exit(ds2786_battery_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " "Matt Reimer <mreimer@vpop.net>, " "Anton Vorontsov <cbou@mail.ru>");MODULE_DESCRIPTION("ds2760 battery driver");//end of apm part
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -