static void sec_bat_initial_check(void)
{
	union power_supply_propval value;

	switch (abb_get_cable_status()) {
	case CABLE_TYPE_AC:
		value.intval = POWER_SUPPLY_TYPE_MAINS;
		break;
	case CABLE_TYPE_MISC:
		value.intval = POWER_SUPPLY_TYPE_MISC;
		break;
	case CABLE_TYPE_USB:
		value.intval = POWER_SUPPLY_TYPE_USB;
		break;
	case CABLE_TYPE_CARDOCK:
		value.intval = POWER_SUPPLY_TYPE_CARDOCK;
		break;
	case CABLE_TYPE_NONE:
		value.intval = POWER_SUPPLY_TYPE_BATTERY;
		break;
	default:
		pr_err("%s: invalid cable :%d\n",
			__func__, abb_get_cable_status());
		return;
	}

	psy_do_property("battery", set,
		POWER_SUPPLY_PROP_ONLINE, value);
}
Exemplo n.º 2
0
static bool sec_bat_check_by_psy(struct sec_battery_info *battery)
{
	char *psy_name;
	union power_supply_propval value;
	bool ret;
	ret = true;

	switch (battery->pdata->battery_check_type) {
	case SEC_BATTERY_CHECK_PMIC:
		psy_name = battery->pdata->pmic_name;
		break;
	case SEC_BATTERY_CHECK_FUELGAUGE:
		psy_name = "sec-fuelgauge";
		break;
	case SEC_BATTERY_CHECK_CHARGER:
		psy_name = "sec-charger";
		break;
	default:
		pr_err("%s: Invalid Battery Check Type\n",
			__func__);
		ret = false;
		goto battery_check_error;
		break;
	}

	psy_do_property(psy_name, get,
		POWER_SUPPLY_PROP_PRESENT, value);
	ret = (bool)value.intval;

battery_check_error:
	return ret;
}
Exemplo n.º 3
0
static bool sec_bat_ovp_uvlo_by_psy(struct sec_battery_info *battery)
{
	char *psy_name;
	union power_supply_propval value;
	bool ret;
	ret = true;

	switch (battery->pdata->ovp_uvlo_check_type) {
	case SEC_BATTERY_OVP_UVLO_PMICPOLLING:
		psy_name = battery->pdata->pmic_name;
		break;
	case SEC_BATTERY_OVP_UVLO_CHGPOLLING:
		psy_name = "sec-charger";
		break;
	default:
		pr_err("%s: Invalid OVP/UVLO Check Type\n",
			__func__);
		ret = false;
		goto ovp_uvlo_check_error;
		break;
	}

	psy_do_property(psy_name, get,
		POWER_SUPPLY_PROP_HEALTH, value);

	if (value.intval != POWER_SUPPLY_HEALTH_GOOD) {
		battery->health = value.intval;
		ret = false;
	}

ovp_uvlo_check_error:
	return ret;
}
Exemplo n.º 4
0
static int otg_accessory_power(bool enable)
{
	u8 on = (u8)!!enable;
	union power_supply_propval val;
	struct device_node *np_charger = NULL;
	char *charger_name;

	pr_info("otg accessory power = %d\n", on);

	np_charger = of_find_node_by_name(NULL, "battery");
	if (!np_charger) {
		pr_err("%s: failed to get the battery device node\n", __func__);
		return 0;
	} else {
		if (!of_property_read_string(np_charger, "battery,charger_name",
					(char const **)&charger_name)) {
			pr_info("%s: charger_name = %s\n", __func__,
					charger_name);
		} else {
			pr_err("%s: failed to get the charger name\n"
								, __func__);
			return 0;
		}
	}

	val.intval = enable;
	psy_do_property(charger_name, set,
			POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, val);

	return 0;
}
void bq51221_wireless_chg_init(struct i2c_client *client)
{
	int data = 0;
	union power_supply_propval value;
	struct bq51221_charger_data *charger = i2c_get_clientdata(client);

	pr_info("%s\n", __func__);

	psy_do_property("battery", get,
				POWER_SUPPLY_PROP_CAPACITY, value);
	/* init I limit(IOREG) */
	bq51221_reg_write(client, BQ51221_REG_CURRENT_REGISTER2, BQ51221_IOREG_100_VALUE);
	data = bq51221_reg_read(client, BQ51221_REG_CURRENT_REGISTER2);
	pr_info("%s IOREG = 0x%x \n", __func__, data);

	/* init CEP timing */

	/* init RCVD PWR */

	/* read pad mode */
	bq51221_get_pad_mode(client);

	pr_info("%s siop = %d \n" ,__func__, charger->pdata->siop_level );
	if ((value.intval < charger->pdata->wireless_cc_cv) &&
		(charger->pdata->pad_mode == BQ51221_PAD_MODE_WPC) &&
		(charger->pdata->siop_level == 100) &&
		!charger->pdata->default_voreg) {
		/* set VOREG set 5.5V*/
		bq51221_set_voreg(charger->client, 0);
	} else {
		/* init VOREG with default value */
		bq51221_set_voreg(charger->client, 1);
	}
}
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;
}
int bq51221_set_voreg(struct i2c_client *client, int default_value)
{
	u8 data = 0;
	int ret = 0;
	int retry_cnt =0;
	union power_supply_propval value;
	struct bq51221_charger_data *charger = i2c_get_clientdata(client);

	return 0; // concept chagned, vout is always 5V

	if (charger->pdata->pad_mode == BQ51221_PAD_MODE_PMA) {
		pr_info("%s PMA MODE, do not set Voreg \n", __func__);
		return 0;
	}

	psy_do_property("battery", get,
				POWER_SUPPLY_PROP_CAPACITY, value);

	if ((value.intval >= charger->pdata->wireless_cc_cv) && !default_value)
		default_value = 1;

	if (default_value) {
		/* init VOREG with default value */
		ret = bq51221_reg_write(client, BQ51221_REG_CURRENT_REGISTER, 0x01);
		if(ret < 0) {
			while(retry_cnt++ < 3) {
				msleep(50);
				pr_debug("%s retry_cnt = %d, ret =%d \n",__func__, retry_cnt, ret);
				/* init VOREG with default value */
				ret = bq51221_reg_write(client, BQ51221_REG_CURRENT_REGISTER, 0x01);
				data = bq51221_reg_read(client, BQ51221_REG_CURRENT_REGISTER);
				if(ret >= 0) {
					pr_debug("%s VOREG = 0x%x \n", __func__, data);
					break;
				}
			}
		}
		data = bq51221_reg_read(client, BQ51221_REG_CURRENT_REGISTER);
		pr_info("%s VOREG = 0x%x 5.0V, cnt(%d)\n", __func__, data, retry_cnt);
	} else {
		ret = bq51221_reg_write(client, BQ51221_REG_CURRENT_REGISTER, 0x02);
		if(ret < 0) {
			while(retry_cnt++ < 3) {
				msleep(50);
				pr_debug("%s retry_cnt = %d, ret =%d \n",__func__, retry_cnt, ret);
				/* init VOREG with default value */
				ret = bq51221_reg_write(client, BQ51221_REG_CURRENT_REGISTER, 0x02);
				data = bq51221_reg_read(client, BQ51221_REG_CURRENT_REGISTER);
				if(ret >= 0) {
					pr_debug("%s VOREG = 0x%x \n", __func__, data);
					break;
				}
			}
		}
		data = bq51221_reg_read(client, BQ51221_REG_CURRENT_REGISTER);
		pr_info("%s VOREG = 0x%x 5.5V, cnt(%d)\n", __func__, data, retry_cnt);
	}
	return ret;
}
Exemplo n.º 8
0
static void sec_bat_initial_check(void)
{
	union power_supply_propval value;

	if (!gpio_get_value_cansleep(
		PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_TA_nCONNECTED)))
		psy_do_property("battery", set,
			POWER_SUPPLY_PROP_ONLINE, value);
}
Exemplo n.º 9
0
static int adc_get_current(struct i2c_client *client)
{
	union power_supply_propval value;

	psy_do_property("sec-charger", get,
		POWER_SUPPLY_PROP_CURRENT_NOW, value);

	return value.intval;
}
static void sec_bat_initial_check(void)
{
	union power_supply_propval value;

	if (POWER_SUPPLY_TYPE_BATTERY < current_cable_type) {
		value.intval = current_cable_type<<ONLINE_TYPE_MAIN_SHIFT;
		psy_do_property("battery", set,
				POWER_SUPPLY_PROP_ONLINE, value);
	} else {
		psy_do_property("sec-charger", get,
				POWER_SUPPLY_PROP_ONLINE, value);
		if (value.intval == POWER_SUPPLY_TYPE_WIRELESS) {
			value.intval =
			POWER_SUPPLY_TYPE_WIRELESS<<ONLINE_TYPE_MAIN_SHIFT;
			psy_do_property("battery", set,
					POWER_SUPPLY_PROP_ONLINE, value);
		}
	}
}
static void sec_bat_initial_check(void)
{
	union power_supply_propval value;

	if (POWER_SUPPLY_TYPE_BATTERY != current_cable_type) {
		value.intval = current_cable_type;
		psy_do_property("battery", set,
			POWER_SUPPLY_PROP_ONLINE, value);
	}
}
void cable_initial_check(struct sec_battery_info *battery)
{
  union power_supply_propval value;

  pr_info("%s : current_cable_type : (%d)\n", __func__, current_cable_type);
  if (POWER_SUPPLY_TYPE_BATTERY != current_cable_type) {
    value.intval = current_cable_type;
    psy_do_property("battery", set,
        POWER_SUPPLY_PROP_ONLINE, value);
  } else {
    psy_do_property(battery->pdata->charger_name, get,
        POWER_SUPPLY_PROP_ONLINE, value);
    if (value.intval == POWER_SUPPLY_TYPE_WIRELESS) {
      value.intval = 1;
      psy_do_property("wireless", set,
          POWER_SUPPLY_PROP_ONLINE, value);
    }
  }
}
Exemplo n.º 13
0
static int sec_bat_set_charge(
				struct sec_battery_info *battery,
				bool enable)
{
	union power_supply_propval val;
	int ret;

	if ((battery->cable_type != POWER_SUPPLY_TYPE_BATTERY) &&
		(battery->health != POWER_SUPPLY_HEALTH_GOOD)) {
		pr_info("%s: Battery is NOT good!\n", __func__);
		return -EPERM;
	}

	if (enable) {
		val.intval = battery->cable_type;
		/*Reset charging start time only in initial charging start */
		if (battery->charging_start_time == 0) {
			battery->charging_start_time = jiffies;
			battery->charging_next_time =
				battery->pdata->charging_reset_time;
		}
	} else {
		val.intval = POWER_SUPPLY_TYPE_BATTERY;
		battery->charging_start_time = 0;
		battery->charging_passed_time = 0;
		battery->charging_next_time = 0;
		battery->full_check_cnt = 0;
	}

	battery->temp_high_cnt = 0;
	battery->temp_low_cnt = 0;
	battery->temp_recover_cnt = 0;

	psy_do_property("sec-charger", set,
		POWER_SUPPLY_PROP_ONLINE, val);

	psy_do_property("sec-fuelgauge", set,
		POWER_SUPPLY_PROP_ONLINE, val);

	return 0;
}
static bool sii8240_vbus_present(void)
{
	union power_supply_propval value;

	psy_do_property("sec-charger", get, POWER_SUPPLY_PROP_ONLINE, value);
	pr_info("sii8240: sec-charger : %d\n", value.intval);

	if (value.intval == POWER_SUPPLY_TYPE_BATTERY ||
			value.intval == POWER_SUPPLY_TYPE_WPC)
		return false;
	else
		return true;
}
static bool sec_bat_ovp_uvlo_result_callback(int health) {
	union power_supply_propval value;

	psy_do_property("sec-charger", get,
				POWER_SUPPLY_PROP_HEALTH, value);

	if (value.intval  == POWER_SUPPLY_HEALTH_OVERVOLTAGE) {
		is_ovlo_state = true;
	} else {
		is_ovlo_state = false;
	}

	return true;
}
static void sec_bat_initial_check(void)
{
	union power_supply_propval value;

	/* check cable by sec_bat_get_cable_type()
	 * for initial check
	 */
	value.intval = -1;

	if (extended_cable_type || !gpio_get_value_cansleep(
		PM8921_GPIO_PM_TO_SYS(PMIC_GPIO_TA_nCONNECTED)))
		psy_do_property("battery", set,
			POWER_SUPPLY_PROP_ONLINE, value);
}
Exemplo n.º 17
0
/******************************************************************************
 *    function:   tuner_drv_gpio_config_poweron
 *    brief   :   interruption registration disable control of a driver
 *    date    :   2012.12.18
 *    author  :   K.Matsumaru(*)(*)
 *
 *    return  :   none
 *    input   :   none
 *    output  :   none
 ******************************************************************************/
