Пример #1
0
static ssize_t store_orig_interval(struct kobject *kobj, struct attribute *attr,
				  char *buff, size_t count)
{
	struct device *dev = to_dev(kobj->parent);
	struct net_device *net_dev = to_net_dev(dev);
	struct bat_priv *bat_priv = netdev_priv(net_dev);
	unsigned long orig_interval_tmp;
	int ret;

	ret = strict_strtoul(buff, 10, &orig_interval_tmp);
	if (ret) {
		bat_info(net_dev, "Invalid parameter for 'orig_interval' "
			 "setting received: %s\n", buff);
		return -EINVAL;
	}

	if (orig_interval_tmp < JITTER * 2) {
		bat_info(net_dev, "New originator interval too small: %li "
			 "(min: %i)\n", orig_interval_tmp, JITTER * 2);
		return -EINVAL;
	}

	if (atomic_read(&bat_priv->orig_interval) == orig_interval_tmp)
		return count;

	bat_info(net_dev, "Changing originator interval from: %i to: %li\n",
		 atomic_read(&bat_priv->orig_interval),
		 orig_interval_tmp);

	atomic_set(&bat_priv->orig_interval, orig_interval_tmp);
	return count;
}
Пример #2
0
static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr,
			      char *buff, size_t count)
{
	struct device *dev = to_dev(kobj->parent);
	struct net_device *net_dev = to_net_dev(dev);
	struct bat_priv *bat_priv = netdev_priv(net_dev);
	unsigned long log_level_tmp;
	int ret;

	ret = strict_strtoul(buff, 10, &log_level_tmp);
	if (ret) {
		bat_info(net_dev, "Invalid parameter for 'log_level' "
			 "setting received: %s\n", buff);
		return -EINVAL;
	}

	if (log_level_tmp > 3) {
		bat_info(net_dev, "New log level too big: %li "
			 "(max: %i)\n", log_level_tmp, 3);
		return -EINVAL;
	}

	if (atomic_read(&bat_priv->log_level) == log_level_tmp)
		return count;

	bat_info(net_dev, "Changing log level from: %i to: %li\n",
		 atomic_read(&bat_priv->log_level),
		 log_level_tmp);

	atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp);
	return count;
}
Пример #3
0
static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr,
                             char *buff, size_t count)
{
    struct net_device *net_dev = kobj_to_netdev(kobj);
    struct bat_priv *bat_priv = netdev_priv(net_dev);
    char *curr_gw_mode_str;
    int gw_mode_tmp = -1;

    if (buff[count - 1] == '\n')
        buff[count - 1] = '\0';

    if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0)
        gw_mode_tmp = GW_MODE_OFF;

    if (strncmp(buff, GW_MODE_CLIENT_NAME,
                strlen(GW_MODE_CLIENT_NAME)) == 0)
        gw_mode_tmp = GW_MODE_CLIENT;

    if (strncmp(buff, GW_MODE_SERVER_NAME,
                strlen(GW_MODE_SERVER_NAME)) == 0)
        gw_mode_tmp = GW_MODE_SERVER;

    if (gw_mode_tmp < 0) {
        bat_info(net_dev,
                 "Invalid parameter for 'gw mode' setting received: "
                 "%s\n", buff);
        return -EINVAL;
    }

    if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp)
        return count;

    switch (atomic_read(&bat_priv->gw_mode)) {
    case GW_MODE_CLIENT:
        curr_gw_mode_str = GW_MODE_CLIENT_NAME;
        break;
    case GW_MODE_SERVER:
        curr_gw_mode_str = GW_MODE_SERVER_NAME;
        break;
    default:
        curr_gw_mode_str = GW_MODE_OFF_NAME;
        break;
    }

    bat_info(net_dev, "Changing gw mode from: %s to: %s\n",
             curr_gw_mode_str, buff);

    gw_deselect(bat_priv);
    atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp);
    return count;
}
Пример #4
0
static void max8998_set_cable(struct max8998_charger_callbacks *ptr,
				enum cable_type_t status)
{
	struct chg_data *chg = container_of(ptr, struct chg_data, callbacks);
	chg->cable_status = status;
	chg->lowbat_warning = false;
	if (chg->esafe == MAX8998_ESAFE_ALLOFF)
		chg->esafe = MAX8998_USB_VBUS_AP_ON;
	bat_info("%s : cable_status = %d\n", __func__, status);

#ifdef __VZW_AUTH_CHECK__
	/* debug info */
	if ((status != CABLE_TYPE_NONE)
		&& (chg->bat_info.batt_health == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE)) {
		int i;
		printk("/BATT_ID/ rom code =");
		for (i = 0; i < 8; i++)
			printk(" %d", vzw_rcode[i]);
		printk("\n");
		printk("/BATT_ID/ rom code crc = %d\n", vzw_crc1);
		printk("/BATT_ID/ crc = %d", vzw_crc2);
	}
#endif

