static u8 SM5414_set_topoff_current_limit_data(
		struct i2c_client *client, int topoff_current)
{
	u8 data;
	u8 topoff_reg;

	SM5414_i2c_read(client, SM5414_CHGCTRL4, &data);

	data &= TOPOFF_MASK;

	if(topoff_current < 100)
		topoff_current = 100;
	else if (topoff_current > 650)
		topoff_current = 650;

	topoff_reg = (topoff_current - 100) / 50;
	data = data | (topoff_reg<<3);

	SM5414_i2c_write(client, SM5414_CHGCTRL4, &data);

	SM5414_i2c_read(client, SM5414_CHGCTRL4, &data);
	dev_dbg(&client->dev,
		"%s : SM5414_CHGCTRL4 (Top-off limit) : 0x%02x\n",
		__func__, data);

	return data;
}
static int SM5414_get_charging_status(struct i2c_client *client)
{
	int status = POWER_SUPPLY_STATUS_UNKNOWN;
	struct sec_charger_info *charger = i2c_get_clientdata(client);
	int nCHG;
	u8 int2, chg_en;
	union power_supply_propval value;

	SM5414_i2c_read(client, SM5414_INT2, &int2);
	SM5414_i2c_read(client, SM5414_CTRL, &chg_en);

	if((int2 & SM5414_INT2_DONE) || (int2 & SM5414_INT2_TOPOFF)) {
		psy_do_property(charger->pdata->fuelgauge_name, get,
				POWER_SUPPLY_PROP_CAPACITY, value);
		if ((value.intval > 96) &&
			(charger->cable_type != POWER_SUPPLY_TYPE_BATTERY)) {
				status = POWER_SUPPLY_STATUS_FULL;
				charger->is_fullcharged = true;
				dev_info(&client->dev,
					"%s : Power Supply Full\n", __func__);
		}
	} else if (chg_en & CHARGE_EN) {
		nCHG = gpio_get_value(charger->pdata->chg_gpio_en);
		if ((nCHG) || (charger_health != POWER_SUPPLY_HEALTH_GOOD))
			status = POWER_SUPPLY_STATUS_DISCHARGING;
		else
			status = POWER_SUPPLY_STATUS_CHARGING;
	} else {
		status = POWER_SUPPLY_STATUS_DISCHARGING;
	}

	return (int)status;
}
bool SM5414_hal_chg_init(struct i2c_client *client)
{
	u8 reg_data;
	u8 int1 = 0;
	struct sec_charger_info *charger = i2c_get_clientdata(client);

	dev_info(&client->dev, "%s: SM5414 Charger init (Starting)!! \n", __func__);
	charger->is_fullcharged = false;

	SM5414_i2c_read(client, SM5414_INT1, &int1);
	dev_info(&client->dev,
		"%s : SM5414_INT1 : 0x%02x\n", __func__, int1);

	reg_data = 0x1F;
	SM5414_i2c_write(client, SM5414_INTMASK1, &reg_data);

	reg_data = 0xFC;
	SM5414_i2c_write(client, SM5414_INTMASK2, &reg_data);

	SM5414_i2c_read(client, SM5414_CHGCTRL1, &reg_data);
	reg_data &= ~SM5414_CHGCTRL1_AUTOSTOP;
	SM5414_i2c_write(client, SM5414_CHGCTRL1, &reg_data);

	(void) debugfs_create_file("SM5414_regs",
		S_IRUGO, NULL, (void *)charger, &SM5414_debugfs_fops);

	return true;
}
static u8 SM5414_set_toggle_charger(struct i2c_client *client, int enable)
{
	u8 chg_en=0;
	u8 data=0;

	SM5414_i2c_read(client, SM5414_CTRL, &chg_en);
	if (enable)
		chg_en |= CHARGE_EN;
	else
		chg_en &= ~CHARGE_EN;

	SM5414_i2c_write(client, SM5414_CTRL, &chg_en);

	dev_info(&client->dev, "%s: SM5414 Charger toggled!! \n", __func__);

	SM5414_i2c_read(client, SM5414_CTRL, &chg_en);
	dev_info(&client->dev,
		"%s : chg_en value(07h register): 0x%02x\n", __func__, chg_en);

	SM5414_i2c_read(client, SM5414_CHGCTRL2, &data);
	dev_info(&client->dev,
		"%s : SM5414_CHGCTRL2 value: 0x%02x", __func__, data);

	return chg_en;
}
static u8 SM5414_set_input_current_limit_data(
		struct i2c_client *client, int input_current)
{
	u8 set_reg, curr_reg = 0;
	u8 chg_en;

