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;
}
Exemple #10
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;
}
Exemple #11
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;
}
Exemple #12
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);
}
Exemple #14
0
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);
}
Exemple #16
0
/*
 * 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;
}
Exemple #17
0
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;
}
Exemple #18
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;
}
Exemple #19
0
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);
}
Exemple #23
0
/*
 * 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 ;
}