void tuner_drv_gpio_config_poweron( void )
{
#if defined(CONFIG_TMM_CHG_CTRL)
    union power_supply_propval value;
	tmm_chg_log("TMM Charge control: Sending TMM Tuner Powered ON Signal\n");
	value.intval = TUNER_SWITCHED_ON_SIGNAL;
    psy_do_property("battery", set, POWER_SUPPLY_PROP_CURRENT_NOW, value);					 
#endif
	
	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_spi_di, GPIOMUX_FUNC_1,
					 GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
					 GPIO_CFG_ENABLE);
	
	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_spi_do, GPIOMUX_FUNC_1,
					 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
					 GPIO_CFG_ENABLE);
	
	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_spi_cs, GPIOMUX_FUNC_1,
					 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
					 GPIO_CFG_ENABLE);
	
	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_spi_clk, GPIOMUX_FUNC_1,
					 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
					 GPIO_CFG_ENABLE);
	
	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_int, GPIOMUX_FUNC_1,
					 GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
					 GPIO_CFG_ENABLE);

	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_en, GPIOMUX_FUNC_GPIO,
					 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
					 GPIO_CFG_ENABLE);
		
	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_rst, GPIOMUX_FUNC_GPIO,
					 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
					 GPIO_CFG_ENABLE);
					 
	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_i2c_sda, GPIOMUX_FUNC_3,
					 GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
					 GPIO_CFG_ENABLE);		
	
	gpio_tlmm_config(GPIO_CFG(isdbtmm_pdata->gpio_i2c_scl, GPIOMUX_FUNC_3,
					 GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
					 GPIO_CFG_ENABLE);		

	return;
}
Exemplo n.º 18
0
/*FIXME, need to use more common/proper function
for checking a VBUS regardless of H/W charger IC*/
static bool sii8240_vbus_present(void)
{
	bool ret = true;
#ifdef MFD_MAX778XX_COMMON
	union power_supply_propval value;
	psy_do_property("sec-charger", get, POWER_SUPPLY_PROP_ONLINE, value);
	pr_info("sec-charger : %d\n", value.intval);
	if (value.intval == POWER_SUPPLY_TYPE_BATTERY
			|| value.intval == POWER_SUPPLY_TYPE_WIRELESS)
		ret = false;
#else
	struct sii8240_platform_data *pdata = g_pdata;
	if (pdata->gpio_ta_int > 0)
		ret = gpio_get_value_cansleep(pdata->gpio_ta_int) ?
								false : true;
#endif
	pr_info("VBUS : %s in %s\n", ret ? "IN" : "OUT", __func__);
	return ret;
}
Exemplo n.º 19
0
static int adc_get_current(struct i2c_client *client)
{
	union power_supply_propval value;
	struct sec_fuelgauge_info *fuelgauge =
				i2c_get_clientdata(client);
	int current_now;

	current_now = adc_get_data_by_adc(fuelgauge,
		get_battery_data(fuelgauge).adc2current_table,
		get_battery_data(fuelgauge).adc2current_table_size,
		adc_get_adc_value(fuelgauge, SEC_BAT_ADC_CHANNEL_CURRENT_NOW));

	if (!current_now) {
		psy_do_property("sec-charger", get,
			POWER_SUPPLY_PROP_CURRENT_NOW, value);
		current_now = value.intval;
	}

	return current_now;
}
Exemplo n.º 20
0
void bq51221_wireless_chg_init(struct i2c_client *client)
{
	int data = 0;
	union power_supply_propval value;

	pr_info("%s\n", __func__);

	psy_do_property("battery", get,
				POWER_SUPPLY_PROP_CAPACITY, value);
	/* init I limit(IOREG) */
	bq51221_reg_write(client, BQ51221_REG_CURRENT_REGISTER2, BQ51221_IOREG_100_VALUE);
	data = bq51221_reg_read(client, BQ51221_REG_CURRENT_REGISTER2);
	pr_info("%s IOREG = 0x%x \n", __func__, data);

	/* init CEP timing */

	/* init RCVD PWR */

	/* read pad mode */
	bq51221_get_pad_mode(client);
}
Exemplo n.º 21
0
static int set_online(int event, int state)
{
	union power_supply_propval val;
	struct device_node *np_charger = NULL;
	char *charger_name;

	if (event == NOTIFY_EVENT_SMTD_EXT_CURRENT)
		pr_info("request smartdock charging current = %s\n",
			state ? "1000mA" : "1700mA");
	else if (event == NOTIFY_EVENT_MMD_EXT_CURRENT)
		pr_info("request mmdock charging current = %s\n",
			state ? "900mA" : "1400mA");

	np_charger = of_find_node_by_name(NULL, "battery");
	if (!np_charger) {
		pr_err("%s: failed to get the battery device node\n", __func__);
		return 0;
	} else {
		if (!of_property_read_string(np_charger, "battery,charger_name",
					(char const **)&charger_name)) {
			pr_info("%s: charger_name = %s\n", __func__,
					charger_name);
		} else {
			pr_err("%s: failed to get the charger name\n",
								 __func__);
			return 0;
		}
	}

	if (state)
		val.intval = POWER_SUPPLY_TYPE_SMART_OTG;
	else
		val.intval = POWER_SUPPLY_TYPE_SMART_NOTG;

	psy_do_property(charger_name, set,
			POWER_SUPPLY_PROP_ONLINE, val);

	return 0;
}
Exemplo n.º 22
0
static void sec_bat_do_fullcharged(
				struct sec_battery_info *battery)
{
	union power_supply_propval value;