	if(input_current < 100)
		input_current = 100;
	else if (input_current >= 2050)
		input_current = 2050;

	set_reg = (input_current - 100) / 50;

	curr_reg = ((input_current % 100) >= 50) ? 1 : 0;

	SM5414_i2c_read(client, SM5414_CTRL, &chg_en);

	if (chg_en & CHARGE_EN) {
		SM5414_i2c_write(client, SM5414_VBUSCTRL, &set_reg);
	} else {
		while (set_reg >= curr_reg) {
			SM5414_i2c_write(client, SM5414_VBUSCTRL, &curr_reg);
			curr_reg += 2;
			msleep(50);
		};
	}

	SM5414_i2c_read(client, SM5414_VBUSCTRL, &curr_reg);
	dev_dbg(&client->dev,
		"%s : SM5414_VBUSCTRL (Input limit) : 0x%02x\n",
		__func__, curr_reg);

	return curr_reg;
}
static u8 SM5414_set_float_voltage_data(
		struct i2c_client *client, int float_voltage)
{
	u8 data, float_reg;

	SM5414_i2c_read(client, SM5414_CHGCTRL3, &data);

	data &= BATREG_MASK;

	if (float_voltage < 4100)
		float_voltage = 4100;
	else if (float_voltage > 4475)
		float_voltage = 4475;

	float_reg = (float_voltage - 4100) / 25;
	data |= (float_reg << 4);

	SM5414_i2c_write(client, SM5414_CHGCTRL3, &data);

	SM5414_i2c_read(client, SM5414_CHGCTRL3, &data);
	dev_dbg(&client->dev,
		"%s : SM5414_CHGCTRL3 (float) : 0x%02x\n", __func__, data);