	if (lpm_charging_mode &&
	    (max8998_check_vdcin(chg) != 1) &&
	    pm_power_off)
		pm_power_off();

	power_supply_changed(&chg->psy_ac);
	power_supply_changed(&chg->psy_usb);
	wake_lock(&chg->work_wake_lock);
	queue_work(chg->monitor_wqueue, &chg->bat_work);
}
Пример #5
0
static void max8998_lowbat_warning(struct chg_data *chg)
{
	bat_info("%s\n", __func__);
	if (chg->bat_info.decimal_point_level == 0)
                return ;        // already requested...

	wake_lock_timeout(&chg->lowbat_wake_lock, 5 * HZ);
	chg->lowbat_warning = 1;
}
Пример #6
0
static void max8998_lowbat_critical(struct chg_data *chg)
{
	if (chg->bat_info.decimal_point_level == 0)
                return ;        // already requested...
	
	bat_info("%s\n", __func__);
	wake_lock_timeout(&chg->lowbat_wake_lock, 30 * HZ);
	chg->bat_info.batt_soc = 0;
	chg->bat_info.decimal_point_level = 0;
}
Пример #7
0
static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr,
			      char *buff, size_t count)
{
	struct device *dev = to_dev(kobj->parent);
	struct net_device *net_dev = to_net_dev(dev);
	struct bat_priv *bat_priv = netdev_priv(net_dev);
	unsigned long val;
	int ret, vis_mode_tmp = -1;

	ret = strict_strtoul(buff, 10, &val);

	if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) ||
	    (strncmp(buff, "client", 6) == 0) ||
	    (strncmp(buff, "off", 3) == 0))
		vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE;

	if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) ||
	    (strncmp(buff, "server", 6) == 0))
		vis_mode_tmp = VIS_TYPE_SERVER_SYNC;

	if (vis_mode_tmp < 0) {
		if (buff[count - 1] == '\n')
			buff[count - 1] = '\0';

		bat_info(net_dev,
			 "Invalid parameter for 'vis mode' setting received: "
			 "%s\n", buff);
		return -EINVAL;
	}

	if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
		return count;

	bat_info(net_dev, "Changing vis mode from: %s to: %s\n",
		 atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ?
		 "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ?
		 "client" : "server");

	atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp);
	return count;
}
Пример #8
0
static void check_lpm_charging_mode(struct chg_data *chg)
{
	if (readl(S5P_INFORM5)) {
		lpm_charging_mode = 1;
		if (max8998_check_vdcin(chg) != 1)
			if (pm_power_off)
				pm_power_off();
	} else
		lpm_charging_mode = 0;

	bat_info("%s : lpm_charging_mode(%d)\n", __func__, lpm_charging_mode);
}
Пример #9
0
static bool max8998_set_esafe(struct max8998_charger_callbacks *ptr, u8 esafe)
{
	struct chg_data *chg = container_of(ptr, struct chg_data, callbacks);
	if (esafe > 3) {
		pr_err("%s : esafe value must not be bigger than 3\n", __func__);
		return 0;
	}
	chg->esafe = esafe;
	max8998_update_reg(chg->iodev->i2c, MAX8998_REG_CHGR2,
		(esafe << MAX8998_SHIFT_ESAFEOUT), MAX8998_MASK_ESAFEOUT);
	bat_info("%s : esafe = %d\n", __func__, esafe);
	return 1;
}
Пример #10
0
static ssize_t store_aggr_ogms(struct kobject *kobj, struct attribute *attr,
			      char *buff, size_t count)
{
	struct device *dev = to_dev(kobj->parent);
	struct net_device *net_dev = to_net_dev(dev);
	struct bat_priv *bat_priv = netdev_priv(net_dev);
	int aggr_tmp = -1;

	if (((count == 2) && (buff[0] == '1')) ||
	    (strncmp(buff, "enable", 6) == 0))
		aggr_tmp = 1;

	if (((count == 2) && (buff[0] == '0')) ||
	    (strncmp(buff, "disable", 7) == 0))
		aggr_tmp = 0;

	if (aggr_tmp < 0) {
		if (buff[count - 1] == '\n')
			buff[count - 1] = '\0';

		bat_info(net_dev,
			 "Invalid parameter for 'aggregate OGM' setting"
			 "received: %s\n", buff);
		return -EINVAL;
	}

	if (atomic_read(&bat_priv->aggregation_enabled) == aggr_tmp)
		return count;

	bat_info(net_dev, "Changing aggregation from: %s to: %s\n",
		 atomic_read(&bat_priv->aggregation_enabled) == 1 ?
		 "enabled" : "disabled", aggr_tmp == 1 ? "enabled" :
		 "disabled");

	atomic_set(&bat_priv->aggregation_enabled, (unsigned)aggr_tmp);
	return count;
}
Пример #11
0
static irqreturn_t max8998_int_work_func(int irq, void *max8998_chg)
{
	int ret;
	u8 data[MAX8998_NUM_IRQ_REGS];

	struct chg_data *chg = max8998_chg;
        struct i2c_client *i2c = chg->iodev->i2c;

	ret = max8998_bulk_read(i2c, MAX8998_REG_IRQ1, MAX8998_NUM_IRQ_REGS, data);
	if (ret < 0)
		goto err;

	wake_lock(&chg->work_wake_lock);

#ifndef TOPOFF_CURRENT_CHECK
	if (data[MAX8998_REG_IRQ3] & MAX8998_IRQ_TOPOFFR_MASK) {
		bat_info("%s : topoff intr(%d)\n", __func__, chg->set_batt_full);
		if (chg->set_batt_full)
			chg->bat_info.batt_is_full = true;
		else {
			chg->set_batt_full = true;

			if (chg->cable_status == CABLE_TYPE_AC)
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
			else if (chg->cable_status == CABLE_TYPE_USB)
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
		}
	}
#endif

	if (data[MAX8998_REG_IRQ4] & MAX8998_IRQ_LOBAT1_MASK)
		max8998_lowbat_warning(chg);

	if (data[MAX8998_REG_IRQ4] & MAX8998_IRQ_LOBAT2_MASK)
		max8998_lowbat_critical(chg);

	queue_work(chg->monitor_wqueue, &chg->bat_work);

	return IRQ_HANDLED;
err:
	pr_err("%s : pmic read error\n", __func__);
	return IRQ_HANDLED;
}
Пример #12
0
static int store_bool_attr(char *buff, size_t count,
                           struct net_device *net_dev,
                           char *attr_name, atomic_t *attr)
{
    int enabled = -1;

    if (buff[count - 1] == '\n')
        buff[count - 1] = '\0';

    if ((strncmp(buff, "1", 2) == 0) ||
            (strncmp(buff, "enable", 7) == 0) ||
            (strncmp(buff, "enabled", 8) == 0))
        enabled = 1;

    if ((strncmp(buff, "0", 2) == 0) ||
            (strncmp(buff, "disable", 8) == 0) ||
            (strncmp(buff, "disabled", 9) == 0))
        enabled = 0;

    if (enabled < 0) {
        bat_info(net_dev,
                 "%s: Invalid parameter received: %s\n",
                 attr_name, buff);
        return -EINVAL;
    }

    if (atomic_read(attr) == enabled)
        return count;

    bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name,
             atomic_read(attr) == 1 ? "enabled" : "disabled",
             enabled == 1 ? "enabled" : "disabled");

    atomic_set(attr, (unsigned)enabled);
    return count;
}
Пример #13
0
static int store_uint_attr(char *buff, size_t count,
                           struct net_device *net_dev, char *attr_name,
                           unsigned int min, unsigned int max, atomic_t *attr)
{
    unsigned long uint_val;
    int ret;

    ret = strict_strtoul(buff, 10, &uint_val);
    if (ret) {
        bat_info(net_dev,
                 "%s: Invalid parameter received: %s\n",
                 attr_name, buff);
        return -EINVAL;
    }

    if (uint_val < min) {
        bat_info(net_dev, "%s: Value is too small: %lu min: %u\n",
                 attr_name, uint_val, min);
        return -EINVAL;
    }

    if (uint_val > max) {
        bat_info(net_dev, "%s: Value is too big: %lu max: %u\n",
                 attr_name, uint_val, max);
        return -EINVAL;
    }

    if (atomic_read(attr) == uint_val)
        return count;

    bat_info(net_dev, "%s: Changing from: %i to: %lu\n",
             attr_name, atomic_read(attr), uint_val);

    atomic_set(attr, uint_val);
    return count;
}
Пример #14
0
ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count)
{
	struct bat_priv *bat_priv = netdev_priv(net_dev);
	long gw_bandwidth_tmp = 0, up = 0, down = 0;
	bool ret;

	ret = parse_gw_bandwidth(net_dev, buff, &up, &down);
	if (!ret)
		goto end;

	if ((!down) || (down < 256))
		down = 2000;

	if (!up)
		up = down / 5;

	kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp);

	/**
	 * the gw bandwidth we guessed above might not match the given
	 * speeds, hence we need to calculate it back to show the number
	 * that is going to be propagated
	 **/
	gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp,
			     (int *)&down, (int *)&up);

	gw_deselect(bat_priv);
	bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' "
		 "(propagating: %ld%s/%ld%s)\n",
		 atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp,
		 (down > 2048 ? down / 1024 : down),
		 (down > 2048 ? "MBit" : "KBit"),
		 (up > 2048 ? up / 1024 : up),
		 (up > 2048 ? "MBit" : "KBit"));

	atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp);