	if (((battery->pdata->full_check_type ==
		SEC_BATTERY_FULLCHARGED_ADC_DUAL) ||
		(battery->pdata->full_check_type ==
		SEC_BATTERY_FULLCHARGED_FG_CURRENT_DUAL)) &&
		(battery->charging_mode ==
		SEC_BATTERY_CHARGING_NORMAL)) {
		battery->charging_mode = SEC_BATTERY_CHARGING_2ND;
	} else {
		battery->charging_mode = SEC_BATTERY_CHARGING_NONE;
		sec_bat_set_charge(battery, false);

		value.intval = POWER_SUPPLY_STATUS_FULL;
		psy_do_property("sec-fuelgauge", set,
			POWER_SUPPLY_PROP_STATUS, value);
	}

	battery->status = POWER_SUPPLY_STATUS_FULL;
}
static int sec_bat_check_cable_callback(void)
{
	union power_supply_propval value;
	value.intval = 0;

	psy_do_property("sec-charger", get,
				POWER_SUPPLY_PROP_CHARGE_COUNTER, value);
	msleep(500);

	if (current_cable_type == POWER_SUPPLY_TYPE_BATTERY &&
		value.intval) {
		pr_info("%s : VBUS IN\n", __func__);
		return POWER_SUPPLY_TYPE_UARTOFF;
	}

	if (current_cable_type == POWER_SUPPLY_TYPE_UARTOFF &&
		!value.intval) {
		pr_info("%s : VBUS OUT\n", __func__);
		return POWER_SUPPLY_TYPE_BATTERY;
	}

	return current_cable_type;
}
Exemplo n.º 24
0
static void smb358_check_slow_charging(struct work_struct *work)
{
	struct sec_charger_info *charger =
		container_of(work, struct sec_charger_info, slow_work.work);

	u8 i, aicl_data;
	int aicl_current = 0;
	union power_supply_propval val;

	if (charger->pdata->charging_current
				[charger->cable_type].input_current_limit <= SLOW_CHARGING_CURRENT_STANDARD) {
			charger->is_slow_charging = true;
	} else {
		for(i = 0; i < 10; i++) {
			msleep(200);
			smb358_i2c_read(charger->client, SMB358_STATUS_E, &aicl_data);
			if (aicl_data & 0x10) { /* check AICL complete */
				break;
			}
		}
		if (i == 10) {
			pr_err("%s: aicl not complete, return\n", __func__);
			charger->is_slow_charging = false;
			return;
		}

		aicl_data &= 0xF; /* get only AICL result field */
		switch (aicl_data) {
		case 0: /* AICL result 300mA */
			aicl_current = 300;
			break;
		case 1: /* AICL result 500mA */
			aicl_current = 500;
			break;
		case 2: /* AICL result 700mA */
			aicl_current = 700;
			break;
		case 3: /* AICL result 1000mA */
			aicl_current = 1000;
			break;
		case 4: /* AICL result 1200mA */
			aicl_current = 1200;
			break;
		case 5: /* AICL result 1300mA */
			aicl_current = 1300;
			break;
		case 6: /* AICL result 1800mA */
			aicl_current = 1800;
			break;
		case 7: /* AICL result 2000mA */
			aicl_current = 2000;
			break;
		default: /* etc */
			aicl_current = 2000;
			break;
		}
		if (aicl_current <= SLOW_CHARGING_CURRENT_STANDARD)
			charger->is_slow_charging = true;
		else
			charger->is_slow_charging = false;
	}

	pr_info("%s: Slow(%d), aicl_current(%d), input_current(%d)\n",
		__func__, charger->is_slow_charging, aicl_current, charger->pdata->charging_current
			[charger->cable_type].input_current_limit);

	psy_do_property("battery", set,
		POWER_SUPPLY_PROP_CHARGE_TYPE, val);

}
Exemplo n.º 25
0
static void smb358_charger_function_control(
				struct i2c_client *client)
{
	struct sec_charger_info *charger = i2c_get_clientdata(client);
	union power_supply_propval val;
	int status;
	u8 data, chgcurrent;
	union power_supply_propval input_value;