	return data;
}
static int SM5414_get_charging_health(struct i2c_client *client)
{
	static int health = POWER_SUPPLY_HEALTH_GOOD;
	struct sec_charger_info *charger = i2c_get_clientdata(client);
	u8 int1;

	SM5414_i2c_read(client, SM5414_INT1, &int1);

	dev_info(&client->dev,
		"%s : SM5414_INT1 : 0x%02x\n", __func__, int1);

	if (int1 & SM5414_INT1_VBUSOVP) {
		health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
		charger_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
	} else if (int1 & SM5414_INT1_VBUSUVLO) {
		msleep(1000);
		if (charger->cable_type != POWER_SUPPLY_TYPE_BATTERY) {
			health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
			charger_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
		}
	} else if (int1 & SM5414_INT1_VBUSINOK) {
		health = POWER_SUPPLY_HEALTH_GOOD;
		charger_health = POWER_SUPPLY_HEALTH_GOOD;
	}

	return (int)health;
}
static void SM5414_read_regs(struct i2c_client *client, char *str)
{
	u8 data = 0;
	u32 addr = 0;

	//0x00~02 are R/C (read and clear)
	for (addr = SM5414_INTMASK1; addr <= SM5414_CHGCTRL5; addr++) {
		SM5414_i2c_read(client, addr, &data);
		sprintf(str+strlen(str), "0x%x, ", data);
	}
}
static void SM5414_test_read(struct i2c_client *client)
{
	u8 data = 0;
	u32 addr = 0;

    //0x00~02 are R/C
	for (addr = SM5414_INTMASK1; addr <= SM5414_CHGCTRL5; addr++) {
		SM5414_i2c_read(client, addr, &data);
		dev_info(&client->dev,
			"SM5414 addr : 0x%02x data : 0x%02x\n", addr, data);
	}
}
static void SM5414_charger_otg_control(
				struct i2c_client *client)
{
	struct sec_charger_info *charger = i2c_get_clientdata(client);
	u8 data;
//turn on/off ENBOOST
	if (charger->cable_type ==
		POWER_SUPPLY_TYPE_BATTERY) {
		dev_info(&client->dev, "%s : turn off OTG\n", __func__);
		/* turn off OTG */
		SM5414_i2c_read(client, SM5414_CTRL, &data);
		data &= 0xfe;
		SM5414_i2c_write(client, SM5414_CTRL, &data);
	} else {
		dev_info(&client->dev, "%s : turn on OTG\n", __func__);
		/* turn on OTG */
		SM5414_i2c_read(client, SM5414_CTRL, &data);
		data |= 0x01;
		SM5414_i2c_write(client, SM5414_CTRL, &data);
	}
}
示例#11
0
bool sec_hal_chg_get_property(struct i2c_client *client,
			      enum power_supply_property psp,
			      union power_supply_propval *val)
{
	struct sec_charger_info *charger = i2c_get_clientdata(client);
	u8 data;
	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		if (charger->is_fullcharged)
			val->intval = POWER_SUPPLY_STATUS_FULL;
		else
			val->intval = SM5414_get_charging_status(client);
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		val->intval = charger_health;
		break;
	case POWER_SUPPLY_PROP_CHARGE_TYPE:
		val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
		break;
	// Have to mention the issue about POWER_SUPPLY_PROP_CHARGE_NOW to Marvel
	case POWER_SUPPLY_PROP_CHARGE_NOW:
	case POWER_SUPPLY_PROP_CURRENT_MAX:
	case POWER_SUPPLY_PROP_CURRENT_AVG:
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
	case POWER_SUPPLY_PROP_CURRENT_NOW:
		if (charger->charging_current) {
			SM5414_i2c_read(client, SM5414_VBUSCTRL, &data);
			data &= 0x3f;
			val->intval = (100 + (data * 50));
			if (val->intval < 2050)
				val->intval = (100 + (data * 50));
			/*dev_dbg(&client->dev,
				"%s 1: set-current(%dmA), current now(%dmA)\n",
				__func__, charger->charging_current, val->intval);*/
		} else {
			val->intval = 100;
			/*dev_dbg(&client->dev,
				"%s 2: set-current(%dmA), current now(%dmA)\n",
				__func__, charger->charging_current, val->intval);*/
		}
		break;
	case POWER_SUPPLY_PROP_POWER_STATUS:
		val->intval = POWER_SUPPLY_PWR_RDY_UNKNOWN;
		break;
	default:
		return false;
	}
	return true;
}
static int SM5414_debugfs_show(struct seq_file *s, void *data)
{
	struct sec_charger_info *charger = s->private;
	u8 reg;
	u8 reg_data;

	seq_printf(s, "SM CHARGER IC :\n");
	seq_printf(s, "==================\n");
	for (reg = SM5414_INTMASK1; reg <= SM5414_CHGCTRL5; reg++) {
		SM5414_i2c_read(charger->client, reg, &reg_data);
		seq_printf(s, "0x%02x:\t0x%02x\n", reg, reg_data);
	}

	seq_printf(s, "\n");
	return 0;
}
static u8 SM5414_set_fast_charging_current_data(
		struct i2c_client *client, int fast_charging_current)
{
	u8 data = 0;

	if(fast_charging_current < 100)
		fast_charging_current = 100;
	else if (fast_charging_current > 2500)
		fast_charging_current = 2500;

	data = (fast_charging_current - 100) / 50;

	SM5414_i2c_write(client, SM5414_CHGCTRL2, &data);
	SM5414_i2c_read(client, SM5414_CHGCTRL2, &data);

	dev_dbg(&client->dev,
		"%s : SM5414_CHGCTRL2 (fast) : 0x%02x\n", __func__, data);