end:
	return count;
}
Пример #15
0
static irqreturn_t max8998_int_work_func(int irq, void *max8998_chg)
{
	int ret;
	u8 data[MAX8998_NUM_IRQ_REGS];

	struct chg_data *chg = max8998_chg;
        struct i2c_client *i2c = chg->iodev->i2c;

	ret = max8998_bulk_read(i2c, MAX8998_REG_IRQ1, MAX8998_NUM_IRQ_REGS, data);
	if (ret < 0)
		goto err;

	wake_lock(&chg->work_wake_lock);

	if (data[MAX8998_REG_IRQ3] & MAX8998_IRQ_TOPOFFR_MASK) {
		bat_info("%s : topoff intr(%d)\n", __func__, chg->set_batt_full);
		if (chg->set_batt_full)
			chg->bat_info.batt_is_full = true;
		else {
			chg->set_batt_full = true;

			if (chg->cable_status == CABLE_TYPE_AC)
#if defined(CONFIG_ARIES_NTT)
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_700	<< MAX8998_SHIFT_ICHG));
#else
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
#endif
			else if (chg->cable_status == CABLE_TYPE_USB)
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_25	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
		}
Пример #16
0
static void max8998_set_cable(struct max8998_charger_callbacks *ptr,
				enum cable_type_t status)
{
	struct chg_data *chg = container_of(ptr, struct chg_data, callbacks);