	psy_do_property("battery", get,
		POWER_SUPPLY_PROP_STATUS, input_value);
	status = input_value.intval;

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

	psy_do_property("battery", get,
		POWER_SUPPLY_PROP_HEALTH, input_value);
	if (input_value.intval ==
		POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) {
		pr_info("[SMB358] Unspec_failure, charger suspend\n");
		smb358_enter_suspend(client);
	}
	else if (charger->cable_type ==
		POWER_SUPPLY_TYPE_BATTERY) {
		/* Charger Disabled */
		smb358_set_command(client, SMB358_COMMAND_A, 0xc0);
		if (status == POWER_SUPPLY_STATUS_FULL)
			return;
		pr_info("[SMB358] Set the registers to the default configuration\n");
		/* Set the registers to the default configuration */
		smb358_set_command(client, SMB358_CHARGE_CURRENT, 0xFE);
		smb358_set_command(client, SMB358_INPUT_CURRENTLIMIT, 0x74);
		smb358_set_command(client, SMB358_VARIOUS_FUNCTIONS, 0xD7);
		data = 0x00;
		data |= smb358_get_float_voltage_data(charger->pdata->chg_float_voltage);
		smb358_set_command(client, SMB358_FLOAT_VOLTAGE, data);
		/* Disable Automatic Recharge */
		smb358_set_command(client, SMB358_CHARGE_CONTROL, 0x84);
		smb358_set_command(client, SMB358_STAT_TIMERS_CONTROL, 0x0F);
		smb358_set_command(client, SMB358_PIN_ENABLE_CONTROL, 0x09);
		smb358_set_command(client, SMB358_THERM_CONTROL_A, 0xF0);
		smb358_set_command(client, SMB358_SYSOK_USB30_SELECTION, 0x08);
		smb358_set_command(client, SMB358_OTHER_CONTROL_A, 0x01);
		smb358_set_command(client, SMB358_OTG_TLIM_THERM_CONTROL, 0xF6);
		smb358_set_command(client, SMB358_LIMIT_CELL_TEMPERATURE_MONITOR, 0xA5);
		smb358_set_command(client, SMB358_FAULT_INTERRUPT, 0x00);
		smb358_set_command(client, SMB358_STATUS_INTERRUPT, 0x00);

	} else {
		int full_check_type;
		psy_do_property("battery", get,
			POWER_SUPPLY_PROP_CHARGE_NOW, val);
		if (val.intval == SEC_BATTERY_CHARGING_1ST)
			full_check_type = charger->pdata->full_check_type;
		else
			full_check_type = charger->pdata->full_check_type_2nd;

		smb358_i2c_read(client, SMB358_COMMAND_A, &data);

		if ((data & 0x10) && charger->pdata->vbus_ctrl_gpio) {
			int level;
			/* disable otg & charging */
			smb358_clear_reg(client, SMB358_COMMAND_A, 0x12);

			/* turn off vbus */
			gpio_set_value(charger->pdata->vbus_ctrl_gpio, 1);
			msleep(30);

			level = gpio_get_value_cansleep(charger->pdata->vbus_ctrl_gpio);
			pr_info("[SMB358] vbus ctrl gpio %d level %d\n", charger->pdata->vbus_ctrl_gpio, level);

			/* turn on vbus */
			gpio_set_value(charger->pdata->vbus_ctrl_gpio, 0);
			/* smb358_test_read(client); */
		} else if ((data & 0x02) && !((status == POWER_SUPPLY_STATUS_FULL) &&
			((full_check_type == SEC_BATTERY_FULLCHARGED_CHGGPIO) ||
			(full_check_type == SEC_BATTERY_FULLCHARGED_CHGINT) ||
			(full_check_type == SEC_BATTERY_FULLCHARGED_CHGPSY)))) {
			chgcurrent = 0;
			smb358_i2c_read(client, SMB358_CHARGE_CURRENT, &chgcurrent);
			chgcurrent &= 0xE0; /* get fast charging current */

			if (chgcurrent == smb358_get_fast_charging_current_data(
					charger->charging_current)) {
				pr_info("[SMB358] Skip the Same charging current setting\n");
				schedule_delayed_work(&charger->slow_work, 0);
				return;
			}
		}

		/* [STEP - 1] ================================================
                 * Volatile write permission(bit 7) - allow(1)
                 * Charging Enable(bit 1) - Disabled(0, default)
                 * STAT Output(bit 0) - Enabled(0)
                */
#if defined(CONFIG_MACH_LT02)
		smb358_set_command(client,
			SMB358_COMMAND_A, 0xC2);
#else
		smb358_set_command(client,
                        SMB358_COMMAND_A, 0xC0);
#endif
                /* [STEP - 2] ================================================
                 * USB 5/1(9/1.5) Mode(bit 1) - USB1/USB1.5(0), USB5/USB9(1)
                 * USB/HC Mode(bit 0) - USB5/1 or USB9/1.5 Mode(0)
                 *                      High-Current Mode(1)
                */
                switch (charger->cable_type) {
		case POWER_SUPPLY_TYPE_UNKNOWN:
		case POWER_SUPPLY_TYPE_MAINS:
		case POWER_SUPPLY_TYPE_USB_CDP:
		case POWER_SUPPLY_TYPE_MISC:
		case POWER_SUPPLY_TYPE_WIRELESS:
		case POWER_SUPPLY_TYPE_CARDOCK:
		case POWER_SUPPLY_TYPE_UARTOFF:
		case POWER_SUPPLY_TYPE_LAN_HUB:
		case POWER_SUPPLY_TYPE_MHL_900:
		case POWER_SUPPLY_TYPE_MHL_1500:
		case POWER_SUPPLY_TYPE_SMART_NOTG:
                    /* High-current mode */
                    data = 0x03;
			break;
		case POWER_SUPPLY_TYPE_UPS:
		case POWER_SUPPLY_TYPE_USB:
		case POWER_SUPPLY_TYPE_USB_DCP:
		case POWER_SUPPLY_TYPE_USB_ACA:
		case POWER_SUPPLY_TYPE_MHL_500:
		case POWER_SUPPLY_TYPE_MHL_USB:
		case POWER_SUPPLY_TYPE_SMART_OTG:
		case POWER_SUPPLY_TYPE_POWER_SHARING:
			/* USB5 */
			data = 0x02;
			break;
		default:
			/* USB1 */
			data = 0x00;
			break;
		}
		smb358_set_command(client,
			SMB358_COMMAND_B, data);


		/* [STEP 3] Charge Current(0x00) ===============================
		 * Set pre-charge current(bit 4:3) - 450mA(11)
		 * Set fast charge current(bit 7:5)
		 * Set termination current(bit 2:0)
		*/
		if (charger->siop_level < 100) {
			charger->charging_current =
				charger->charging_current * charger->siop_level / 100;
		}
		dev_info(&client->dev,
			"%s : fast charging current (%dmA)\n",
			__func__, charger->charging_current);

		data = 0x18;
		data |= smb358_get_fast_charging_current_data(
			charger->charging_current);
		switch (full_check_type) {
		case SEC_BATTERY_FULLCHARGED_CHGGPIO:
		case SEC_BATTERY_FULLCHARGED_CHGINT:
		case SEC_BATTERY_FULLCHARGED_CHGPSY:
			if (val.intval == SEC_BATTERY_CHARGING_1ST) {
				dev_info(&client->dev,
					"%s : termination current (%dmA)\n",
					__func__, charger->pdata->charging_current[
					charger->cable_type].full_check_current_1st);
				data |= smb358_get_term_current_limit_data(
					charger->pdata->charging_current[
					charger->cable_type].full_check_current_1st);
			} else {
				dev_info(&client->dev,
					"%s : termination current (%dmA)\n",
					__func__, charger->pdata->charging_current[
					charger->cable_type].full_check_current_2nd);
				data |= smb358_get_term_current_limit_data(
					charger->pdata->charging_current[
					charger->cable_type].full_check_current_2nd);
			}
			break;
		}
		smb358_set_command(client,
			SMB358_CHARGE_CURRENT, data);

		/* [STEP - 4] =================================================
		 * Enable(EN) Pin Control(bit 6) - i2c(0), Pin(1)
		 * Pin control(bit 5) - active high(0), active low(1)
		 * USB5/1/HC input State(bit3) - Dual-state input(1)
		 * USB Input Pre-bias(bit 0) - Enable(1)
		*/
		data = 0x09;
		if (charger->pdata->chg_gpio_en)
			data |= 0x40;
		if (charger->pdata->chg_polarity_en)
			data |= 0x20;
		smb358_set_command(client,
			SMB358_PIN_ENABLE_CONTROL, data);

		/* [STEP - 5] =============================================== */
		dev_info(&client->dev, "%s : input current (%dmA)\n",
			__func__, charger->pdata->charging_current
			[charger->cable_type].input_current_limit);
		/* Input current limit */
		data = 0x00;
		data |= smb358_get_input_current_limit_data(
			charger,
			charger->pdata->charging_current
			[charger->cable_type].input_current_limit);
		smb358_set_command(client,
			SMB358_INPUT_CURRENTLIMIT, data);

		/* [STEP - 6] =================================================
		 * Input to System FET(bit 7) - Controlled by Register(1)
		 * Max System voltage(bit 5) -  Vflt + 0.1v(0)
		 * AICL(bit 4) - Enalbed(1)
		 * VCHG Function(bit 0) - Enabled(1)
		 */
		if (charger->pdata->chg_functions_setting &
			SEC_CHARGER_NO_GRADUAL_CHARGING_CURRENT)
			/* disable AICL */
			smb358_set_command(client,
				SMB358_VARIOUS_FUNCTIONS, 0x81);
		else {
			/* disable AICL */
			smb358_set_command(client,
				SMB358_VARIOUS_FUNCTIONS, 0x81);
			/* enable AICL */
			smb358_set_command(client,
				SMB358_VARIOUS_FUNCTIONS, 0x95);
		}

		/* [STEP - 7] =================================================
		 * Pre-charged to Fast-charge Voltage Threshold(Bit 7:6) - 2.3V
		 * Float Voltage(bit 5:0)
		*/
		dev_dbg(&client->dev, "%s : float voltage (%dmV)\n",
				__func__, charger->pdata->chg_float_voltage);
		data = 0x00;
		data |= smb358_get_float_voltage_data(
			charger->pdata->chg_float_voltage);
		smb358_set_command(client,
			SMB358_FLOAT_VOLTAGE, data);


		/* [STEP - 8] =================================================
		 * Charge control
		 * Automatic Recharge disable(bit 7),
		 * Current Termination disable(bit 6),
		 * BMD disable(bit 5:4),
		 * INOK Output Configuration : Push-pull(bit 3)
		 * APSD disable
		*/
#if defined(CONFIG_MACH_LT02)
		data = 0xC0;
#else
		data = 0xC1;
#endif
		switch (full_check_type) {
		case SEC_BATTERY_FULLCHARGED_CHGGPIO:
		case SEC_BATTERY_FULLCHARGED_CHGINT:
		case SEC_BATTERY_FULLCHARGED_CHGPSY:
			/* Enable Current Termination */
			data &= 0xB1;
			break;
		}
		smb358_set_command(client,
			SMB358_CHARGE_CONTROL, data);

		/* [STEP - 9] =================================================
		 *  STAT active low(bit 7),
		 *  Complete charge Timeout(bit 3:2) - Disabled(11)
		 *  Pre-charge Timeout(bit 1:0) - Disable(11)
		*/
		smb358_set_command(client,
			SMB358_STAT_TIMERS_CONTROL, 0x1F);


#if defined(CONFIG_MACH_LT02)
		/* [STEP - 10] =================================================
		 * Mininum System Voltage(bit 6) - 3.15v(1)
		 * Therm monitor(bit 4) - Disabled(1)
		 * Soft Cold/Hot Temp Limit Behavior(bit 3:2, bit 1:0) -
		 *	Charger Current + Float voltage Compensation(11)
		*/
		smb358_set_command(client,
			SMB358_THERM_CONTROL_A, 0xB0);
#else
		/* [STEP - 10] =================================================
		 * Mininum System Voltage(bit 6) - 3.75v(1)
		 * Therm monitor(bit 4) - Disabled(1)
		 * Soft Cold/Hot Temp Limit Behavior(bit 3:2, bit 1:0) -
		 *	Charger Current + Float voltage Compensation(11)
		*/
		smb358_set_command(client,
			SMB358_THERM_CONTROL_A, 0xF0);
#endif
		/* [STEP - 11] ================================================
		 * OTG/ID Pin Control(bit 7:6) - RID Disabled, OTG I2c(00)
		 * Minimum System Voltage(bit 4) - 3.75V(1)
		 * Low-Battery/SYSOK Voltage threshold(bit 3:0) - 2.5V(0001)
		 *    if this bit is disabled,
		 *    input current for system will be disabled
		 */
		smb358_set_command(client,
			SMB358_OTHER_CONTROL_A, 0x11);

		/* [STEP - 12] ================================================
		 * Charge Current Compensation(bit 7:6) - 200mA(00)
		 * Digital Thermal Regulation Threshold(bit 5:4) - 130c
		 * OTG current Limit at USBIN(Bit 3:2) - 900mA(11)
		 * OTG Battery UVLO Threshold(Bit 1:0) - 3.3V(11)
		*/
		smb358_set_command(client,
			SMB358_OTG_TLIM_THERM_CONTROL, 0x3F);

		/* [STEP - 13] ================================================
		 * Hard/Soft Limit Cell temp monitor
		*/
		smb358_set_command(client,
			SMB358_LIMIT_CELL_TEMPERATURE_MONITOR, 0x01);

		/* [STEP - 14] ================================================
		 * FAULT interrupt - Disabled
		*/
		smb358_set_command(client,
			SMB358_FAULT_INTERRUPT, 0x00);

		/* [STEP - 15] ================================================
		 * STATUS ingerrupt - Clear
		*/
		smb358_set_command(client,
			SMB358_STATUS_INTERRUPT, 0x00);

		/* [STEP - 16] ================================================
		 * Volatile write permission(bit 7) - allowed(1)
		 * Charging Enable(bit 1) - Enabled(1)
		 * STAT Output(bit 0) - Enabled(0)
		*/
#if !defined(CONFIG_MACH_LT02)
		smb358_set_command(client,
			SMB358_COMMAND_A, 0xC2);
#endif
		schedule_delayed_work(&charger->slow_work, 0);
	}
#if 0
#if (defined(CONFIG_MACH_MILLET3G_EUR) || defined(CONFIG_MACH_MATISSE3G_OPEN) || defined(CONFIG_MACH_BERLUTI3G_EUR))
	/* Allow time for AICL to complete */
	msleep(1000);
	smb358_aicl_calibrate(client);
#endif
#endif
}
static void sdchg_exynos7420_cs_use_monitor(void *arg,
					__kernel_time_t curr_sec, bool skip_monitor)
{
	struct sdchg_info_nochip_t *info = sdchg_info->nochip;
	struct sec_battery_info *battery = (struct sec_battery_info *)arg;

	int temperature = 0;
	static int battcond = 0;
	bool need_set_state = false;
	bool need_set_alarm = false;
	int set_alarm_time = 0;

	bool runned_by_sdchg_poll;
#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND
	static bool state_machine_retry = false;
#endif


	/******************************************/
	runned_by_sdchg_poll = sdchg_check_polling_time(curr_sec);

	temperature = battery->temperature;

	if (skip_monitor) {
#ifdef SDCHG_CHECK_TYPE_SOC
		value.intval = SEC_BATTERY_CURRENT_MA;
		psy_do_property(battery->pdata->fuelgauge_name, get,
			POWER_SUPPLY_PROP_CURRENT_NOW, value);
		battcond = value.intval;
#else
		battcond = battery->voltage_now;
#endif
	}
	else {
#ifdef SDCHG_CHECK_TYPE_SOC
		battcond = (short)battery->current_now;
#else
		battcond = (short)battery->voltage_avg;
#endif
	}

	/******************************************/

	if ( temperature >= sdchg_info->temp_start 
			&& battcond >= SDCHG_BATTCOND_START)
	{
		/******************************************/
		if (!info->wake_lock_set) {
			wake_lock(&info->wake_lock);
			info->wake_lock_set = true;
		}
		/******************************************/
		info->need_state = SDCHG_STATE_SET;
	}
	/******************************************/
	else if (temperature <= sdchg_info->temp_end 
			|| battcond <= SDCHG_BATTCOND_END)
	{
		info->need_state = SDCHG_STATE_NONE;
	}
	/******************************************/
	else {
		if (info->need_state != SDCHG_STATE_NONE) {
			info->need_state = SDCHG_STATE_SET;
		}
	}
	/******************************************/
	/****************************************/
	if (info->display_on) {
		if (info->need_state == SDCHG_STATE_SET)
			info->need_state = SDCHG_STATE_SET_DISPLAY_ON;
	}

#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND
	if (info->need_state != SDCHG_STATE_NONE)
		state_machine_retry = false;
#endif

	/****************************************/
	if (info->set_state != info->need_state) {
		need_set_state = true;

		if (info->set_state == SDCHG_STATE_NONE) {	// none -> discharing
			{
				//need_set_alarm = info->state_machine_run = true;
				//set_alarm_time = SDCHG_DISCHARGING_DELAY;
				need_set_alarm = false; // in discharing, according to original monitor work time
				info->state_machine_run = true;
			}
		} else {		// prev : discharging
			if (info->need_state == SDCHG_STATE_NONE) {	// discharging -> none
				if (sdchg_ta_attach(battery) || battcond >= SDCHG_BATTCOND_START) {
					need_set_alarm = info->state_machine_run = true;
					if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY)
						set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL;
					else
						set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT;
#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND
					state_machine_retry = false;
#endif
				} else {
#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND
#ifdef SDCHG_SELF_TEST
					need_set_alarm = info->state_machine_run = true;
					if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY)
						set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; 
					else
						set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT;
#else
					if (state_machine_retry) {
						if (runned_by_sdchg_poll) {
							need_set_alarm = info->state_machine_run = false;
							state_machine_retry = false;							
						} else {
							need_set_alarm = info->state_machine_run = true;
							if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY)
								set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; 
							else
								set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT;
						}
					} else {
						need_set_alarm = info->state_machine_run = true;
						if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY)
							set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; 
						else
							set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT;
						state_machine_retry = true;
					}
#endif	// #ifdef SDCHG_SELF_TEST
#else
					need_set_alarm = info->state_machine_run = false;
#endif	// #ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND
				}
			} else {	// discharging -> discharging
				//need_set_alarm = info->state_machine_run = true;
				//set_alarm_time = SDCHG_DISCHARGING_DELAY;
				need_set_alarm = false; // in discharing, according to original monitor work time
				info->state_machine_run = true;
			}
		}
	}
	/****************************************/
	else {
//KEEP_GOING:
		need_set_state = false;

		if (info->need_state == SDCHG_STATE_NONE) {	// prev : none
			if (sdchg_ta_attach(battery) || battcond >= SDCHG_BATTCOND_START) {
				need_set_alarm = info->state_machine_run = true;
				if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY)
					set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; 
				else
					set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT;
#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND
				state_machine_retry = false;
#endif
			} else {
#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND
#ifdef SDCHG_SELF_TEST
				need_set_alarm = info->state_machine_run = true;
				if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY)
					set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; 
				else
					set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT;
#else
				if (state_machine_retry) {
					if (runned_by_sdchg_poll) {
						need_set_alarm = info->state_machine_run = false;
						state_machine_retry = false;							
					} else {
						need_set_alarm = info->state_machine_run = true;
						if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY)
							set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; 
						else
							set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT;
					}
				} else {
					need_set_alarm = info->state_machine_run = true;
					if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY)
						set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; 
					else
						set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT;
					state_machine_retry = true;
				}