	return data;
}
ssize_t SM5414_hal_chg_store_attrs(struct device *dev,
				const ptrdiff_t offset,
				const char *buf, size_t count)
{
	struct power_supply *psy = dev_get_drvdata(dev);
	struct sec_charger_info *chg =
		container_of(psy, struct sec_charger_info, psy_chg);
	int ret = 0;
	int x = 0;
	u8 data = 0;

	switch (offset) {
	case CHG_REG:
		if (sscanf(buf, "%x\n", &x) == 1) {
			chg->reg_addr = x;
			SM5414_i2c_read(chg->client,
				chg->reg_addr, &data);
			chg->reg_data = data;
			dev_dbg(dev, "%s: (read) addr = 0x%x, data = 0x%x\n",
				__func__, chg->reg_addr, chg->reg_data);
			ret = count;
		}
		break;
	case CHG_DATA:
		if (sscanf(buf, "%x\n", &x) == 1) {
			data = (u8)x;
			dev_dbg(dev, "%s: (write) addr = 0x%x, data = 0x%x\n",
				__func__, chg->reg_addr, data);
			SM5414_i2c_write(chg->client,
				chg->reg_addr, &data);
			ret = count;
		}
		break;
	default:
		ret = -EINVAL;
		break;
	}

	return ret;
}
static void SM5414_charger_function_control(
				struct i2c_client *client)
{
	struct sec_charger_info *charger = i2c_get_clientdata(client);
	union power_supply_propval value;
	u8 ctrl;
	u8 chg_en;

	charger->charging_current_max =
		charger->pdata->charging_current[
		charger->cable_type].input_current_limit;

	charger->charging_current =
		charger->pdata->charging_current[
		charger->cable_type].fast_charging_current;

	if (charger->charging_current < 0) {
		dev_info(&client->dev,
			"%s : OTG is activated. Ignore command!\n", __func__);
		return;
	}

	if (charger->cable_type == POWER_SUPPLY_TYPE_BATTERY) {
		/* Disable Charger */
		dev_info(&client->dev,
			"%s : Disable Charger, Battery Supply!\n", __func__);
		// nCHG_EN is logic low so set 1 to disable charger
		charger->is_fullcharged = false;
		gpio_direction_output((charger->pdata->chg_gpio_en), 1);
		SM5414_set_toggle_charger(client, 0);
	} else {

		psy_do_property(charger->pdata->fuelgauge_name, get,
				POWER_SUPPLY_PROP_CAPACITY, value);
		if (value.intval > 0) {
			/* Suspend enable for register reset */
			ctrl = 0x44;
			SM5414_i2c_write(client, SM5414_CTRL, &ctrl);
			msleep(20);

			ctrl = 0x40;
			SM5414_i2c_write(client, SM5414_CTRL, &ctrl);
		}

		dev_info(&client->dev, "%s : float voltage (%dmV)\n",
			__func__, charger->pdata->chg_float_voltage);

		/* Set float voltage */
		SM5414_set_float_voltage_data(
			client, charger->pdata->chg_float_voltage);

		dev_info(&client->dev, "%s : topoff current (%dmA)\n",
			__func__, charger->pdata->charging_current[
			charger->cable_type].full_check_current_1st);
		SM5414_set_topoff_current_limit_data(
			client, charger->pdata->charging_current[
				charger->cable_type].full_check_current_1st);

		SM5414_i2c_read(client, SM5414_CTRL, &chg_en);

		if (!(chg_en & CHARGE_EN)) {
			SM5414_set_input_current_limit_data(client, 100);
			// nCHG_EN is logic low so set 0 to enable charger
			gpio_direction_output((charger->pdata->chg_gpio_en), 0);
			SM5414_set_toggle_charger(client, 1);
			msleep(100);

			/* Input current limit */
			dev_info(&client->dev, "%s : input current (%dmA)\n",
				__func__, charger->charging_current_max);

			SM5414_set_input_current_limit_data(
				client, charger->charging_current_max);
		}

		/* Set fast charge current */
		dev_info(&client->dev, "%s : fast charging current (%dmA), siop_level=%d\n",
			__func__, charger->charging_current, charger->siop_level);
		SM5414_set_fast_charging_current_data(
			client, charger->charging_current);

		dev_info(&client->dev,
			"%s : Enable Charger!\n", __func__);
	}
}