	chg->cable_status = status;
	chg->lowbat_warning = false;
	if (chg->esafe == MAX8998_ESAFE_ALLOFF)
		chg->esafe = MAX8998_USB_VBUS_AP_ON;

	bat_info("%s : cable_status(%d) esafe(%d)\n", __func__, status, chg->esafe);

	if (lpm_charging_mode &&
	    (max8998_check_vdcin(chg) != 1) &&
	    pm_power_off)
		pm_power_off();

	power_supply_changed(&chg->psy_ac);
	power_supply_changed(&chg->psy_usb);
	wake_lock(&chg->work_wake_lock);
	queue_work(chg->monitor_wqueue, &chg->bat_work);
}
Пример #17
0
static void s3c_bat_top_off(struct chg_data *chg)
{
	struct i2c_client *i2c = chg->iodev->i2c;

	bat_info("%s : topoff(%d)\n", __func__, chg->set_batt_full);
	if (chg->set_batt_full)
		chg->bat_info.batt_is_full = true;
	else {
		chg->set_batt_full = true;
	
		if (chg->cable_status == CABLE_TYPE_AC)
			max8998_write_reg(i2c, MAX8998_REG_CHGR1,
				(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
				(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
				(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
		else if (chg->cable_status == CABLE_TYPE_USB)
			max8998_write_reg(i2c, MAX8998_REG_CHGR1,
				(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
				(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
				(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
	}
}
Пример #18
0
static int max8998_charging_control(struct chg_data *chg)
{
        struct i2c_client *i2c = chg->iodev->i2c;
	static int prev_charging = -1, prev_cable = -1;
	int ret;

	if ((prev_charging == chg->charging) && (prev_cable == chg->cable_status))
		return 0;

	bat_info("%s : chg(%d) cable(%d) dis(%X) esafe(%d) bat(%d,%d,%d)\n", __func__,
		chg->charging, chg->cable_status, chg->bat_info.dis_reason, chg->esafe,
		chg->bat_info.batt_soc, chg->set_batt_full, chg->bat_info.batt_is_full);

	if (!chg->charging) {
		/* disable charging */
		ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
			(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
			(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
			(MAX8998_CHGEN_DISABLE	<< MAX8998_SHIFT_CHGEN));
		if (ret < 0)
			goto err;
	} else {
		/* enable charging */
		if (chg->cable_status == CABLE_TYPE_AC) {
			/* ac */
#if defined(CONFIG_ARIES_NTT)
			if (chg->set_batt_full)
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_700	<< MAX8998_SHIFT_ICHG));
			else
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_15	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_700	<< MAX8998_SHIFT_ICHG));
#else
			if (chg->set_batt_full)
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
			else
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_20	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
#endif
			if (ret < 0)
				goto err;

			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
				(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
				(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
				(MAX8998_CHGEN_ENABLE	<< MAX8998_SHIFT_CHGEN));
			if (ret < 0)
				goto err;
		} else {
			/* usb */
			if (chg->set_batt_full)
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_25	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
			else
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_30	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
			if (ret < 0)
				goto err;

			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
				(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
				(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
				(MAX8998_CHGEN_ENABLE	<< MAX8998_SHIFT_CHGEN));
			if (ret < 0)
				goto err;
		}
	}

	prev_charging = chg->charging;
	prev_cable = chg->cable_status;

	return 0;
err:
	pr_err("max8998_read_reg error\n");
	return ret;
}
Пример #19
0
static void max8998_lowbat_critical(struct chg_data *chg)
{
	bat_info("%s\n", __func__);
	wake_lock_timeout(&chg->lowbat_wake_lock, 30 * HZ);
	chg->bat_info.batt_soc = 0;
}
Пример #20
0
static void max8998_lowbat_warning(struct chg_data *chg)
{
	bat_info("%s\n", __func__);
	wake_lock_timeout(&chg->lowbat_wake_lock, 5 * HZ);
	chg->lowbat_warning = 1;
}
Пример #21
0
static __devinit int max8998_charger_probe(struct platform_device *pdev)
{
	struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
	struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
	struct chg_data *chg;
        struct i2c_client *i2c = iodev->i2c;
	int ret = 0;

	bat_info("%s : MAX8998 Charger Driver Loading\n", __func__);

	chg = kzalloc(sizeof(*chg), GFP_KERNEL);
	if (!chg)
		return -ENOMEM;

	chg->iodev = iodev;
	chg->pdata = pdata->charger;

	if (!chg->pdata || !chg->pdata->adc_table) {
		pr_err("%s : No platform data & adc_table supplied\n", __func__);
		ret = -EINVAL;
		goto err_bat_table;
	}

	chg->psy_bat.name = "battery";
	chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY;
	chg->psy_bat.properties = max8998_battery_props;
	chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props);
	chg->psy_bat.get_property = s3c_bat_get_property;

	chg->psy_usb.name = "usb";
	chg->psy_usb.type = POWER_SUPPLY_TYPE_USB;
	chg->psy_usb.supplied_to = supply_list;
	chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list);
	chg->psy_usb.properties = s3c_power_properties;
	chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties);
	chg->psy_usb.get_property = s3c_usb_get_property;

	chg->psy_ac.name = "ac";
	chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS;
	chg->psy_ac.supplied_to = supply_list;
	chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list);
	chg->psy_ac.properties = s3c_power_properties;
	chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties);
	chg->psy_ac.get_property = s3c_ac_get_property;

	chg->present = 1;
	chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD;
	chg->bat_info.batt_is_full = false;
	chg->set_batt_full = false;
	chg->set_charge_timeout = false;

	chg->cable_status = CABLE_TYPE_NONE;
	chg->esafe = MAX8998_USB_VBUS_AP_ON;

	mutex_init(&chg->mutex);

	platform_set_drvdata(pdev, chg);

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1,
		~(MAX8998_IRQ_DCINR_MASK | MAX8998_IRQ_DCINF_MASK));
	if (ret < 0)
		goto err_kfree;

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF);
	if (ret < 0)
		goto err_kfree;

#ifdef TOPOFF_CURRENT_CHECK
	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, 0xFF);