#endif	// #ifdef SDCHG_SELF_TEST

#else
				need_set_alarm = info->state_machine_run = false;
#endif	// #ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND
			}
		} else {		// prev : discharging
			//need_set_alarm = info->state_machine_run = true;
			//set_alarm_time = SDCHG_DISCHARGING_DELAY;
			need_set_alarm = false;	// in discharing, according to original monitor work time
			info->state_machine_run = true;
		}
	}
	/****************************************/
	if (need_set_state) {
		current_source_set(info);
	}

	if (need_set_alarm)
		sdchg_set_polling_time(set_alarm_time);
	else
		sdchg_set_polling_time(0);

#ifdef SDCHG_CHECK_TYPE_SOC
		pr_info("[SDCHG][%s] soc : %d , temp : %d, state : %s\n", 
			__func__, battcond, temperature, sdchg_state_str[info->set_state]);
#else
		pr_info("[SDCHG][%s] volt : %d , temp : %d, state : %s\n", 
			__func__, battcond, temperature, sdchg_state_str[info->set_state]);
#endif

	if (info->set_state == SDCHG_STATE_NONE)
	{
		if (info->wake_lock_set) {
			wake_lock_timeout(&info->wake_lock, HZ * 10);
			wake_unlock(&info->wake_lock);
			info->wake_lock_set = false;
		}
	}

	return;
}
static void sec_chg_isr_work(struct work_struct *work)
{
    struct sec_charger_info *charger =
        container_of(work, struct sec_charger_info, isr_work.work);
    union power_supply_propval val;

    dev_info(&charger->client->dev,
             "%s: Charger Interrupt\n", __func__);

    if (charger->pdata->full_check_type ==
            SEC_BATTERY_FULLCHARGED_CHGINT) {
        if (!sec_hal_chg_get_property(charger->client,
                                      POWER_SUPPLY_PROP_STATUS, &val))
            return;

        switch (val.intval) {
        case POWER_SUPPLY_STATUS_DISCHARGING:
            dev_err(&charger->client->dev,
                    "%s: Interrupted but Discharging\n", __func__);
            break;

        case POWER_SUPPLY_STATUS_NOT_CHARGING:
            dev_err(&charger->client->dev,
                    "%s: Interrupted but NOT Charging\n", __func__);
            break;

        case POWER_SUPPLY_STATUS_FULL:
            dev_info(&charger->client->dev,
                     "%s: Interrupted by Full\n", __func__);
            psy_do_property("battery", set,
                            POWER_SUPPLY_PROP_STATUS, val);
            break;

        case POWER_SUPPLY_STATUS_CHARGING:
            dev_err(&charger->client->dev,
                    "%s: Interrupted but Charging\n", __func__);
            break;

        case POWER_SUPPLY_STATUS_UNKNOWN:
        default:
            dev_err(&charger->client->dev,
                    "%s: Invalid Charger Status\n", __func__);
            break;
        }
    }

    if (charger->pdata->ovp_uvlo_check_type ==
            SEC_BATTERY_OVP_UVLO_CHGINT) {
        if (!sec_hal_chg_get_property(charger->client,
                                      POWER_SUPPLY_PROP_HEALTH, &val))
            return;

        switch (val.intval) {
        case POWER_SUPPLY_HEALTH_OVERHEAT:
        case POWER_SUPPLY_HEALTH_COLD:
            dev_err(&charger->client->dev,
                    "%s: Interrupted but Hot/Cold\n", __func__);
            break;

        case POWER_SUPPLY_HEALTH_DEAD:
            dev_err(&charger->client->dev,
                    "%s: Interrupted but Dead\n", __func__);
            break;

        case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
        case POWER_SUPPLY_HEALTH_UNDERVOLTAGE:
            dev_info(&charger->client->dev,
                     "%s: Interrupted by OVP/UVLO\n", __func__);
            psy_do_property("battery", set,
                            POWER_SUPPLY_PROP_HEALTH, val);
            break;

        case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
            dev_err(&charger->client->dev,
                    "%s: Interrupted but Unspec\n", __func__);
            break;

        case POWER_SUPPLY_HEALTH_GOOD:
            dev_err(&charger->client->dev,
                    "%s: Interrupted but Good\n", __func__);
            break;

        case POWER_SUPPLY_HEALTH_UNKNOWN:
        default:
            dev_err(&charger->client->dev,
                    "%s: Invalid Charger Health\n", __func__);
            break;
        }
    }
}
Exemplo n.º 28
0
static int adc_get_vcell(struct i2c_client *client)
{
	union power_supply_propval cable;
	union power_supply_propval event;
	union power_supply_propval is_charging;
	struct sec_fuelgauge_info *fuelgauge =
				i2c_get_clientdata(client);
	int vcell, vcell_raw;

	vcell = adc_get_data_by_adc(fuelgauge,
		get_battery_data(fuelgauge).adc2vcell_table,
		get_battery_data(fuelgauge).adc2vcell_table_size,
		adc_get_adc_value(fuelgauge, SEC_BAT_ADC_CHANNEL_VOLTAGE_NOW));
	vcell_raw = vcell;

	psy_do_property("battery", get,
		POWER_SUPPLY_PROP_ONLINE, cable);
	/* get current event status */
	event.intval = BATT_EVENT;
	psy_do_property("battery", get,
		POWER_SUPPLY_PROP_TECHNOLOGY, event);
	psy_do_property("battery", get,
		POWER_SUPPLY_PROP_CHARGE_NOW, is_charging);

	if (is_charging.intval != SEC_BATTERY_CHARGING_NONE) {
		/* compensate voltage by cable only in charging status */
		if (cable.intval != POWER_SUPPLY_TYPE_BATTERY)
			vcell += get_cable_compensation_voltage(
				fuelgauge, vcell);
	} else {
		/* need compensation before cable detection
		 * in power-off charging
		 */
		if ((cable.intval == POWER_SUPPLY_TYPE_BATTERY) &&
			(fuelgauge->pdata->is_lpm() ||
			fuelgauge->pdata->check_vbus_status())) {
			dev_dbg(&client->dev, "%s: VBUS compensation\n",
				__func__);
			vcell += get_cable_compensation_voltage(
				fuelgauge, vcell);
		}
	}

	if (event.intval) {
		if (fuelgauge->pdata->check_vbus_status() &&
			(event.intval & EVENT_BOOTING))
			dev_dbg(&client->dev, "%s: no event compensation "
				"in booting with charging\n", __func__);
		else
			vcell += get_event_compensation_voltage(
				fuelgauge, event.intval);
	}

#if defined(SEC_FUELGAUGE_ADC_DELTA_COMPENSATION)
	if (!fuelgauge->pdata->monitor_initial_count)
		vcell += get_delta_compensation_voltage(
			fuelgauge, vcell, vcell_raw);
#endif

	return vcell;
}
Exemplo n.º 29
0
static void smb347_charger_function_control(
				struct i2c_client *client)
{
	struct sec_charger_info *charger = i2c_get_clientdata(client);
	union power_supply_propval val;
	int full_check_type;
	u8 data;

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

