static int __devinit vt1603_bat_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { int ret = 0; struct vt1603_bat_drvdata *bat_drv = NULL; struct vt1603_bat_platform_data *bat_pdata; bat_dbg("Enter\n"); bat_pdata = i2c->dev.platform_data; if (NULL == bat_pdata) { bat_dbg("vt1603_bat: platform data NULL\n"); ret = -ENODATA; goto out; } bat_drv = kzalloc(sizeof(*bat_drv), GFP_KERNEL); if (!bat_drv) { bat_dbg("vt1603_bat: alloc driver data failed\n"); ret = -ENOMEM; goto out; } vt1603_bat = bat_drv; bat_drv->i2c = i2c; dev_set_drvdata(&i2c->dev, bat_drv); vt1603_reg_dump(bat_drv, 0xc0, 12); #ifdef CONFIG_VT1603_BATTERY_ENABLE vt1603_bat_info_init(bat_drv); vt1603_bat_work(&bat_drv->work); #endif printk(KERN_INFO "VT1603 SAR-ADC Battery Driver OK!\n"); goto out; out: bat_dbg("Exit\n"); return ret; }
static void __exit vt1603_bat_i2c_exit(void) { bat_dbg("Enter\n"); i2c_unregister_device(vt1603_bat->i2c); i2c_del_driver(&vt1603_bat_i2c_driver); bat_dbg("Exit\n"); }
static int __init vt1603_bat_uboot_env_check(void) { int len = 128; char buf[128] = { 0 }; int ret = 0; int bat_op = 0; int bat_update_interval = 0; /* TODO uboot env should be like * 2:1000:b78:972:b29:b11:afe:aca:aab:a94:a80:a64:a40:a1b:972 */ ret = wmt_getsyspara("wmt.io.bat", buf, &len); if (ret) { bat_dbg("can not find parameter: wmt.io.bat\n"); ret = -ENODATA; goto out; } bat_dbg("%s", buf); sscanf(buf,"%x:%x", &bat_op, &bat_update_interval); bat_dbg("bat_op:%d, bat_update_interval:%d\n", bat_op, bat_update_interval); if (bat_op != 2) { bat_dbg("VT1603 Battery disabled now\n"); ret = -ENODEV; goto out; } /* battery update interval 1sec ~ 30sec */ if ((bat_update_interval > 1000) && (bat_update_interval < 30000)) vt1603_bat_pdata.interval = bat_update_interval; out: return ret; }
/* * vt1603_work_mode_switch - switch VT1603 to battery mode * @bat_drv: vt1603 battery driver data */ static void vt1603_switch_to_bat_mode(struct vt1603_bat_drvdata *bat_drv) { bat_dbg("Enter\n"); vt1603_set_reg8(bat_drv, VT1603_CR_REG, 0x00); vt1603_set_reg8(bat_drv, VT1603_AMCR_REG, BIT0); bat_dbg("Exit\n"); }
static void wm8650_wakeup_exit(u8 wk_src) { bat_dbg("Enter\n"); bat_dbg("vt1603 battery alarm use wakeup src:0x%08x\n", wk_src); /* disable WAKE_UP */ REG8_VAL(GPIO_CTRL_GP2_WAKEUP_SUS_BYTE_ADDR) &= ~wk_src; bat_dbg("Exit\n"); return ; }
/* * vt1603_bat_tmr_isr - vt1603 battery detect timer isr * @bat_drvdata_addr: address of vt1603 battery driver data */ static void vt1603_bat_tmr_isr(unsigned long bat_drvdata_addr) { struct vt1603_bat_drvdata *bat_drv; bat_dbg("Enter\n"); bat_drv = (struct vt1603_bat_drvdata *)bat_drvdata_addr; schedule_work(&bat_drv->work); bat_dbg("Exit\n"); return ; }
static int vt1603_bat_alarm_release(struct vt1603_bat_drvdata *bat_drv, int wk_src) { bat_dbg("Enter\n"); wm8650_wakeup_exit(wk_src); vt1603_clrbits(bat_drv, VT1603_BAEN_REG, BIT1 | BIT0); bat_dbg("Exit\n"); return 0; }
/* * vt1603_reg_dump - dubug function, for dump vt1603 related registers * @bat_drv: vt1603 battery driver data */ static void vt1603_reg_dump(struct vt1603_bat_drvdata *bat_drv, u8 addr, int len) { u8 i; for (i = addr; i < addr + len; i += 2) bat_dbg("reg[%d]:0x%02X, reg[%d]:0x%02X\n", i, vt1603_get_reg8(bat_drv, i), i + 1, vt1603_get_reg8(bat_drv, i + 1)); }
static int vt1603_bat_i2c_resume(struct i2c_client *i2c) { struct vt1603_bat_drvdata *bat_drv = NULL; struct vt1603_bat_platform_data *bat_pdata = NULL; bat_dbg("Enter\n"); bat_drv = dev_get_drvdata(&i2c->dev); bat_pdata = i2c->dev.platform_data; #ifdef CONFIG_VT1603_BATTERY_ALARM vt1603_bat_alarm_release(bat_drv, bat_pdata->wakeup_src); #endif #ifdef CONFIG_VT1603_BATTERY_ENABLE mod_timer(&bat_drv->bat_tmr, jiffies + msecs_to_jiffies(3000)); #endif bat_dbg("Exit\n"); return 0; }
static int vt1603_bat_i2c_suspend(struct i2c_client *i2c, pm_message_t message) { struct vt1603_bat_drvdata *bat_drv = NULL; struct vt1603_bat_platform_data *bat_pdata = NULL; bat_dbg("Enter\n"); bat_drv = dev_get_drvdata(&i2c->dev); bat_pdata = i2c->dev.platform_data; #ifdef CONFIG_VT1603_BATTERY_ENABLE del_timer_sync(&bat_drv->bat_tmr); #endif #ifdef CONFIG_VT1603_BATTERY_ALARM vt1603_bat_alarm_setup(bat_drv, bat_pdata->alarm_threshold, bat_pdata->wakeup_src); #endif bat_dbg("Exit\n"); return 0; }
static int __devexit vt1603_bat_i2c_remove(struct i2c_client *i2c) { struct vt1603_bat_drvdata *bat_drv = dev_get_drvdata(&i2c->dev); bat_dbg("Enter\n"); vt1603_bat = NULL; #ifdef CONFIG_VT1603_BATTERY_ENABLE del_timer_sync(&bat_drv->bat_tmr); bat_drv->bat_val = 0; bat_drv->detect_time = 0; #endif dev_set_drvdata(&i2c->dev, NULL); kfree(bat_drv); bat_drv = NULL; bat_dbg("Exit\n"); return 0; }
static void wm8650_wakeup_init(int wk_src) { bat_dbg("Enter\n"); bat_dbg("vt1603 battery alarm use wakeup src:0x%08x\n", wk_src); /* disable WAKE_UP first */ REG8_VAL(GPIO_CTRL_GP2_WAKEUP_SUS_BYTE_ADDR) &= ~wk_src; /* disable WAKE_UP output */ REG8_VAL(GPIO_OC_GP2_WAKEUP_SUS_BYTE_ADDR) &= ~wk_src; /* enable pull high/low */ REG8_VAL(GPIO_PULL_EN_GP2_WAKEUP_SUS_BYTE_ADDR) |= wk_src; /* set pull high WAKE_UP */ REG8_VAL(GPIO_PULL_CTRL_GP2_WAKEUP_SUS_BYTE_ADDR) |= wk_src; /* enable WAKE_UP last */ REG8_VAL(GPIO_CTRL_GP2_WAKEUP_SUS_BYTE_ADDR) |= wk_src; bat_dbg("Exit\n"); return ; }
static void hna_local_del(struct hna_local_entry *hna_local_entry, char *message) { bat_dbg(DBG_ROUTES, "Deleting local hna entry (%pM): %s\n", hna_local_entry->addr, message); hash_remove(hna_local_hash, hna_local_entry->addr); _hna_local_del(hna_local_entry); }
int throw_uevent(struct bat_priv *bat_priv, enum uev_type type, enum uev_action action, const char *data) { int ret = -1; struct hard_iface *primary_if = NULL; struct kobject *bat_kobj; char *uevent_env[4] = { NULL, NULL, NULL, NULL }; primary_if = primary_if_get_selected(bat_priv); if (!primary_if) goto out; bat_kobj = &primary_if->soft_iface->dev.kobj; uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) + strlen(uev_type_str[type]) + 1, GFP_ATOMIC); if (!uevent_env[0]) goto out; sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]); uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) + strlen(uev_action_str[action]) + 1, GFP_ATOMIC); if (!uevent_env[1]) goto out; sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]); /* If the event is DEL, ignore the data field */ if (action != UEV_DEL) { uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) + strlen(data) + 1, GFP_ATOMIC); if (!uevent_env[2]) goto out; sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data); } ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); out: kfree(uevent_env[0]); kfree(uevent_env[1]); kfree(uevent_env[2]); if (primary_if) hardif_free_ref(primary_if); if (ret) bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send " "uevent for (%s,%s,%s) event (err: %d)\n", uev_type_str[type], uev_action_str[action], (action == UEV_DEL ? "NULL" : data), ret); return ret; }
void _hna_global_del_orig(struct hna_global_entry *hna_global_entry, char *message) { bat_dbg(DBG_ROUTES, "Deleting global hna entry %pM (via %pM): %s\n", hna_global_entry->addr, hna_global_entry->orig_node->orig, message); hash_remove(hna_global_hash, hna_global_entry->addr); kfree(hna_global_entry); }
/* * vt1603_get_reg8 - get register value of vt1603 * @bat_drv: vt1603 battery driver data * @reg: vt1603 register address */ static u8 vt1603_get_reg8(struct vt1603_bat_drvdata *bat_drv, u8 reg) { u8 val = 0; int ret = 0; ret = vt1603_i2c_read(bat_drv->i2c, reg, &val); if (ret) bat_dbg("vt1603_bat: read register failed with error:%d\n", ret); return val; }
static int vt1603_bat_alarm_setup(struct vt1603_bat_drvdata *bat_drv, u8 threshold, int wk_src) { bat_dbg("Enter\n"); /* register setting */ vt1603_set_reg8(bat_drv, VT1603_PWC_REG, 0x08); vt1603_set_reg8(bat_drv, VT1603_CR_REG, 0x00); vt1603_set_reg8(bat_drv, VT1603_AMCR_REG, 0x01); vt1603_set_reg8(bat_drv, VT1603_BTHD_REG, threshold & 0xFF); vt1603_clrbits(bat_drv, VT1603_BAEN_REG, BIT2); vt1603_setbits(bat_drv, VT1603_BAEN_REG, BIT1 | BIT0); vt1603_set_reg8(bat_drv, VT1603_BCLK_REG, 0x28); /* vt1603 gpio1 setup */ vt1603_gpio1_low_active_setup(bat_drv); /* wakeup setup */ wm8650_wakeup_init(wk_src); bat_dbg("Exit\n"); return 0; }
static int __init vt1603_bat_i2c_init(void) { int ret = 0; struct i2c_adapter *adapter = NULL; struct i2c_client *client = NULL; struct i2c_board_info *vt1603_i2c_bi = NULL; bat_dbg("Enter\n"); ret = vt1603_bat_uboot_env_check(); if (ret) { bat_dbg("vt1603_bat uboot env check failed\n"); goto out; } vt1603_i2c_bi = &vt1603_bat_i2c_board_info; adapter = i2c_get_adapter(vt1603_bat_pdata.i2c_bus_id); if (NULL == adapter) { bat_dbg("can not get i2c adapter, client address error\n"); ret = -ENODEV; goto out; } client = i2c_new_device(adapter, vt1603_i2c_bi); if (client == NULL) { bat_dbg("allocate i2c client failed\n"); ret = -ENOMEM; goto out; } i2c_put_adapter(adapter); ret = i2c_add_driver(&vt1603_bat_i2c_driver); if (ret) { bat_dbg("register vt1603 battery i2c driver failed\n"); goto release_client; } bat_dbg("Exit\n"); goto out; release_client: i2c_unregister_device(client); client = NULL; out: return ret; }
static void s3c_bat_discharge_reason(struct chg_data *chg) { int discharge_reason; ktime_t ktime; struct timespec cur_time; union power_supply_propval value; if (chg->pdata && chg->pdata->psy_fuelgauge && chg->pdata->psy_fuelgauge->get_property) { chg->pdata->psy_fuelgauge->get_property( chg->pdata->psy_fuelgauge, POWER_SUPPLY_PROP_VOLTAGE_NOW, &value); chg->bat_info.batt_vcell = value.intval; chg->pdata->psy_fuelgauge->get_property( chg->pdata->psy_fuelgauge, POWER_SUPPLY_PROP_CAPACITY, &value); if ((chg->bat_info.charging_status != POWER_SUPPLY_STATUS_DISCHARGING) || (chg->bat_info.batt_soc > value.intval)) chg->bat_info.batt_soc = value.intval; } discharge_reason = chg->bat_info.dis_reason & 0xf; if ((discharge_reason & DISCONNECT_BAT_FULL) && chg->bat_info.batt_vcell < RECHARGE_COND_VOLTAGE) chg->bat_info.dis_reason &= ~DISCONNECT_BAT_FULL; if ((discharge_reason & DISCONNECT_TEMP_OVERHEAT) && chg->bat_info.batt_temp <= HIGH_RECOVER_TEMP) chg->bat_info.dis_reason &= ~DISCONNECT_TEMP_OVERHEAT; if ((discharge_reason & DISCONNECT_TEMP_FREEZE) && chg->bat_info.batt_temp >= LOW_RECOVER_TEMP) chg->bat_info.dis_reason &= ~DISCONNECT_TEMP_FREEZE; if ((discharge_reason & DISCONNECT_OVER_TIME) && chg->bat_info.batt_vcell < RECHARGE_COND_VOLTAGE) chg->bat_info.dis_reason &= ~DISCONNECT_OVER_TIME; if (chg->bat_info.batt_is_full) chg->bat_info.dis_reason |= DISCONNECT_BAT_FULL; if (chg->bat_info.batt_health != POWER_SUPPLY_HEALTH_GOOD) chg->bat_info.dis_reason |= (chg->bat_info.batt_health == POWER_SUPPLY_HEALTH_OVERHEAT) ? DISCONNECT_TEMP_OVERHEAT : DISCONNECT_TEMP_FREEZE; ktime = alarm_get_elapsed_realtime(); cur_time = ktime_to_timespec(ktime); if (chg->discharging_time && cur_time.tv_sec > chg->discharging_time) { chg->set_charge_timeout = true; chg->bat_info.dis_reason |= DISCONNECT_OVER_TIME; chg->set_batt_full = true; } bat_dbg("bat(%d,%d) tmp(%d,%d) full(%d,%d) cable(%d) chg(%d) dis(%X)\n", chg->bat_info.batt_soc, chg->bat_info.batt_vcell/1000, chg->bat_info.batt_temp, chg->bat_info.batt_temp_adc, chg->set_batt_full, chg->bat_info.batt_is_full, chg->cable_status, chg->bat_info.charging_status, chg->bat_info.dis_reason); }
void hna_local_add(struct net_device *soft_iface, uint8_t *addr) { struct bat_priv *bat_priv = netdev_priv(soft_iface); struct hna_local_entry *hna_local_entry; struct hna_global_entry *hna_global_entry; struct hashtable_t *swaphash; unsigned long flags; int required_bytes; spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); hna_local_entry = ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, addr)); spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); if (hna_local_entry) { hna_local_entry->last_seen = jiffies; return; } /* only announce as many hosts as possible in the batman-packet and space in batman_packet->num_hna That also should give a limit to MAC-flooding. */ required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN; required_bytes += BAT_PACKET_LEN; if ((required_bytes > ETH_DATA_LEN) || (atomic_read(&bat_priv->aggregation_enabled) && required_bytes > MAX_AGGREGATION_BYTES) || (bat_priv->num_local_hna + 1 > 255)) { bat_dbg(DBG_ROUTES, bat_priv, "Can't add new local hna entry (%pM): " "number of local hna entries exceeds packet size\n", addr); return; } bat_dbg(DBG_ROUTES, bat_priv, "Creating new local hna entry: %pM\n", addr); hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC); if (!hna_local_entry) return; memcpy(hna_local_entry->addr, addr, ETH_ALEN); hna_local_entry->last_seen = jiffies; /* the batman interface mac address should never be purged */ if (compare_orig(addr, soft_iface->dev_addr)) hna_local_entry->never_purge = 1; else hna_local_entry->never_purge = 0; spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); hash_add(bat_priv->hna_local_hash, hna_local_entry); bat_priv->num_local_hna++; atomic_set(&bat_priv->hna_local_changed, 1); if (bat_priv->hna_local_hash->elements * 4 > bat_priv->hna_local_hash->size) { swaphash = hash_resize(bat_priv->hna_local_hash, bat_priv->hna_local_hash->size * 2); if (!swaphash) pr_err("Couldn't resize local hna hash table\n"); else bat_priv->hna_local_hash = swaphash; } spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); /* remove address from global hash if present */ spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); hna_global_entry = ((struct hna_global_entry *) hash_find(bat_priv->hna_global_hash, addr)); if (hna_global_entry) _hna_global_del_orig(bat_priv, hna_global_entry, "local hna received"); spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); }
void hna_global_add_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, unsigned char *hna_buff, int hna_buff_len) { struct hna_global_entry *hna_global_entry; struct hna_local_entry *hna_local_entry; struct hashtable_t *swaphash; int hna_buff_count = 0; unsigned long flags; unsigned char *hna_ptr; while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_global_entry = (struct hna_global_entry *) hash_find(bat_priv->hna_global_hash, hna_ptr); if (!hna_global_entry) { spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); hna_global_entry = kmalloc(sizeof(struct hna_global_entry), GFP_ATOMIC); if (!hna_global_entry) break; memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN); bat_dbg(DBG_ROUTES, bat_priv, "Creating new global hna entry: " "%pM (via %pM)\n", hna_global_entry->addr, orig_node->orig); spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); hash_add(bat_priv->hna_global_hash, hna_global_entry); } hna_global_entry->orig_node = orig_node; spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); /* remove address from local hash if present */ spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags); hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); hna_local_entry = (struct hna_local_entry *) hash_find(bat_priv->hna_local_hash, hna_ptr); if (hna_local_entry) hna_local_del(bat_priv, hna_local_entry, "global hna received"); spin_unlock_irqrestore(&bat_priv->hna_lhash_lock, flags); hna_buff_count++; } /* initialize, and overwrite if malloc succeeds */ orig_node->hna_buff = NULL; orig_node->hna_buff_len = 0; if (hna_buff_len > 0) { orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC); if (orig_node->hna_buff) { memcpy(orig_node->hna_buff, hna_buff, hna_buff_len); orig_node->hna_buff_len = hna_buff_len; } } spin_lock_irqsave(&bat_priv->hna_ghash_lock, flags); if (bat_priv->hna_global_hash->elements * 4 > bat_priv->hna_global_hash->size) { swaphash = hash_resize(bat_priv->hna_global_hash, bat_priv->hna_global_hash->size * 2); if (!swaphash) pr_err("Couldn't resize global hna hash table\n"); else bat_priv->hna_global_hash = swaphash; } spin_unlock_irqrestore(&bat_priv->hna_ghash_lock, flags); }
void hna_local_add(uint8_t *addr) { struct hna_local_entry *hna_local_entry; struct hna_global_entry *hna_global_entry; struct hashtable_t *swaphash; unsigned long flags; spin_lock_irqsave(&hna_local_hash_lock, flags); hna_local_entry = ((struct hna_local_entry *)hash_find(hna_local_hash, addr)); spin_unlock_irqrestore(&hna_local_hash_lock, flags); if (hna_local_entry != NULL) { hna_local_entry->last_seen = jiffies; return; } /* only announce as many hosts as possible in the batman-packet and space in batman_packet->num_hna That also should give a limit to MAC-flooding. */ if ((num_hna + 1 > (ETH_DATA_LEN - BAT_PACKET_LEN) / ETH_ALEN) || (num_hna + 1 > 255)) { bat_dbg(DBG_ROUTES, "Can't add new local hna entry (%pM): " "number of local hna entries exceeds packet size\n", addr); return; } bat_dbg(DBG_ROUTES, "Creating new local hna entry: %pM\n", addr); hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC); if (!hna_local_entry) return; memcpy(hna_local_entry->addr, addr, ETH_ALEN); hna_local_entry->last_seen = jiffies; /* the batman interface mac address should never be purged */ if (compare_orig(addr, soft_device->dev_addr)) hna_local_entry->never_purge = 1; else hna_local_entry->never_purge = 0; spin_lock_irqsave(&hna_local_hash_lock, flags); hash_add(hna_local_hash, hna_local_entry); num_hna++; atomic_set(&hna_local_changed, 1); if (hna_local_hash->elements * 4 > hna_local_hash->size) { swaphash = hash_resize(hna_local_hash, hna_local_hash->size * 2); if (swaphash == NULL) printk(KERN_ERR "batman-adv:" "Couldn't resize local hna hash table\n"); else hna_local_hash = swaphash; } spin_unlock_irqrestore(&hna_local_hash_lock, flags); /* remove address from global hash if present */ spin_lock_irqsave(&hna_global_hash_lock, flags); hna_global_entry = ((struct hna_global_entry *)hash_find(hna_global_hash, addr)); if (hna_global_entry != NULL) _hna_global_del_orig(hna_global_entry, "local hna received"); spin_unlock_irqrestore(&hna_global_hash_lock, flags); }
/* * vt1603_bat_work - vt1603 battery workqueue routine, switch * vt1603 working mode to battery detecting * @work: battery work struct */ static void vt1603_bat_work(struct work_struct *work) { u8 tmp = 0; u16 val = 0; int tout = 0; unsigned long now = 0; struct vt1603_bat_drvdata *bat_drv; bat_dbg("Enter\n"); bat_drv = container_of(work, struct vt1603_bat_drvdata, work); if (unlikely(vt1603_get_pen_state(bat_drv) == TS_PENDOWN_STATE)) { bat_dbg("vt1603 pendown when battery detect\n"); tout = 1000; goto out; } /* enable sar-adc power and clock */ vt1603_bat_power_up(bat_drv); /* enable pen down/up to avoid miss irq */ vt1603_bat_pen_manual(bat_drv); /* switch vt1603 to battery detect mode */ vt1603_switch_to_bat_mode(bat_drv); /* do conversion use battery manual mode */ vt1603_setbits(bat_drv, VT1603_INTS_REG, BIT0); if (vt1603_get_reg8(bat_drv, VT1603_AMCR_REG) != 0x01) { tout = 1000; bat_dbg("vt1603 battery channel changed already?\n"); goto out; } vt1603_set_reg8(bat_drv, VT1603_CR_REG, BIT4); now = jiffies; while (time_before(jiffies, now + msecs_to_jiffies(POLL_TOUT))) { tmp = vt1603_get_reg8(bat_drv, VT1603_INTS_REG); if (tmp & BIT0) { val = vt1603_get_bat_convert_data(bat_drv); bat_dbg("vt1603 battery value is %d\n", val); if (vt1603_get_reg8(bat_drv, VT1603_AMCR_REG) != 0x01) { tout = 1000; bat_dbg("vt1603 battery channel changed already?\n"); goto out; } if (val < 2048) { tout = 1000; printk(KERN_ERR "vt1603 battery conversion failed?!\n"); goto out; } bat_drv->bat_val = val; bat_drv->detect_time++; bat_drv->time_stamp = jiffies; tout = bat_drv->interval; goto out; } } bat_dbg("vt1603 battery detect failed, conversion timeout!\n"); tout = 1000; goto out; out: vt1603_clrbits(bat_drv, VT1603_INTCR_REG, BIT7); vt1603_setbits(bat_drv, VT1603_INTS_REG, BIT0 | BIT3); vt1603_set_reg8(bat_drv, VT1603_CR_REG, BIT1); mod_timer(&bat_drv->bat_tmr, jiffies + msecs_to_jiffies(tout)); bat_dbg("Exit\n\n\n"); return ; }