#else
	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_TOPOFFR_MASK);
#endif
	if (ret < 0)
		goto err_kfree;

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4,
		~(MAX8998_IRQ_LOBAT2_MASK | MAX8998_IRQ_LOBAT1_MASK));
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_ONOFF3,
		(1 << MAX8998_SHIFT_ENBATTMON), MAX8998_MASK_ENBATTMON);
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_LBCNFG1, 0x7, 0x37); //3.57V
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_LBCNFG2, 0x5, 0x37); //3.4V
	if (ret < 0)
		goto err_kfree;

	max8998_lowbat_config(chg, 0);

	wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
	wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND, "max8998-charger");
	wake_lock_init(&chg->lowbat_wake_lock, WAKE_LOCK_SUSPEND, "max8998-lowbat");

	INIT_WORK(&chg->bat_work, s3c_bat_work);
	setup_timer(&chg->bat_work_timer, s3c_bat_work_timer_func, (unsigned long)chg);

	chg->monitor_wqueue = create_freezeable_workqueue(dev_name(&pdev->dev));
	if (!chg->monitor_wqueue) {
		pr_err("%s : Failed to create freezeable workqueue\n", __func__);
		ret = -ENOMEM;
		goto err_wake_lock;
	}

	check_lpm_charging_mode(chg);

	/* init power supplier framework */
	ret = power_supply_register(&pdev->dev, &chg->psy_bat);
	if (ret) {
		pr_err("%s : Failed to register power supply psy_bat\n", __func__);
		goto err_wqueue;
	}

	ret = power_supply_register(&pdev->dev, &chg->psy_usb);
	if (ret) {
		pr_err("%s : Failed to register power supply psy_usb\n", __func__);
		goto err_supply_unreg_bat;
	}

	ret = power_supply_register(&pdev->dev, &chg->psy_ac);
	if (ret) {
		pr_err("%s : Failed to register power supply psy_ac\n", __func__);
		goto err_supply_unreg_usb;
	}

	ret = request_threaded_irq(iodev->i2c->irq, NULL, max8998_int_work_func,
				   IRQF_TRIGGER_FALLING, "max8998-charger", chg);
	if (ret) {
		pr_err("%s : Failed to request pmic irq\n", __func__);
		goto err_supply_unreg_ac;
	}

	ret = enable_irq_wake(iodev->i2c->irq);
	if (ret) {
		pr_err("%s : Failed to enable pmic irq wake\n", __func__);
		goto err_irq;
	}

	ret = s3c_bat_create_attrs(chg->psy_bat.dev);
	if (ret) {
		pr_err("%s : Failed to create_attrs\n", __func__);
		goto err_irq;
	}

	chg->callbacks.set_cable = max8998_set_cable;
	chg->callbacks.set_esafe = max8998_set_esafe;
	chg->callbacks.get_vdcin = max8998_get_vdcin;
	if (chg->pdata->register_callbacks)
		chg->pdata->register_callbacks(&chg->callbacks);

	wake_lock(&chg->work_wake_lock);
	queue_work(chg->monitor_wqueue, &chg->bat_work);

	return 0;