	if (charger->cable_type ==
		POWER_SUPPLY_TYPE_BATTERY) {
		/* turn off charger */
		smb347_set_command(client,
			SMB347_COMMAND_A, 0x80);

		/* high current mode for system current */
		smb347_set_command(client,
			SMB347_COMMAND_B, 0x01);
	} else {
		/* Pre-charge curr 250mA */
		dev_dbg(&client->dev,
			"%s : fast charging current (%dmA)\n",
			__func__, charger->charging_current);
		dev_dbg(&client->dev,
			"%s : termination current (%dmA)\n",
			__func__, charger->pdata->charging_current[
			charger->cable_type].full_check_current_1st);
		data = 0x1c;
		data |= smb347_get_fast_charging_current_data(
			charger->charging_current);
		data |= smb347_get_termination_current_limit_data(
			charger->pdata->charging_current[
			charger->cable_type].full_check_current_1st);
		smb347_set_command(client,
			SMB347_CHARGE_CURRENT, data);

		/* Pin enable control */
		/* DCIN Input Pre-bias Enable */
		data = 0x01;
		if (charger->pdata->chg_gpio_en)
			data |= 0x40;
		if (charger->pdata->chg_polarity_en)
			data |= 0x20;
		smb347_set_command(client,
			SMB347_PIN_ENABLE_CONTROL, data);

		/* Input current limit */
		dev_dbg(&client->dev, "%s : input current (%dmA)\n",
			__func__, charger->pdata->charging_current
			[charger->cable_type].input_current_limit);
		data = 0;
		data = smb347_get_input_current_limit_data(
			charger,
			charger->pdata->charging_current
			[charger->cable_type].input_current_limit);
		smb347_set_command(client,
			SMB347_INPUT_CURRENTLIMIT, data);

		/*
		 * Input to System FET by Register
		 * Enable AICL, VCHG
		 * Max System voltage =Vflt + 0.1v
		 * Input Source Priority : USBIN
		 */
		if (charger->pdata->chg_functions_setting &
			SEC_CHARGER_NO_GRADUAL_CHARGING_CURRENT)
			/* disable AICL */
			smb347_set_command(client,
				SMB347_VARIOUS_FUNCTIONS, 0x85);
		else
			/* enable AICL */
			smb347_set_command(client,
				SMB347_VARIOUS_FUNCTIONS, 0x95);

		/* Float voltage, Vprechg : 2.4V */
		dev_dbg(&client->dev, "%s : float voltage (%dmV)\n",
				__func__, charger->pdata->chg_float_voltage);
		data = 0;
		data |= smb347_get_float_voltage_data(
			charger->pdata->chg_float_voltage);
		smb347_set_command(client,
			SMB347_FLOAT_VOLTAGE, data);

		/* Charge control
		 * Automatic Recharge disable,
		 * Current Termination disable,
		 * BMD disable, Recharge Threshold =50mV,
		 * APSD disable */
		data = 0xC0;
		psy_do_property("battery", get,
			POWER_SUPPLY_PROP_CHARGE_NOW, val);
		if (val.intval == SEC_BATTERY_CHARGING_1ST)
			full_check_type = charger->pdata->full_check_type;
		else
			full_check_type = charger->pdata->full_check_type_2nd;
		switch (full_check_type) {
		case SEC_BATTERY_FULLCHARGED_CHGGPIO:
		case SEC_BATTERY_FULLCHARGED_CHGINT:
		case SEC_BATTERY_FULLCHARGED_CHGPSY:
			/* Enable Current Termination */
			data &= 0xBF;
			break;
		}
		smb347_set_command(client,
			SMB347_CHARGE_CONTROL, data);

		/* STAT, Timer control : STAT active low,
		 * Complete time out 1527min.
		 */
		smb347_set_command(client,
			SMB347_STAT_TIMERS_CONTROL, 0x1A);

		/* Pin/Enable
		 * USB 5/1/HC Dual state
		 * DCIN pre-bias Enable
		 */
		smb347_set_command(client,
			SMB347_PIN_ENABLE_CONTROL, 0x09);

		/* Therm control :
		 * Therm monitor disable,
		 * Minimum System Voltage 3.60V
		 */
		smb347_set_command(client,
			SMB347_THERM_CONTROL_A, 0x7F);

		/* USB selection : USB2.0(100mA/500mA),
		 * INOK polarity Active low
		 */
		smb347_set_command(client,
			SMB347_SYSOK_USB30_SELECTION, 0x08);

		/* Other control
		 * Low batt detection disable
		 * Minimum System Voltage 3.60V
		 */
		smb347_set_command(client,
			SMB347_OTHER_CONTROL_A, 0x00);

		/* OTG tlim therm control */
		smb347_set_command(client,
			SMB347_OTG_TLIM_THERM_CONTROL, 0x3F);

		/* Limit cell temperature */
		smb347_set_command(client,
			SMB347_LIMIT_CELL_TEMPERATURE_MONITOR, 0x01);

		/* Fault interrupt : Clear */
		smb347_set_command(client,
			SMB347_FAULT_INTERRUPT, 0x00);

		/* STATUS ingerrupt : Clear */
		smb347_set_command(client,
			SMB347_STATUS_INTERRUPT, 0x00);

		/* turn on charger */
		smb347_set_command(client,
			SMB347_COMMAND_A, 0x82);

		/* HC or USB5 mode */
		switch (charger->cable_type) {
		case POWER_SUPPLY_TYPE_MAINS:
		case POWER_SUPPLY_TYPE_MISC:
			/* High-current mode */
			data = 0x01;
			break;
		case POWER_SUPPLY_TYPE_USB:
		case POWER_SUPPLY_TYPE_USB_DCP:
		case POWER_SUPPLY_TYPE_USB_CDP:
		case POWER_SUPPLY_TYPE_USB_ACA:
			/* USB5 */
			data = 0x02;
			break;
		default:
			/* USB1 */
			data = 0x00;
			break;
		}
		smb347_set_command(client,
			SMB347_COMMAND_B, data);
	}
}
static int sec_bat_get_cable_from_extended_cable_type(
	int input_extended_cable_type)
{
	int cable_main, cable_sub, cable_power;
	int cable_type = POWER_SUPPLY_TYPE_UNKNOWN;

	union power_supply_propval value;

	int charge_current_max = 0, charge_current = 0;

	cable_main = GET_MAIN_CABLE_TYPE(input_extended_cable_type);
	if (cable_main != POWER_SUPPLY_TYPE_UNKNOWN)
		extended_cable_type = (extended_cable_type &
			~(int)ONLINE_TYPE_MAIN_MASK) |
			(cable_main << ONLINE_TYPE_MAIN_SHIFT);
	cable_sub = GET_SUB_CABLE_TYPE(input_extended_cable_type);
	if (cable_sub != ONLINE_SUB_TYPE_UNKNOWN)
		extended_cable_type = (extended_cable_type &
			~(int)ONLINE_TYPE_SUB_MASK) |
			(cable_sub << ONLINE_TYPE_SUB_SHIFT);
	cable_power = GET_POWER_CABLE_TYPE(input_extended_cable_type);
	if (cable_power != ONLINE_POWER_TYPE_UNKNOWN)
		extended_cable_type = (extended_cable_type &
			~(int)ONLINE_TYPE_PWR_MASK) |
			(cable_power << ONLINE_TYPE_PWR_SHIFT);

	switch (cable_main) {
	case POWER_SUPPLY_TYPE_CARDOCK:
		switch (cable_power) {
		case ONLINE_POWER_TYPE_BATTERY:
			cable_type = POWER_SUPPLY_TYPE_BATTERY;
			break;
		case ONLINE_POWER_TYPE_TA:
			switch (cable_sub) {
			case ONLINE_SUB_TYPE_MHL:
				cable_type = POWER_SUPPLY_TYPE_USB;
				break;
			case ONLINE_SUB_TYPE_AUDIO:
			case ONLINE_SUB_TYPE_DESK:
			case ONLINE_SUB_TYPE_SMART_NOTG:
			case ONLINE_SUB_TYPE_KBD:
				cable_type = POWER_SUPPLY_TYPE_MAINS;
				break;
			case ONLINE_SUB_TYPE_SMART_OTG:
				cable_type = POWER_SUPPLY_TYPE_CARDOCK;
				break;
			}
			break;
		case ONLINE_POWER_TYPE_USB:
			cable_type = POWER_SUPPLY_TYPE_USB;
			break;
		default:
			cable_type = current_cable_type;
			break;
		}
		break;
	case POWER_SUPPLY_TYPE_MISC:
		switch (cable_sub) {
		case ONLINE_SUB_TYPE_MHL:
			switch (cable_power) {
			case ONLINE_POWER_TYPE_BATTERY:
				cable_type = POWER_SUPPLY_TYPE_BATTERY;
				break;
			case ONLINE_POWER_TYPE_TA:
				cable_type = POWER_SUPPLY_TYPE_MISC;
				charge_current_max = 700;
				charge_current = 700;
				break;
			case ONLINE_POWER_TYPE_USB:
				cable_type = POWER_SUPPLY_TYPE_USB;
				charge_current_max = 300;
				charge_current = 300;
				break;
			default:
				cable_type = cable_main;
			}
			break;
		default:
			cable_type = cable_main;
			break;
		}
		break;
	default:
		cable_type = cable_main;
		break;
	}


	if (charge_current_max == 0) {
		charge_current_max =
			charging_current_table[cable_type].input_current_limit;
		charge_current =
			charging_current_table[cable_type].
			fast_charging_current;
	}
	value.intval = charge_current_max;
	psy_do_property(sec_battery_pdata.charger_name, set,
			POWER_SUPPLY_PROP_CURRENT_MAX, value);
	value.intval = charge_current;
	psy_do_property(sec_battery_pdata.charger_name, set,
			POWER_SUPPLY_PROP_CURRENT_AVG, value);

	return cable_type;
}