err_irq:
	free_irq(iodev->i2c->irq, NULL);
err_supply_unreg_ac:
	power_supply_unregister(&chg->psy_ac);
err_supply_unreg_usb:
	power_supply_unregister(&chg->psy_usb);
err_supply_unreg_bat:
	power_supply_unregister(&chg->psy_bat);
err_wqueue:
	destroy_workqueue(chg->monitor_wqueue);
	cancel_work_sync(&chg->bat_work);
err_wake_lock:
	wake_lock_destroy(&chg->work_wake_lock);
	wake_lock_destroy(&chg->vbus_wake_lock);
	wake_lock_destroy(&chg->lowbat_wake_lock);
err_kfree:
	mutex_destroy(&chg->mutex);
err_bat_table:
	kfree(chg);
	return ret;
}
Пример #22
0
static int max8998_charging_control(struct chg_data *chg)
{
        struct i2c_client *i2c = chg->iodev->i2c;
	static int prev_charging = -1, prev_cable = -1;
	int ret;
	int topoff;

	if ((prev_charging == chg->charging) && (prev_cable == chg->cable_status))
		return 0;

	bat_info("%s : chg(%d) cable(%d) dis(%X) bat(%d,%d,%d), esafe(%d)\n", __func__,
		chg->charging, chg->cable_status, chg->bat_info.dis_reason,
		chg->bat_info.batt_soc, chg->set_batt_full, chg->bat_info.batt_is_full,
		chg->esafe);

	if (!chg->charging) {
		/* disable charging */
		s3c_clean_chg_current(chg);

		ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
			(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
			(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
			(MAX8998_CHGEN_DISABLE	<< MAX8998_SHIFT_CHGEN));
		if (ret < 0)
			goto err;
	} else {
		/* enable charging */
		if (chg->cable_status == CABLE_TYPE_AC) {
			/* termination current adc NOT used to detect full-charging */
			if (chg->pdata->termination_curr_adc > 0)
				topoff = MAX8998_TOPOFF_10;
			else
				topoff = MAX8998_TOPOFF_30;

			/* ac */
			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
				(topoff	<< MAX8998_SHIFT_TOPOFF) |
				(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
				(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
			if (ret < 0)
				goto err;

			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
				(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
				(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
				(MAX8998_CHGEN_ENABLE	<< MAX8998_SHIFT_CHGEN));
			if (ret < 0)
				goto err;
		} else {
			if (chg->pdata->termination_curr_adc > 0)
				topoff = MAX8998_TOPOFF_10;
			else
				topoff = MAX8998_TOPOFF_35;

			/* usb */
			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
				(topoff	<< MAX8998_SHIFT_TOPOFF) |
				(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
				(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
			if (ret < 0)
				goto err;

			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
				(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
				(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
				(MAX8998_CHGEN_ENABLE	<< MAX8998_SHIFT_CHGEN));
			if (ret < 0)
				goto err;
		}
	}

	prev_charging = chg->charging;
	prev_cable = chg->cable_status;

	return 0;
err:
	pr_err("max8998_read_reg error\n");
	return ret;
}
Пример #23
0
static void max8998_set_jig(struct max8998_charger_callbacks *ptr, bool attached)
{
	struct chg_data *chg = container_of(ptr, struct chg_data, callbacks);
	chg->jig_status = attached;
	bat_info("%s %d\n", __func__, (int)attached);
}