Пример #1
0
static int bq24297_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct bq24297_chip *chip;
	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
	struct device_node *np = client->dev.of_node;
	struct pinctrl *pinctrl;
	int ret = 0;

	dev_info(&client->dev, "%s: addr=0x%x @ IIC%d, irq=%d\n",
			client->name,client->addr,client->adapter->nr,client->irq);

	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))//I2C_FUNC_SMBUS_BYTE
		return -EIO;

	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
	if (!chip)
		return -ENOMEM;
	this_chip = chip;
	chip->client = client;
	i2c_set_clientdata(client, chip);

	of_property_read_u32(np, "debug", &bq24297_dbg);

	ret = bq24297_hw_init();
	if (ret < 0)
	{
		goto err_hw_init;
	}
	bq24297_read_version();

	chip->usb.name		= "usb";
	chip->usb.type		= POWER_SUPPLY_TYPE_USB;
	chip->usb.supplied_to	= supply_to_list;
	chip->usb.num_supplicants = ARRAY_SIZE(supply_to_list);
	chip->usb.get_property	= bq24297_power_get_property;
	chip->usb.properties	= bq24297_power_props;
	chip->usb.num_properties	= ARRAY_SIZE(bq24297_power_props);

	chip->ac.name		= "ac";
	chip->ac.type		= POWER_SUPPLY_TYPE_MAINS;
	chip->ac.supplied_to	= supply_to_list;
	chip->ac.num_supplicants = ARRAY_SIZE(supply_to_list);
	chip->ac.get_property	= bq24297_power_get_property;
	chip->ac.properties	= bq24297_power_props;
	chip->ac.num_properties	= ARRAY_SIZE(bq24297_power_props);

	power_supply_register(&client->dev, &chip->usb);
	power_supply_register(&client->dev, &chip->ac);
	chip->battery = power_supply_get_by_name("battery");

	ret = sysfs_create_group(&client->dev.kobj, &bq24297_attr_group);
	if (ret)
	{
		dev_err(&client->dev, "create sysfs error\n");
		goto err_create_sysfs;
	}

	pinctrl = devm_pinctrl_get_select_default(&client->dev);
	if (IS_ERR(pinctrl))
	{
		dev_err(&client->dev, "pinctrl error\n");
		goto err_pinctrl;
	}

	INIT_DELAYED_WORK(&chip->work_status, bq24297_status_func);

	chip->chg_int_gpio = of_get_named_gpio(np, "bq24297,chg_int", 0);
	chip->chg_int_irq = gpio_to_irq(chip->chg_int_gpio);
	//gpio_set_debounce(chip->chg_int_gpio, 1);// TODO
	ret = request_irq(chip->chg_int_irq, chg_int_func,
			IRQF_TRIGGER_RISING, "chg_int", NULL);
	if (ret)
	{
		dev_err(&client->dev, "request_irq error\n");
		goto err_request_irq;
	}

	return 0;

err_request_irq:
err_pinctrl:
	sysfs_remove_group(&client->dev.kobj, &bq24297_attr_group);
err_create_sysfs:
	power_supply_unregister(&chip->usb);
	power_supply_unregister(&chip->ac);
err_hw_init:
	kfree(chip);
	return ret;	
}
static void sii8240_charger_mhl_cb(bool otg_enable, int charger)
{
	struct sii8240_platform_data *pdata = g_pdata;
	union power_supply_propval value;
	int i, ret = 0;
	struct power_supply *psy;
	pdata->charging_type = POWER_SUPPLY_TYPE_MISC;

	ret = sii8240_muic_get_charging_type();
	if (ret < 0) {
		pr_info("%s: It's not mhl cable type!\n", __func__);
		return;
	}

	pr_info("%s: otg_enable : %d, charger: %d\n", __func__, otg_enable, charger);

	if (charger == 0x00) {
		pr_info("%s() TA charger 500mA\n", __func__);
		pdata->charging_type = POWER_SUPPLY_TYPE_MHL_500;
	} else if (charger == 0x01) {
		pr_info("%s() TA charger 900mA\n", __func__);
		pdata->charging_type = POWER_SUPPLY_TYPE_MHL_900;
	} else if (charger == 0x02) {
		pr_info("%s() TA charger 1500mA\n", __func__);
		pdata->charging_type = POWER_SUPPLY_TYPE_MHL_1500;
	} else if (charger == 0x03) {
		pr_info("%s() USB charger\n", __func__);
		pdata->charging_type = POWER_SUPPLY_TYPE_MHL_USB;
	} else
		pdata->charging_type = POWER_SUPPLY_TYPE_BATTERY;

	if (otg_enable) {
		if (!sii8240_vbus_present()) {
#ifdef CONFIG_SAMSUNG_LPM_MODE
			if (!poweroff_charging) {
#else
			{
#endif
				if (pdata->muic_otg_set)
					pdata->muic_otg_set(true);
				pdata->charging_type = POWER_SUPPLY_TYPE_OTG;
			}
		}
	} else {
		if (pdata->muic_otg_set)
			pdata->muic_otg_set(false);
	}

	for (i = 0; i < 10; i++) {
		psy = power_supply_get_by_name("battery");
		if (psy)
			break;
	}
	if (i == 10) {
		pr_err("[ERROR] %s: fail to get battery ps\n", __func__);
		return;
	}
	value.intval = pdata->charging_type;
	ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &value);
	if (ret) {
		pr_err("[ERROR] %s: fail to set power_suppy ONLINE property(%d)\n",
			__func__, ret);
		return;
	}
}

static void sii8240_int_gpio_config(bool onoff)
{
	struct sii8240_platform_data *pdata = g_pdata;
	int rc = 0;

	if (onoff) {
		rc = gpio_tlmm_config(GPIO_CFG(pdata->gpio_mhl_irq, 0,
				GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
				GPIO_CFG_ENABLE);
	} else {
		rc = gpio_tlmm_config(GPIO_CFG(pdata->gpio_mhl_irq, 0,
				GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
				GPIO_CFG_ENABLE);
	}

	if (rc) {
		pr_err("[ERROR] %s: gpio_tlmm_config(%#x)=%d\n, onoff: %s",
				__func__, pdata->gpio_mhl_irq, rc, onoff ? "on": "off");
	}
}

static void of_sii8240_gpio_init(void)
{
	struct sii8240_platform_data *pdata = g_pdata;
	if (pdata->gpio_mhl_en > 0) {
		if (gpio_request(pdata->gpio_mhl_en, "mhl_en")) {
			pr_err("[ERROR] %s: unable to request gpio_mhl_en [%d]\n",
					__func__, pdata->gpio_mhl_en);
			return;
		}
		if (gpio_direction_output(pdata->gpio_mhl_en, 0)) {
			pr_err("[ERROR] %s: unable to  gpio_mhl_en low[%d]\n",
				__func__, pdata->gpio_mhl_en);
			return;
		}
	}

	if (pdata->gpio_mhl_reset > 0) {
		if (gpio_request(pdata->gpio_mhl_reset, "mhl_reset")) {
			pr_err("[ERROR] %s: unable to request gpio_mhl_reset [%d]\n",
					__func__, pdata->gpio_mhl_reset);
			return;
		}
		if (gpio_direction_output(pdata->gpio_mhl_reset, 0)) {
			pr_err("[ERROR] %s: unable to gpio_mhl_reset low[%d]\n",
				__func__, pdata->gpio_mhl_reset);
			return;
		}
	}

	if (pdata->drm_workaround)
		msm_gpiomux_install(msm_hdmi_ddc_configs, ARRAY_SIZE(msm_hdmi_ddc_configs));
/*
	if(pdata->gpio_barcode_emul) {
		ice_gpiox_get(FPGA_GPIO_MHL_EN);
		ice_gpiox_get(FPGA_GPIO_MHL_RST);
	}*/
}

static void of_sii8240_gpio_config(enum mhl_sleep_state sleep_status)
{
	struct sii8240_platform_data *pdata = g_pdata;
	int ret;

	pr_info("%s() %s - reset_pin_type(%d), en_pin_type(%d)\n", __func__,
		sleep_status ? "resume" : "suspend",
		pdata->gpio_mhl_reset_type, pdata->gpio_mhl_en_type);

	if (pdata->gpio_barcode_emul) {
		gpio_tlmm_config(GPIO_CFG(pdata->gpio_mhl_reset, 0, GPIO_CFG_OUTPUT,
			GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1);
		gpio_tlmm_config(GPIO_CFG(pdata->gpio_mhl_en, 0, GPIO_CFG_INPUT,
			GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), 1);
		return;
	}

	if (sleep_status == MHL_SUSPEND_STATE) {
		if (pdata->gpio_mhl_reset) {
			switch (pdata->gpio_mhl_reset_type) {
			case MHL_GPIO_AP_GPIO:
				gpio_tlmm_config(GPIO_CFG(pdata->gpio_mhl_reset, 0, GPIO_CFG_INPUT,
					GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1);
				break;
			case MHL_GPIO_PM_GPIO:
				ret = qpnp_pin_config(pdata->gpio_mhl_reset, &MHL_PIN_PM_GPIO_MHL_RESET_SLEEP);
				if (unlikely(ret < 0))
					pr_err("[ERROR] %s() set gpio_mhl_reset\n", __func__);
				break;
			case MHL_GPIO_PM_MPP:
				ret = qpnp_pin_config(pdata->gpio_mhl_reset, &MHL_PIN_PM_MPP_SLEEP);
				if (unlikely(ret < 0))
					pr_err("[ERROR] %s() set gpio_mhl_reset\n", __func__);
				break;
			default:
				break;
			}
		} else {
			pr_err("[ERROR] %s() gpio_mhl_reset is NULL\n", __func__);
		}

		if (pdata->gpio_mhl_en) {
			switch (pdata->gpio_mhl_en_type) {
			case MHL_GPIO_AP_GPIO:
				gpio_tlmm_config(GPIO_CFG(pdata->gpio_mhl_en, 0, GPIO_CFG_INPUT,
							GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1);
				break;
			case MHL_GPIO_PM_GPIO:
				ret = qpnp_pin_config(pdata->gpio_mhl_en, &MHL_PIN_PM_GPIO_MHL_EN_SLEEP);
				if (unlikely(ret < 0))
					pr_err("[ERROR] %s() set gpio_mhl_en\n", __func__);
				break;
			case MHL_GPIO_PM_MPP:
				ret = qpnp_pin_config(pdata->gpio_mhl_en, &MHL_PIN_PM_MPP_SLEEP);
				if (unlikely(ret < 0))
					pr_err("[ERROR] %s() set gpio_mhl_en\n", __func__);
				break;
			default:
				break;
			}
		} else {
			pr_err("[ERROR] %s() gpio_mhl_en is NULL\n", __func__);
		}

	/* suspend */
	} else if (sleep_status == MHL_RESUME_STATE) {

		if (pdata->gpio_mhl_reset) {
			switch (pdata->gpio_mhl_reset_type) {
			case MHL_GPIO_AP_GPIO:
				gpio_tlmm_config(GPIO_CFG(pdata->gpio_mhl_reset, 0, GPIO_CFG_OUTPUT,
					GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1);
				break;
			case MHL_GPIO_PM_GPIO:
				ret = qpnp_pin_config(pdata->gpio_mhl_reset, &MHL_PIN_PM_GPIO_WAKE);
				if (unlikely(ret < 0))
					pr_err("[ERROR] %s() set gpio_mhl_reset\n", __func__);
				break;
			case MHL_GPIO_PM_MPP:
				ret = qpnp_pin_config(pdata->gpio_mhl_reset, &MHL_PIN_PM_MPP_WAKE);
				if (unlikely(ret < 0))
					pr_err("[ERROR] %s() set gpio_mhl_reset\n", __func__);
				break;
			default:
				break;
			}
		} else {
			pr_err("[ERROR] %s() gpio_mhl_reset is NULL\n", __func__);
		}

		if (pdata->gpio_mhl_en) {
			switch (pdata->gpio_mhl_en_type) {
			case MHL_GPIO_AP_GPIO:
				gpio_tlmm_config(GPIO_CFG(pdata->gpio_mhl_en, 0, GPIO_CFG_OUTPUT,
					GPIO_CFG_NO_PULL, GPIO_CFG_2MA), 1);
				break;
			case MHL_GPIO_PM_GPIO:
				ret = qpnp_pin_config(pdata->gpio_mhl_en, &MHL_PIN_PM_GPIO_WAKE);
				if (unlikely(ret < 0))
					pr_err("[ERROR] %s() set gpio_mhl_en\n", __func__);
				break;
			case MHL_GPIO_PM_MPP:
				ret = qpnp_pin_config(pdata->gpio_mhl_en, &MHL_PIN_PM_MPP_WAKE);
				if (unlikely(ret < 0))
					pr_err("[ERROR] %s() set gpio_mhl_en\n", __func__);
				break;
			default:
				break;
			}
		} else {
			pr_err("[ERROR] %s() gpio_mhl_en is NULL\n", __func__);
		}
	}
}

static void of_sii8240_hw_onoff(bool onoff)
{
	int ret;
	struct sii8240_platform_data *pdata = g_pdata;
	pr_info("%s: Onoff: %d\n", __func__, onoff);
	if (mhl_power_on == onoff) {
		pr_info("sii8240 : MHL power is already %d\n", onoff);
		return;
	}
	mhl_power_on = onoff;
	if (onoff) {
		/*
		if(pdata->gpio_barcode_emul)
			ice_gpiox_set(FPGA_GPIO_MHL_EN, onoff);
			*/

		if (pdata->gpio_mhl_en > 0)
			gpio_set_value_cansleep(pdata->gpio_mhl_en, onoff);

		if (pdata->vcc_1p2v) {
			ret = regulator_set_voltage(pdata->vcc_1p2v, 1200000, 1200000);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc_1p2v set_vtg failed rc\n");
				return;
			}

			ret = regulator_enable(pdata->vcc_1p2v);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc_1p2v enable failed rc\n");
				return;
			}
		}

		if (pdata->vcc_1p8v) {
			ret = regulator_set_voltage(pdata->vcc_1p8v, 1800000, 1800000);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc 1p8v set_vtg failed rc\n");
				goto err_regulator_1p8v;
			}

			ret = regulator_enable(pdata->vcc_1p8v);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc 1p8v enable failed rc\n");
				goto err_regulator_1p8v;
			}
		}

		if (pdata->vcc_3p3v) {
			ret = regulator_set_voltage(pdata->vcc_3p3v, 3300000, 3300000);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc_3p3v set_vtg failed rc\n");
				goto err_regulator_3p3v;
			}

			ret = regulator_enable(pdata->vcc_3p3v);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc_3p3v enable failed rc\n");
				goto err_regulator_3p3v;
			}
		}

	} else {
		/*
		if(pdata->gpio_barcode_emul)
			ice_gpiox_set(FPGA_GPIO_MHL_EN, onoff);
			*/

		if (pdata->gpio_mhl_en > 0)
			gpio_set_value_cansleep(pdata->gpio_mhl_en, onoff);

		if (pdata->vcc_1p2v) {
			ret = regulator_disable(pdata->vcc_1p2v);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc_1p2v disable failed rc\n");
				return;
			}
		}

		if (pdata->vcc_1p8v) {
			ret = regulator_disable(pdata->vcc_1p8v);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc_1p8v disable failed rc\n");
				return;
			}
		}

		if (pdata->vcc_3p3v) {
			ret = regulator_disable(pdata->vcc_3p3v);
			if (unlikely(ret < 0)) {
				pr_err("[ERROR] regulator vcc_3pv3 disable failed rc\n");
				return;
			}
		}

		usleep_range(10000, 20000);

		if (pdata->gpio_mhl_reset > 0)
			gpio_set_value_cansleep(pdata->gpio_mhl_reset, 0);
	}

	return;

err_regulator_3p3v:
	if (pdata->vcc_1p8v)
		regulator_disable(pdata->vcc_1p8v);
err_regulator_1p8v:
	if (pdata->vcc_1p2v)
		regulator_disable(pdata->vcc_1p2v);
}
static int set_charging_fsm(struct pm860x_charger_info *info)
{
	struct power_supply *psy;
	union power_supply_propval data;
	unsigned char fsm_state[][16] = { "init", "discharge", "precharge",
		"fastcharge",
	};
	int ret;
	int vbatt;

	psy = power_supply_get_by_name(pm860x_supplied_to[0]);
	if (!psy)
		return -EINVAL;
	ret = psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &data);
	if (ret)
		return ret;
	vbatt = data.intval / 1000;

	ret = psy->get_property(psy, POWER_SUPPLY_PROP_PRESENT, &data);
	if (ret)
		return ret;

	mutex_lock(&info->lock);
	info->present = data.intval;

	dev_dbg(info->dev, "Entering FSM:%s, Charger:%s, Battery:%s, "
		"Allowed:%d\n",
		&fsm_state[info->state][0],
		(info->online) ? "online" : "N/A",
		(info->present) ? "present" : "N/A", info->allowed);
	dev_dbg(info->dev, "set_charging_fsm:vbatt:%d(mV)\n", vbatt);

	switch (info->state) {
	case FSM_INIT:
		if (info->online && info->present && info->allowed) {
			if (vbatt < PRECHARGE_THRESHOLD) {
				info->state = FSM_PRECHARGE;
				start_precharge(info);
			} else if (vbatt > DISCHARGE_THRESHOLD) {
				info->state = FSM_DISCHARGE;
				stop_charge(info, vbatt);
			} else if (vbatt < DISCHARGE_THRESHOLD) {
				info->state = FSM_FASTCHARGE;
				start_fastcharge(info);
			}
		} else {
			if (vbatt < POWEROFF_THRESHOLD) {
				power_off_notification(info);
			} else {
				info->state = FSM_DISCHARGE;
				stop_charge(info, vbatt);
			}
		}
		break;
	case FSM_PRECHARGE:
		if (info->online && info->present && info->allowed) {
			if (vbatt > PRECHARGE_THRESHOLD) {
				info->state = FSM_FASTCHARGE;
				start_fastcharge(info);
			}
		} else {
			info->state = FSM_DISCHARGE;
			stop_charge(info, vbatt);
		}
		break;
	case FSM_FASTCHARGE:
		if (info->online && info->present && info->allowed) {
			if (vbatt < PRECHARGE_THRESHOLD) {
				info->state = FSM_PRECHARGE;
				start_precharge(info);
			}
		} else {
			info->state = FSM_DISCHARGE;
			stop_charge(info, vbatt);
		}
		break;
	case FSM_DISCHARGE:
		if (info->online && info->present && info->allowed) {
			if (vbatt < PRECHARGE_THRESHOLD) {
				info->state = FSM_PRECHARGE;
				start_precharge(info);
			} else if (vbatt < DISCHARGE_THRESHOLD) {
				info->state = FSM_FASTCHARGE;
				start_fastcharge(info);
			}
		} else {
			if (vbatt < POWEROFF_THRESHOLD)
				power_off_notification(info);
			else if (vbatt > CHARGE_THRESHOLD && info->online)
				set_vbatt_threshold(info, CHARGE_THRESHOLD, 0);
		}
		break;
	default:
		dev_warn(info->dev, "FSM meets wrong state:%d\n",
			 info->state);
		break;
	}
	dev_dbg(info->dev,
		"Out FSM:%s, Charger:%s, Battery:%s, Allowed:%d\n",
		&fsm_state[info->state][0],
		(info->online) ? "online" : "N/A",
		(info->present) ? "present" : "N/A", info->allowed);
	mutex_unlock(&info->lock);

	return 0;
}
Пример #4
0
int max77803_muic_charger_cb(enum cable_type_muic cable_type)
{
	struct power_supply *psy = power_supply_get_by_name("battery");
	struct power_supply *psy_p = power_supply_get_by_name("ps");
	union power_supply_propval value;
	static enum cable_type_muic previous_cable_type = CABLE_TYPE_NONE_MUIC;

	pr_info("[BATT] CB enabled(%d), prev_cable(%d)\n", cable_type, previous_cable_type);

	/* others setting */
	switch (cable_type) {
	case CABLE_TYPE_NONE_MUIC:
	case CABLE_TYPE_OTG_MUIC:
	case CABLE_TYPE_JIG_UART_OFF_MUIC:
	case CABLE_TYPE_MHL_MUIC:
	case CABLE_TYPE_DESKDOCK_MUIC:
	case CABLE_TYPE_PS_CABLE_MUIC:
		is_cable_attached = false;
		break;
	case CABLE_TYPE_USB_MUIC:
	case CABLE_TYPE_JIG_USB_OFF_MUIC:
	case CABLE_TYPE_JIG_USB_ON_MUIC:
	case CABLE_TYPE_SMARTDOCK_USB_MUIC:
		is_cable_attached = true;
		break;
	case CABLE_TYPE_MHL_VB_MUIC:
		is_cable_attached = true;
		break;
	case CABLE_TYPE_TA_MUIC:
	case CABLE_TYPE_LANHUB_MUIC:
	case CABLE_TYPE_CARDOCK_MUIC:
	case CABLE_TYPE_DESKDOCK_TA_MUIC:
	case CABLE_TYPE_SMARTDOCK_MUIC:
	case CABLE_TYPE_SMARTDOCK_TA_MUIC:
	case CABLE_TYPE_AUDIODOCK_MUIC:
	case CABLE_TYPE_JIG_UART_OFF_VB_MUIC:
	case CABLE_TYPE_CDP_MUIC:
	case CABLE_TYPE_MMDOCK_MUIC:
	case CABLE_TYPE_UNSUPPORTED_ID_VB_MUIC:
		is_cable_attached = true;
		break;
	default:
		pr_err("%s: invalid type:%d\n", __func__, cable_type);
		return -EINVAL;
	}

#ifdef SYNAPTICS_RMI_INFORM_CHARGER
#if defined(CONFIG_V2A)
	if (0x6 <= system_rev)
		tsp_charger_infom(is_cable_attached);
	else
#endif
	synaptics_tsp_charger_infom(cable_type);
#elif defined(CONFIG_V1A) || defined(CONFIG_V2A) \
		|| defined(CONFIG_N1A) || defined(CONFIG_N2A)\
		|| defined(CONFIG_KLIMT)
	tsp_charger_infom(is_cable_attached);
#endif
#if defined(CONFIG_MACH_JA)
	touchkey_charger_infom(is_cable_attached);
#endif
#if defined(CONFIG_KLIMT) && defined(TK_INFORM_CHARGER)
	touchkey_charger_infom(is_cable_attached);
#endif

	/*  charger setting */
	if (previous_cable_type == cable_type) {
		pr_info("%s: SKIP cable setting\n", __func__);
		goto skip_cable_setting;
	}

	switch (cable_type) {
	case CABLE_TYPE_NONE_MUIC:
	case CABLE_TYPE_JIG_UART_OFF_MUIC:
	case CABLE_TYPE_DESKDOCK_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_BATTERY;
		break;
	case CABLE_TYPE_MHL_VB_MUIC:
		if (lpcharge)
			current_cable_type = POWER_SUPPLY_TYPE_USB;
		else
			goto skip;
		break;
	case CABLE_TYPE_MHL_MUIC:
		if (lpcharge) {
			current_cable_type = POWER_SUPPLY_TYPE_BATTERY;
		} else {
			goto skip;
		}
		break;
	case CABLE_TYPE_OTG_MUIC:
		goto skip;
	case CABLE_TYPE_USB_MUIC:
	case CABLE_TYPE_JIG_USB_OFF_MUIC:
	case CABLE_TYPE_JIG_USB_ON_MUIC:
	case CABLE_TYPE_SMARTDOCK_USB_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_USB;
		break;
	case CABLE_TYPE_JIG_UART_OFF_VB_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_UARTOFF;
		break;
	case CABLE_TYPE_TA_MUIC:
	case CABLE_TYPE_CARDOCK_MUIC:
	case CABLE_TYPE_DESKDOCK_TA_MUIC:
	case CABLE_TYPE_SMARTDOCK_MUIC:
	case CABLE_TYPE_SMARTDOCK_TA_MUIC:
	case CABLE_TYPE_UNSUPPORTED_ID_VB_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_MAINS;
		break;
	case CABLE_TYPE_AUDIODOCK_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_MISC;
		break;
	case CABLE_TYPE_CDP_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_USB_CDP;
		break;
	case CABLE_TYPE_LANHUB_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_LAN_HUB;
		break;
	case CABLE_TYPE_PS_CABLE_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_POWER_SHARING;
		break;
	case CABLE_TYPE_MMDOCK_MUIC:
		return 0;
	default:
		pr_err("%s: invalid type for charger:%d\n",
			__func__, cable_type);
		goto skip;
	}

	if (!psy || !psy->set_property || !psy_p || !psy_p->set_property) {
		pr_err("%s: fail to get battery/ps psy\n", __func__);
	} else {
		if (current_cable_type == POWER_SUPPLY_TYPE_POWER_SHARING) {
			value.intval = current_cable_type;
			psy_p->set_property(psy_p, POWER_SUPPLY_PROP_ONLINE, &value);
		} else {
			if (previous_cable_type == CABLE_TYPE_PS_CABLE_MUIC) {
				value.intval = current_cable_type;
				psy_p->set_property(psy_p, POWER_SUPPLY_PROP_ONLINE, &value);
			}
			value.intval = current_cable_type<<ONLINE_TYPE_MAIN_SHIFT;
			psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &value);
		}
	}
skip:
	previous_cable_type = cable_type;
skip_cable_setting:
#ifdef CONFIG_JACK_MON
	jack_event_handler("charger", is_cable_attached);
#endif

	return 0;
}
static int bq27541_soc_calibrate(struct bq27541_device_info *di, int soc)
{
    union power_supply_propval ret = {0,};
    unsigned int soc_calib;
    int counter_temp = 0;

    if (!di->batt_psy) {
        di->batt_psy = power_supply_get_by_name("battery");
        di->soc_pre = soc;
    }
    if (di->batt_psy) {
        di->batt_psy->get_property(di->batt_psy,POWER_SUPPLY_PROP_STATUS, &ret);

        if (ret.intval == POWER_SUPPLY_STATUS_CHARGING || ret.intval == POWER_SUPPLY_STATUS_FULL) { // is charging
            if (abs(soc - di->soc_pre) >= 2) {
                di->saltate_counter++;
                if(di->saltate_counter < CAPACITY_SALTATE_COUNTER)
                    return di->soc_pre;
                else
                    di->saltate_counter = 0;
            } else
                di->saltate_counter = 0;

            if (soc > di->soc_pre)
                soc_calib = di->soc_pre + 1;
            else if (soc < (di->soc_pre - 2))
                soc_calib = di->soc_pre - 1;
            else
                soc_calib = di->soc_pre;

            /* [email protected], 2013/12/12  Add for set capacity to 100 when full in normal temp */
            if (ret.intval == POWER_SUPPLY_STATUS_FULL) {
                if (soc > 94) {
                    soc_calib = 100;
                }
            }
        } else {
            // not charging
            if ((abs(soc - di->soc_pre) >= 2) || (di->soc_pre > 80)) {
                di->saltate_counter++;
                if (di->soc_pre == 100) {
                    counter_temp = CAPACITY_SALTATE_COUNTER_FULL;//6
                } else if (di->soc_pre > 95) {
                    counter_temp = CAPACITY_SALTATE_COUNTER_95;//3
                } else if (di->soc_pre > 90) {
                    counter_temp = CAPACITY_SALTATE_COUNTER_90;//2
                } else if (di->soc_pre > 80) {
                    counter_temp = CAPACITY_SALTATE_COUNTER_80;//1.5
                } else {
                    counter_temp = CAPACITY_SALTATE_COUNTER_NOT_CHARGING;//1
                }
                if(di->saltate_counter < counter_temp)
                    return di->soc_pre;
                else
                    di->saltate_counter = 0;
            }
            else
                di->saltate_counter = 0;

            if (soc < di->soc_pre)
                soc_calib = di->soc_pre - 1;
            else
                soc_calib = di->soc_pre;
        }
    } else {
        soc_calib = soc;
    }
    if (soc >= 100)
        soc_calib = 100;
    di->soc_pre = soc_calib;
    return soc_calib;
}
void sec_charger_cb(u8 cable_type)
{
	union power_supply_propval value;
	struct power_supply *psy = power_supply_get_by_name("battery");
    pr_info("%s: cable type (0x%02x)\n", __func__, cable_type);
	attached_cable = cable_type;

	switch (cable_type) {
	case MUIC_RT8973_CABLE_TYPE_NONE:
	case MUIC_RT8973_CABLE_TYPE_UNKNOWN:
		current_cable_type = POWER_SUPPLY_TYPE_BATTERY;
		break;
	case MUIC_RT8973_CABLE_TYPE_USB:
	case MUIC_RT8973_CABLE_TYPE_CDP:
	case MUIC_RT8973_CABLE_TYPE_LG_SPEC_USB:
		current_cable_type = POWER_SUPPLY_TYPE_USB;
		break;
	case MUIC_RT8973_CABLE_TYPE_REGULAR_TA:
		current_cable_type = POWER_SUPPLY_TYPE_MAINS;
		break;
	case MUIC_RT8973_CABLE_TYPE_OTG:
		goto skip;
	case MUIC_RT8973_CABLE_TYPE_JIG_UART_OFF_WITH_VBUS:
		current_cable_type = POWER_SUPPLY_TYPE_UARTOFF;
		break;
	case MUIC_RT8973_CABLE_TYPE_JIG_UART_OFF:
	/*
		if (!gpio_get_value(mfp_to_gpio(GPIO008_GPIO_8))) {
			pr_info("%s cable type POWER_SUPPLY_TYPE_UARTOFF\n", __func__);
			current_cable_type = POWER_SUPPLY_TYPE_UARTOFF;
		}
		else {
		current_cable_type = POWER_SUPPLY_TYPE_BATTERY;
		}*/
		current_cable_type = POWER_SUPPLY_TYPE_BATTERY;

		break;
	case MUIC_RT8973_CABLE_TYPE_JIG_USB_ON:
	case MUIC_RT8973_CABLE_TYPE_JIG_USB_OFF:
		current_cable_type = POWER_SUPPLY_TYPE_USB;
		break;
	case MUIC_RT8973_CABLE_TYPE_0x1A:
	case MUIC_RT8973_CABLE_TYPE_TYPE1_CHARGER:
		current_cable_type = POWER_SUPPLY_TYPE_MAINS;
		break;
	case MUIC_RT8973_CABLE_TYPE_0x15:
		current_cable_type = POWER_SUPPLY_TYPE_MISC;
		break;
	default:
		pr_err("%s: invalid type for charger:%d\n",
			__func__, cable_type);
		current_cable_type = POWER_SUPPLY_TYPE_UNKNOWN;
		goto skip;
	}

	if (!psy || !psy->set_property)
		pr_err("%s: fail to get battery psy\n", __func__);
	else {
		value.intval = current_cable_type;
		psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &value);
	}

	if (current_cable_type == POWER_SUPPLY_TYPE_USB) {
		epmic_event_handler(1);
	}
skip:
	return;
}
struct device_node *of_batterydata_get_best_profile(
		const struct device_node *batterydata_container_node,
		const char *psy_name,  const char  *batt_type)
{
	struct batt_ids batt_ids;
	struct device_node *node, *best_node = NULL;
	struct power_supply *psy;
	const char *battery_type = NULL;
	union power_supply_propval ret = {0, };
	int delta = 0, best_delta = 0, best_id_kohm = 0, id_range_pct,
		batt_id_kohm = 0, i = 0, rc = 0;

	psy = power_supply_get_by_name(psy_name);
	if (!psy) {
		pr_err("%s supply not found. defer\n", psy_name);
		return ERR_PTR(-EPROBE_DEFER);
	}

	rc = psy->get_property(psy, POWER_SUPPLY_PROP_RESISTANCE_ID, &ret);
	if (rc) {
		pr_err("failed to retrieve resistance value rc=%d\n", rc);
		return ERR_PTR(-ENOSYS);
	}

	batt_id_kohm = ret.intval / 1000;

	/*
	 * Find the battery data with a battery id resistor closest to this one
	 */
	for_each_child_of_node(batterydata_container_node, node) {
		if (batt_type != NULL) {
			rc = of_property_read_string(node, "qcom,battery-type",
							&battery_type);
			if (!rc && strcmp(battery_type, batt_type) == 0) {
				best_node = node;
				best_id_kohm = batt_id_kohm;
				break;
			}
		} else {
			rc = of_batterydata_read_batt_id_kohm(node,
							"qcom,batt-id-kohm",
							&batt_ids);
			if (rc)
				continue;
			for (i = 0; i < batt_ids.num; i++) {
				delta = abs(batt_ids.kohm[i] - batt_id_kohm);
				if (delta < best_delta || !best_node) {
					best_node = node;
					best_delta = delta;
					best_id_kohm = batt_ids.kohm[i];
				}
			}
		}
	}

	if (best_node == NULL) {
		pr_err("No battery data found\n");
		return best_node;
	}

	/* read battery id value for best profile */
	rc = of_property_read_u32(batterydata_container_node,
			"qcom,batt-id-range-pct", &id_range_pct);
	if (!rc) {
		/* check that profile id is in range of the measured batt_id */
		if (abs(best_id_kohm - batt_id_kohm) >
				((best_id_kohm * id_range_pct) / 100)) {
			pr_err("out of range: profile id %d batt id %d pct %d",
				best_id_kohm, batt_id_kohm, id_range_pct);
			return NULL;
		}
	} else if (rc == -EINVAL) {
		rc = 0;
	} else {
		pr_err("failed to read battery id range\n");
		return ERR_PTR(-ENXIO);
	}

	rc = of_property_read_string(best_node, "qcom,battery-type",
							&battery_type);
	if (!rc)
		pr_info("%s found\n", battery_type);
	else
		pr_info("%s found\n", best_node->name);

	return best_node;
}
Пример #8
0
/*
 * Every sampling_rate, we check, if current idle time is less than 20%
 * (default), then we try to increase frequency. Every sampling_rate, we look
 * for the lowest frequency which can sustain the load while keeping idle time
 * over 30%. If such a frequency exist, we try to decrease to this frequency.
 *
 * Any frequency increase takes it to the maximum frequency. Frequency reduction
 * happens at minimum steps of 5% (default) of current frequency
 */
static void od_check_cpu(int cpu, unsigned int load_freq)
{
	struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
	struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
	struct dbs_data *dbs_data = policy->governor_data;
	struct od_dbs_tuners *od_tuners = dbs_data->tuners;
	char name[]= "BAT0";
	int bat_current = 0;
	int bat_capacity = 0;
	int bat_percentage =0;
	int ac_status=0;
	int bat_status=0;
	struct power_supply *psy = power_supply_get_by_name(name);
	union power_supply_propval chargenow, chargecapacity, batstatus;
	dbs_info->freq_lo = 0;	
	bat_capacity = psy->get_property(psy,POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,&chargecapacity);
	bat_current = psy->get_property(psy,POWER_SUPPLY_PROP_CHARGE_NOW,&chargenow);
	bat_status = psy->get_property(psy,POWER_SUPPLY_PROP_STATUS,&batstatus);
	ac_status = batstatus.intval;
	bat_percentage=(chargenow.intval*100)/chargecapacity.intval;
	printk(KERN_INFO "*****************%d*********************",ac_status);
	if(bat_percentage<DEF_BATTERY_THRESHOLD&&(!(ac_status==4||ac_status==1))){ 
		if(bat_prev-bat_percentage>=2){
			bat_prev=bat_percentage;
			target_freq=max(policy->min,((policy->max-policy->min)*bat_percentage)/100);
		}
		printk(KERN_INFO "policy->curr::  %d target_freq:: %d load_freq:: %d \n",policy->cur,target_freq,load_freq);
		if(bat_flag==0){
			bat_flag=1;
			bat_sampling_rate=od_tuners->sampling_rate;
		}
		if(hist_counter==10){
			hist_counter=0;		
		}
		freq_history[hist_counter]=policy->cur;
		hist_counter=hist_counter+1;
		his_flag=1;
		his_flag=freq_history[0]^freq_history[1]^freq_history[2]^freq_history[3]^freq_history[4]^freq_history[5]^freq_history[6]^freq_history[7]^freq_history[8]^freq_history[9];
		//use a low cost methord ie xor
		/*for(hist_loop_cntr=0;hist_loop_cntr<10;hist_loop_cntr++){
			printk(KERN_INFO "%d_%d\n",hist_loop_cntr,freq_history[hist_loop_cntr]);
			if(freq_history[hist_loop_cntr]!=freq_history[0]){
				if(od_tuners->sampling_rate==bat_sampling_rate)
					break;
				printk(KERN_INFO "Reseted sampling to::: %d",od_tuners->sampling_rate);
				his_flag=1;	
				break;		
			}
		}*/
		if((his_flag==0)&&(od_tuners->sampling_rate==bat_sampling_rate)){
			od_tuners->sampling_rate=od_tuners->sampling_rate*11;
			printk(KERN_INFO "changed sampling to::: %d",od_tuners->sampling_rate);
		}
		else if(his_flag!=0){
			if(od_tuners->sampling_rate!=bat_sampling_rate){
				od_tuners->sampling_rate=bat_sampling_rate;
				printk(KERN_INFO "Reseted sampling to::: %d",od_tuners->sampling_rate);
				his_flag=1;	
			}
		}
		if (load_freq > od_tuners->up_threshold *policy->cur) {
			freq_down_counter=1;
			if (policy->cur < policy->max)
				dbs_info->rate_mult = od_tuners->sampling_down_factor;
			target_freq=target_freq+(freq_up_counter*10000);
			printk(KERN_INFO "load is gr8r upcounter  %d target %d\n",freq_up_counter,target_freq);
			freq_up_counter++;

		}
		else if(load_freq < od_tuners->adj_up_threshold* policy->cur){
			freq_up_counter=0;
			target_freq=target_freq-((freq_down_counter-1)*10000);
			printk(KERN_INFO "load is less downcr  %d target %d adj_up %d \n",freq_down_counter,target_freq,od_tuners->adj_up_threshold);
			freq_down_counter=freq_down_counter*2;
		}
		printk(KERN_INFO "Battery <95 Target freq %d load freq %d threshold %d\n",target_freq,load_freq,od_tuners->up_threshold);
		__cpufreq_driver_target(policy, target_freq, CPUFREQ_RELATION_L);
		if(target_freq<=policy->min){
			freq_down_counter=1;
			target_freq=policy->cur;
		}
		if(target_freq>=policy->max){
			freq_up_counter=0;
			target_freq=policy->cur;
		}
		return;
	}
	if(bat_flag==1){
		bat_flag=0;	
		freq_up_counter=0;
		freq_down_counter=1;
		bat_prev=105;
		hist_counter=0;
		od_tuners->sampling_rate=bat_sampling_rate;
	}
	/* Check for frequency increase */
	if (load_freq > od_tuners->up_threshold * policy->cur) {
		/* If switching to max speed, apply sampling_down_factor */
		if (policy->cur < policy->max)
			dbs_info->rate_mult =
				od_tuners->sampling_down_factor;
		dbs_freq_increase(policy, policy->max);
		return;
	}

	/* Check for frequency decrease */
	/* if we cannot reduce the frequency anymore, break out early */
	if (policy->cur == policy->min)
		return;

	/*
	 * The optimal frequency is the frequency that is the lowest that can
	 * support the current CPU usage without triggering the up policy. To be
	 * safe, we focus 10 points under the threshold.
	 */
	if (load_freq < od_tuners->adj_up_threshold
			* policy->cur) {
		unsigned int freq_next;
		freq_next = load_freq / od_tuners->adj_up_threshold;

		/* No longer fully busy, reset rate_mult */
		dbs_info->rate_mult = 1;

		if (freq_next < policy->min)
			freq_next = policy->min;

		if (!od_tuners->powersave_bias) {
			__cpufreq_driver_target(policy, freq_next,
					CPUFREQ_RELATION_L);
			return;
		}

		freq_next = od_ops.powersave_bias_target(policy, freq_next,
					CPUFREQ_RELATION_L);
		__cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
	}
}
Пример #9
0
static int max17048_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct max17048_chip *chip;
	int ret;
	uint16_t version;

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

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

	if (!i2c_check_functionality(client->adapter,
				I2C_FUNC_SMBUS_WORD_DATA)) {
		pr_err("%s: i2c_check_functionality fail\n", __func__);
		return -EIO;
	}

	chip->client = client;
	chip->ac_psy = power_supply_get_by_name("ac");
	if (!chip->ac_psy) {
		pr_err("ac supply not found deferring probe\n");
		ret = -EPROBE_DEFER;
		goto error;
	}

	if (&client->dev.of_node) {
		ret = max17048_parse_dt(&client->dev, chip);
		if (ret) {
			pr_err("%s: failed to parse dt\n", __func__);
			goto  error;
		}
	} else {
		chip->pdata = client->dev.platform_data;
	}

	i2c_set_clientdata(client, chip);

	version = max17048_get_version(chip);
	dev_info(&client->dev, "MAX17048 Fuel-Gauge Ver 0x%x\n", version);
	if (version != MAX17048_VERSION_11 &&
	    version != MAX17048_VERSION_12) {
		pr_err("%s: Not supported version: 0x%x\n", __func__,
				version);
		ret = -ENODEV;
		goto error;
	}

	init_completion(&monitor_work_done);
	chip->capacity_level = -EINVAL;
	ref = chip;
	chip->batt_psy.name = "battery";
	chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
	chip->batt_psy.get_property = max17048_get_property;
	chip->batt_psy.properties = max17048_battery_props;
	chip->batt_psy.num_properties = ARRAY_SIZE(max17048_battery_props);
	chip->batt_psy.external_power_changed =
				max17048_external_power_changed;

	ret = power_supply_register(&client->dev, &chip->batt_psy);
	if (ret) {
		dev_err(&client->dev, "failed: power supply register\n");
		goto error;
	}

	INIT_DELAYED_WORK(&chip->monitor_work, max17048_work);
	wake_lock_init(&chip->alert_lock, WAKE_LOCK_SUSPEND,
			"max17048_alert");

	ret = gpio_request_one(chip->alert_gpio, GPIOF_DIR_IN,
				"max17048_alert");
	if (ret) {
		pr_err("%s: GPIO Request Failed : return %d\n",
				__func__, ret);
		goto err_gpio_request;
	}

	chip->alert_irq = gpio_to_irq(chip->alert_gpio);
	if (chip->alert_irq < 0) {
		pr_err("%s: failed to get alert irq\n", __func__);
		goto err_request_irq;
	}

	ret = request_threaded_irq(chip->alert_irq, NULL,
				max17048_interrupt_handler,
				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
				"MAX17048_Alert", chip);
	if (ret) {
		pr_err("%s: IRQ Request Failed : return %d\n",
				__func__, ret);
		goto err_request_irq;
	}

	ret = enable_irq_wake(chip->alert_irq);
	if (ret) {
		pr_err("%s: set irq to wakeup source failed.\n", __func__);
		goto err_request_wakeup_irq;
	}

	disable_irq(chip->alert_irq);

	ret = device_create_file(&client->dev, &dev_attr_fuelrst);
	if (ret) {
		pr_err("%s: fuelrst creation failed: %d\n", __func__, ret);
		ret = -ENODEV;
		goto err_create_file_fuelrst;
	}

	ret = max17048_create_debugfs_entries(chip);
	if (ret) {
		pr_err("max17048_create_debugfs_entries failed\n");
		goto err_create_debugfs;
	}

	ret = max17048_hw_init(chip);
	if (ret) {
		pr_err("%s: failed to init hw.\n", __func__);
		goto err_hw_init;
	}

	chip->pm_notifier.notifier_call = max17048_pm_notifier;
	ret = register_pm_notifier(&chip->pm_notifier);
	if (ret) {
		pr_err("%s: failed to register pm notifier\n", __func__);
		goto err_hw_init;
	}

	schedule_delayed_work(&chip->monitor_work, 0);
	enable_irq(chip->alert_irq);

	pr_info("%s: done\n", __func__);
	return 0;

err_hw_init:
	debugfs_remove_recursive(chip->dent);
err_create_debugfs:
	device_remove_file(&client->dev, &dev_attr_fuelrst);
err_create_file_fuelrst:
	disable_irq_wake(chip->alert_irq);
err_request_wakeup_irq:
	free_irq(chip->alert_irq, NULL);
err_request_irq:
	gpio_free(chip->alert_gpio);
err_gpio_request:
	wake_lock_destroy(&chip->alert_lock);
	power_supply_unregister(&chip->batt_psy);
error:
	ref = NULL;
	kfree(chip);
	return ret;
}
static __devinit int samsung_battery_probe(struct platform_device *pdev)
{
	struct battery_info *info;
	int ret = 0;
	char *temper_src_name[] = { "fuelgauge", "ap adc",
		"ext adc", "unknown"
	};
	pr_info("%s: SAMSUNG Battery Driver Loading\n", __func__);

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

	platform_set_drvdata(pdev, info);

	info->dev = &pdev->dev;
	info->pdata = pdev->dev.platform_data;

	/* Check charger name and fuelgauge name. */
	if (!info->pdata->charger_name || !info->pdata->fuelgauge_name) {
		pr_err("%s: no charger or fuel gauge name\n", __func__);
		goto err_kfree;
	}
	info->charger_name = info->pdata->charger_name;
	info->fuelgauge_name = info->pdata->fuelgauge_name;

	pr_info("%s: Charger name: %s\n", __func__, info->charger_name);
	pr_info("%s: Fuelgauge name: %s\n", __func__, info->fuelgauge_name);

	info->psy_charger = power_supply_get_by_name(info->charger_name);
	info->psy_fuelgauge = power_supply_get_by_name(info->fuelgauge_name);

	if (!info->psy_charger || !info->psy_fuelgauge) {
		pr_err("%s: fail to get power supply\n", __func__);
		goto err_kfree;
	}

	info->use_sub_charger = info->pdata->use_sub_charger;
	if (info->use_sub_charger) {
		info->sub_charger_name = info->pdata->sub_charger_name;
		pr_info("%s: subcharger name: %s\n", __func__,
			info->sub_charger_name);
		info->psy_sub_charger = power_supply_get_by_name(info->sub_charger_name);

		if (!info->psy_sub_charger) {
			pr_err("%s fail to get sub charger\n", __func__);
			goto err_kfree;
		}
	}
	/* force set S2PLUS recharge voltage */
	info->pdata->recharge_voltage = 4150;

	pr_info("%s: Temperature source: %s\n", __func__,
		temper_src_name[info->pdata->temper_src]);
	pr_info("%s: Recharge voltage: %d\n", __func__,
				info->pdata->recharge_voltage);

#if defined(CONFIG_S3C_ADC)
	info->adc_client = s3c_adc_register(pdev, NULL, NULL, 0);
#endif

	/* init battery info */
	info->full_charged_state = false;
	info->abstimer_state = false;
	info->recharge_phase = false;
	info->siop_charge_current = CHARGER_USB_CURRENT;
	info->monitor_mode = MONITOR_NORM;

	/* LPM charging state */
	info->lpm_state = lpcharge;

	wake_lock_init(&info->monitor_wake_lock, WAKE_LOCK_SUSPEND,
		       "battery-monitor");
	wake_lock_init(&info->emer_wake_lock, WAKE_LOCK_SUSPEND,
		       "battery-emergency");
	if (!info->pdata->suspend_chging)
		wake_lock_init(&info->charge_wake_lock,
			       WAKE_LOCK_SUSPEND, "battery-charging");

	/* Init wq for battery */
	INIT_WORK(&info->error_work, battery_error_work);
	INIT_WORK(&info->monitor_work, battery_monitor_work);

	/* Init Power supply class */
	info->psy_bat.name = "battery";
	info->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY;
	info->psy_bat.properties = samsung_battery_props;
	info->psy_bat.num_properties = ARRAY_SIZE(samsung_battery_props);
	info->psy_bat.get_property = samsung_battery_get_property;
	info->psy_bat.set_property = samsung_battery_set_property;

	info->psy_usb.name = "usb";
	info->psy_usb.type = POWER_SUPPLY_TYPE_USB;
	info->psy_usb.supplied_to = supply_list;
	info->psy_usb.num_supplicants = ARRAY_SIZE(supply_list);
	info->psy_usb.properties = samsung_power_props;
	info->psy_usb.num_properties = ARRAY_SIZE(samsung_power_props);
	info->psy_usb.get_property = samsung_usb_get_property;

	info->psy_ac.name = "ac";
	info->psy_ac.type = POWER_SUPPLY_TYPE_MAINS;
	info->psy_ac.supplied_to = supply_list;
	info->psy_ac.num_supplicants = ARRAY_SIZE(supply_list);
	info->psy_ac.properties = samsung_power_props;
	info->psy_ac.num_properties = ARRAY_SIZE(samsung_power_props);
	info->psy_ac.get_property = samsung_ac_get_property;

	ret = power_supply_register(&pdev->dev, &info->psy_bat);
	if (ret) {
		pr_err("%s: failed to register psy_bat\n", __func__);
		goto err_psy_reg_bat;
	}

	ret = power_supply_register(&pdev->dev, &info->psy_usb);
	if (ret) {
		pr_err("%s: failed to register psy_usb\n", __func__);
		goto err_psy_reg_usb;
	}

	ret = power_supply_register(&pdev->dev, &info->psy_ac);
	if (ret) {
		pr_err("%s: failed to register psy_ac\n", __func__);
		goto err_psy_reg_ac;
	}

	/* Using android alarm for gauging instead of workqueue */
	info->last_poll = alarm_get_elapsed_realtime();
	alarm_init(&info->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
		   samsung_battery_alarm_start);

	/* update battery init status */
	schedule_work(&info->monitor_work);

	/* Create samsung detail attributes */
	battery_create_attrs(info->psy_bat.dev);

	pr_info("%s: SAMSUNG Battery Driver Loaded\n", __func__);
	return 0;

 err_psy_reg_ac:
	power_supply_unregister(&info->psy_usb);
 err_psy_reg_usb:
	power_supply_unregister(&info->psy_bat);
 err_psy_reg_bat:
	wake_lock_destroy(&info->monitor_wake_lock);
	wake_lock_destroy(&info->emer_wake_lock);
	if (!info->pdata->suspend_chging)
		wake_lock_destroy(&info->charge_wake_lock);
 err_kfree:
	kfree(info);

	return ret;
}
Пример #11
0
static void max77665_poll_work_func(struct work_struct *work)
{
	struct max77665_charger *charger =
		container_of(work, struct max77665_charger, poll_dwork.work);
	struct power_supply *fuelgauge_ps
		= power_supply_get_by_name("fuelgauge");
	union power_supply_propval val;
	int battery_health = POWER_SUPPLY_HEALTH_GOOD;


	mutex_lock(&charger->mutex_t);
	
	if (fuelgauge_ps)
		if(fuelgauge_ps->get_property(fuelgauge_ps, POWER_SUPPLY_PROP_HEALTH, &val) == 0)
			battery_health = val.intval;

	if (charger->chg_status == CHG_STATUS_FAST ||
			charger->chg_status == CHG_STATUS_RECHG) {
		struct i2c_client *i2c = charger->iodev->i2c;
		u8 reg_data;

		if(max77665_read_reg(i2c, MAX77665_CHG_REG_CHG_DETAILS_01, &reg_data) >= 0) {
			if((reg_data & 0x0F) == 0x04) {
				charger->chg_status = CHG_STATUS_DONE;
			}
		}
	}

	if ( charger->cable_status == CABLE_TYPE_USB ||
			charger->cable_status == CABLE_TYPE_AC) {

		if(battery_health != POWER_SUPPLY_HEALTH_GOOD) {
			if (regulator_is_enabled(charger->ps)) {
				printk("----------battery unhealthy, disable charging\n");
				regulator_disable(charger->ps);
			}
		} else {
			if (regulator_is_enabled(charger->ps)) {
				if (charger->chg_status == CHG_STATUS_DONE && fuelgauge_ps) {
					int soc = 100;
					if(fuelgauge_ps->get_property(fuelgauge_ps, POWER_SUPPLY_PROP_CAPACITY, &val) == 0)
						soc = val.intval;
					if(soc <= 98) {
						regulator_disable(charger->ps);
						msleep(500);
						regulator_enable(charger->ps);
						charger->chg_status = CHG_STATUS_RECHG;
					}
				}
			} else {
				printk("----------battery healthy good, enable charging\n");
				regulator_enable(charger->ps);
			}
		}

		schedule_delayed_work_on(0, &charger->poll_dwork, TEMP_CHECK_DELAY);
	} else {
		if (regulator_is_enabled(charger->ps)) {
			printk("--------------charger remove, disable charging\n");
			regulator_disable(charger->ps);
		}
	}
	mutex_unlock(&charger->mutex_t);
}
Пример #12
0
static int sec_bat_enable_charging_sub(struct sec_bat_info *info, bool enable)
{
	struct power_supply *psy_main =
	    power_supply_get_by_name(info->charger_name);
	struct power_supply *psy_sub =
	    power_supply_get_by_name(info->sub_charger_name);
	union power_supply_propval val_type, val_chg_current;
	int ret;

	if (!psy_main || !psy_sub) {
		dev_err(info->dev, "%s: fail to get charger ps\n", __func__);
		return -ENODEV;
	}

	info->batt_full_status = BATT_NOT_FULL;

	if (enable) {		/* Enable charging */
		val_type.intval = POWER_SUPPLY_STATUS_DISCHARGING;
		ret = psy_main->set_property(psy_main, POWER_SUPPLY_PROP_STATUS,
					     &val_type);
		if (ret) {
			dev_err(info->dev, "%s: fail to set charging"
				" status-main(%d)\n", __func__, ret);
			return ret;
		}

		switch (info->cable_type) {
		case CABLE_TYPE_USB:
			val_type.intval = POWER_SUPPLY_STATUS_CHARGING;
			val_chg_current.intval = 450;	/* mA */
			break;
		case CABLE_TYPE_AC:
			val_type.intval = POWER_SUPPLY_STATUS_CHARGING;
			val_chg_current.intval = 650;	/* mA */
			break;
		case CABLE_TYPE_MISC:
			val_type.intval = POWER_SUPPLY_STATUS_CHARGING;
			val_chg_current.intval = 550;	/* mA */
			break;
		default:
			dev_err(info->dev, "%s: Invalid func use\n", __func__);
			return -EINVAL;
		}

		/* Set charging current */
		ret = psy_sub->set_property(psy_sub,
					    POWER_SUPPLY_PROP_CURRENT_NOW,
					    &val_chg_current);
		if (ret) {
			dev_err(info->dev, "%s: fail to set charging cur(%d)\n",
				__func__, ret);
			return ret;
		}

		/*Reset charging start time only in initial charging start */
		if (info->charging_start_time == 0) {
			info->charging_start_time = jiffies;
			info->charging_next_time = RESETTING_CHG_TIME;
		}
	} else {		/* Disable charging */
		val_type.intval = POWER_SUPPLY_STATUS_DISCHARGING;
		ret = psy_main->set_property(psy_main, POWER_SUPPLY_PROP_STATUS,
					     &val_type);
		if (ret) {
			dev_err(info->dev, "%s: fail to set charging"
				" status-main(%d)\n", __func__, ret);
			return ret;
		}

		info->charging_start_time = 0;
		info->charging_passed_time = 0;
		info->charging_next_time = 0;
	}

	ret = psy_sub->set_property(psy_sub, POWER_SUPPLY_PROP_STATUS,
				    &val_type);
	if (ret) {
		dev_err(info->dev, "%s: fail to set charging status(%d)\n",
			__func__, ret);
		return ret;
	}

	return 0;
}
Пример #13
0
static int sec_bat_check_temper(struct sec_bat_info *info)
{
	struct power_supply *psy
	    = power_supply_get_by_name(info->fuel_gauge_name);
	union power_supply_propval value;
	int ret;

	int temp;
	int temp_adc = s3c_read_temper_adc(info);
	int health = info->batt_health;
	int low = 0;
	int high = 0;
	int mid = 0;

	calculate_average_adc(info, &info->temper_adc_sample, temp_adc);

	if (!info->adc_table || !info->adc_arr_size) {
		/* using fake temp */
		temp = 300;
		info->batt_temp = temp;
		return temp;
	}
	high = info->adc_arr_size - 1;

	while (low <= high) {
		mid = (low + high) / 2;
		if (info->adc_table[mid].adc > temp_adc)
			high = mid - 1;
		else if (info->adc_table[mid].adc < temp_adc)
			low = mid + 1;
		else
			break;
	}
	temp = info->adc_table[mid].temperature;

	info->batt_temp = temp;

	if (temp >= HIGH_BLOCK_TEMP) {
		if (health != POWER_SUPPLY_HEALTH_OVERHEAT &&
		    health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE)
			if (info->batt_temp_high_cnt < TEMP_BLOCK_COUNT)
				info->batt_temp_high_cnt++;
			dev_info(info->dev, "%s: high count = %d\n",
				__func__, info->batt_temp_high_cnt);
	} else if (temp <= HIGH_RECOVER_TEMP && temp >= LOW_RECOVER_TEMP) {
		if (health == POWER_SUPPLY_HEALTH_OVERHEAT ||
		    health == POWER_SUPPLY_HEALTH_COLD)
			if (info->batt_temp_recover_cnt < TEMP_BLOCK_COUNT)
				info->batt_temp_recover_cnt++;
			dev_info(info->dev, "%s: recovery count = %d\n",
				__func__, info->batt_temp_recover_cnt);
	} else if (temp <= LOW_BLOCK_TEMP) {
		if (health != POWER_SUPPLY_HEALTH_COLD &&
		    health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE)
			if (info->batt_temp_low_cnt < TEMP_BLOCK_COUNT)
				info->batt_temp_low_cnt++;
			dev_info(info->dev, "%s: low count = %d\n",
				__func__, info->batt_temp_low_cnt);
	} else {
		info->batt_temp_high_cnt = 0;
		info->batt_temp_low_cnt = 0;
		info->batt_temp_recover_cnt = 0;
	}

	if (info->batt_temp_high_cnt >= TEMP_BLOCK_COUNT)
		info->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
	else if (info->batt_temp_low_cnt >= TEMP_BLOCK_COUNT)
		info->batt_health = POWER_SUPPLY_HEALTH_COLD;
	else if (info->batt_temp_recover_cnt >= TEMP_BLOCK_COUNT)
		info->batt_health = POWER_SUPPLY_HEALTH_GOOD;

	/* Set temperature to fuel gauge */
	if (info->fuel_gauge_name) {
		value.intval = info->batt_temp / 10;
		ret = psy->set_property(psy, POWER_SUPPLY_PROP_TEMP, &value);
		if (ret) {
			dev_err(info->dev, "%s: fail to set temperature(%d)\n",
				__func__, ret);
		}
	}

	dev_info(info->dev, "%s: temp=%d, adc=%d\n", __func__, temp, temp_adc);

	return temp;
}
Пример #14
0
static int sec_bat_set_property(struct power_supply *ps,
				enum power_supply_property psp,
				const union power_supply_propval *val)
{
	struct sec_bat_info *info = container_of(ps, struct sec_bat_info,
						 psy_bat);
	struct power_supply *psy = power_supply_get_by_name(info->charger_name);
	union power_supply_propval value;

	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		dev_info(info->dev, "%s: topoff intr\n", __func__);
		if (val->intval != POWER_SUPPLY_STATUS_FULL)
			return -EINVAL;

		if (info->use_sub_charger) {
			if (info->cable_type == CABLE_TYPE_USB ||
					info->cable_type == CABLE_TYPE_MISC)
				sec_bat_handle_charger_topoff(info);
			break;
		}

		if (info->batt_full_status == BATT_NOT_FULL) {
			info->recharging_status = false;
			info->batt_full_status = BATT_FULL;
			info->charging_status = POWER_SUPPLY_STATUS_FULL;

			info->charging_start_time = 0;
			info->charging_passed_time = 0;
			info->charging_next_time = 0;

			/* disable charging */
			value.intval = POWER_SUPPLY_STATUS_DISCHARGING;
			psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
					  &value);
		}
#if 0				/* for reference */
		if (info->batt_full_status == BATT_NOT_FULL) {
			info->batt_full_status = BATT_1ST_FULL;
			info->charging_status = POWER_SUPPLY_STATUS_FULL;
			/* TODO: set topoff current 60mA */
			value.intval = 120;
			psy->set_property(psy, POWER_SUPPLY_PROP_CHARGE_FULL,
					  &value);
		} else {
			info->batt_full_status = BATT_2ND_FULL;
			info->recharging_status = false;
			/* disable charging */
			value.intval = POWER_SUPPLY_STATUS_DISCHARGING;
			psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
					  &value);
		}
#endif
		break;
	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
		/* TODO: lowbatt interrupt: called by fuel gauge */
		dev_info(info->dev, "%s: lowbatt intr\n", __func__);
		if (val->intval != POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL)
			return -EINVAL;
		wake_lock(&info->monitor_wake_lock);
		queue_work(info->monitor_wqueue, &info->monitor_work);

		break;
	case POWER_SUPPLY_PROP_ONLINE:
		/* cable is attached or detached. called by USB switch(MUIC) */
		dev_info(info->dev, "%s: cable was changed(%d)\n", __func__,
			 val->intval);
		switch (val->intval) {
		case POWER_SUPPLY_TYPE_BATTERY:
			info->cable_type = CABLE_TYPE_NONE;
			break;
		case POWER_SUPPLY_TYPE_MAINS:
			info->cable_type = CABLE_TYPE_AC;
			break;
		case POWER_SUPPLY_TYPE_USB:
			info->cable_type = CABLE_TYPE_USB;
			break;
		case POWER_SUPPLY_TYPE_MISC:
			info->cable_type = CABLE_TYPE_MISC;
			break;
		default:
			return -EINVAL;
		}
		wake_lock(&info->cable_wake_lock);
		queue_work(info->monitor_wqueue, &info->cable_work);
		break;
	case POWER_SUPPLY_PROP_HEALTH:
		/* call by TMU driver
		  * alarm for abnormal temperature increasement
		  */
		info->batt_tmu_status = val->intval;

		wake_lock(&info->monitor_wake_lock);
		queue_work(info->monitor_wqueue, &info->monitor_work);

		dev_info(info->dev, "%s: TMU status has been changed(%d)\n",
			__func__, info->batt_tmu_status);

		break;
	default:
		return -EINVAL;
	}
	return 0;
}
static int qpnp_usbdetect_probe(struct platform_device *pdev)
{
	struct qpnp_usbdetect *usb;
	struct power_supply *usb_psy;
	int rc, vbus;
	unsigned long flags;

	usb_psy = power_supply_get_by_name("usb");
	if (!usb_psy) {
		dev_dbg(&pdev->dev, "USB power_supply not found, deferring probe\n");
		return -EPROBE_DEFER;
	}

	usb = devm_kzalloc(&pdev->dev, sizeof(*usb), GFP_KERNEL);
	if (!usb)
		return -ENOMEM;

	usb->pdev = pdev;
	usb->usb_psy = usb_psy;

	if (of_get_property(pdev->dev.of_node, "vin-supply", NULL)) {
		usb->vin = devm_regulator_get(&pdev->dev, "vin");
		if (IS_ERR(usb->vin)) {
			dev_err(&pdev->dev, "Failed to get VIN regulator: %ld\n",
				PTR_ERR(usb->vin));
			return PTR_ERR(usb->vin);
		}
	}

	if (usb->vin) {
		rc = regulator_enable(usb->vin);
		if (rc) {
			dev_err(&pdev->dev, "Failed to enable VIN regulator: %d\n",
				rc);
			return rc;
		}
	}

	usb->vbus_det_irq = platform_get_irq_byname(pdev, "vbus_det_irq");
	if (usb->vbus_det_irq < 0) {
		if (usb->vin)
			regulator_disable(usb->vin);
		return usb->vbus_det_irq;
	}

	rc = devm_request_irq(&pdev->dev, usb->vbus_det_irq,
			      qpnp_usbdetect_vbus_irq,
			      IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
			      "vbus_det_irq", usb);
	if (rc) {
		dev_err(&pdev->dev, "request for vbus_det_irq failed: %d\n",
			rc);
		if (usb->vin)
			regulator_disable(usb->vin);
		return rc;
	}

	enable_irq_wake(usb->vbus_det_irq);
	dev_set_drvdata(&pdev->dev, usb);

	/* Read and report initial VBUS state */
	local_irq_save(flags);
	vbus = !!irq_read_line(usb->vbus_det_irq);
	local_irq_restore(flags);

	power_supply_set_present(usb->usb_psy, vbus);

	return 0;
}
Пример #16
0
static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA)
{
	static int power_supply_type;
	struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);
#if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM)
	static bool chglogo_check = false;
#endif

	if (!dotg->psy || !dotg->charger) {
		dev_err(phy->dev, "no usb power supply/charger registered\n");
		return 0;
	}

	if (dotg->charger->charging_disabled)
		return 0;

#ifdef CONFIG_LGE_PM
	if (dotg->charger->chg_type == DWC3_SDP_CHARGER ||
			dotg->charger->chg_type == DWC3_FLOATED_CHARGER)
#else
	if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
#endif
		power_supply_type = POWER_SUPPLY_TYPE_USB;
	else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_CDP;
	else if (dotg->charger->chg_type == DWC3_DCP_CHARGER ||
			dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
	else
#ifdef CONFIG_LGE_PM
		/* [email protected]
		 * healthd get battery psy type at init only.
		 * If cable detach before healthd init,
		 * healthd recognize usb psy as battery type.
		 */
		power_supply_type = POWER_SUPPLY_TYPE_UNKNOWN;
#else
		power_supply_type = POWER_SUPPLY_TYPE_BATTERY;
#endif

#ifndef CONFIG_LGE_PM
	power_supply_set_supply_type(dotg->psy, power_supply_type);
#endif

#if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)
	update_status(1, dotg->charger->chg_type);
#endif

#if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM)
	if (!chglogo_check && lge_get_boot_mode() == LGE_BOOT_MODE_CHARGERLOGO &&
			dotg->charger->chg_type == DWC3_SDP_CHARGER) {
		if (mA > IUNIT)
			chglogo_check = true;
		else if (mA <= 2) {
			dotg->charger->max_power = mA;
			return 0;
		}
	}

	if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) {
		if (dotg->charger->chg_type == DWC3_DCP_CHARGER)
			mA = lge_pm_get_ta_current();
	}
#elif defined(CONFIG_LGE_PM)
	if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) {
		if (dotg->charger->chg_type == DWC3_SDP_CHARGER) {
			if (dotg->dwc->gadget.speed == USB_SPEED_SUPER) {
				if (dotg->charger->max_power > 2)
					dotg->charger->max_power = 0;
				mA = DWC3_USB30_CHG_CURRENT;
			} else {
				mA = lge_pm_get_usb_current();
			}
#ifdef CONFIG_QPNP_CHARGER
			/* For MST, boost current up over 900mA in spite of USB */
			if (pseudo_batt_info.mode && mA == 500 )
				mA = DWC3_USB30_CHG_CURRENT;
#endif
		} else if (dotg->charger->chg_type == DWC3_DCP_CHARGER) {
			mA = lge_pm_get_ta_current();
		} else if (dotg->charger->chg_type == DWC3_FLOATED_CHARGER) {
			mA = lge_pm_get_usb_current();
		}
	}
#endif

	if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		mA = DWC3_IDEV_CHG_MAX;

	if (dotg->charger->max_power == mA)
		return 0;

	dev_info(phy->dev, "Avail curr from USB = %u\n", mA);

/* [email protected] make psy getter and move it above power_supply_type setter. 2014-02-06 */
#ifdef CONFIG_LGE_PM
#ifndef CONFIG_USB_DWC3_LGE_SINGLE_PSY
	if (dwc3_otg_get_psy(phy) < 0)
		goto psy_error;
#else
	if (strcmp(dotg->psy->name, "usb")) {
		pr_info("%s psy name is %s, so change psy to usb.\n", __func__, dotg->psy->name);
		dotg->psy = power_supply_get_by_name("usb");
		if (!dotg->psy)
			goto psy_error;
	}
#endif
	power_supply_set_supply_type(dotg->psy, power_supply_type);
#endif

	if (dotg->charger->max_power <= 2 && mA > 2) {
		/* Enable charging */
		if (power_supply_set_online(dotg->psy, true))
			goto psy_error;
		if (power_supply_set_current_limit(dotg->psy, 1000*mA))
			goto psy_error;
#ifdef CONFIG_QPNP_CHARGER
		if (!strncmp(dotg->psy->name, "ac", 2)) {
			dotg->psy = power_supply_get_by_name("usb");
			if (!dotg->psy)
				goto psy_error;

			if (power_supply_set_online(dotg->psy, true))
				goto psy_error;

			if (power_supply_set_supply_type(dotg->psy, power_supply_type))
				goto psy_error;

			if (power_supply_set_current_limit(dotg->psy, 1000*mA))
				goto psy_error;

			dotg->psy = power_supply_get_by_name("ac");
			if (!dotg->psy)
				goto psy_error;
		}
#endif
	} else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) {
		/* Disable charging */
		if (power_supply_set_online(dotg->psy, false))
			goto psy_error;
		/* Set max current limit */
		if (power_supply_set_current_limit(dotg->psy, 0))
			goto psy_error;

#ifdef CONFIG_QPNP_CHARGER
		if (!strncmp(dotg->psy->name, "ac", 2)) {
			dotg->psy = power_supply_get_by_name("usb");
			if (!dotg->psy)
				goto psy_error;

			if (power_supply_set_online(dotg->psy, false))
				goto psy_error;

			if (power_supply_set_supply_type(dotg->psy, power_supply_type))
				goto psy_error;

			if (power_supply_set_current_limit(dotg->psy, 0))
				goto psy_error;

			dotg->psy = power_supply_get_by_name("ac");
			if (!dotg->psy)
				goto psy_error;
		}
#endif
	}

	power_supply_changed(dotg->psy);

	dotg->charger->max_power = mA;

	return 0;

psy_error:
	dev_dbg(phy->dev, "power supply error when setting property\n");
	return -ENXIO;
}
Пример #17
0
static void olpc_xo175_ec_complete(void *arg)
{
	struct olpc_xo175_ec *priv = arg;
	struct device *dev = &priv->spi->dev;
	struct power_supply *psy;
	unsigned long flags;
	u8 channel;
	u8 byte;
	int ret;

	ret = priv->msg.status;
	if (ret) {
		dev_err(dev, "SPI transfer failed: %d\n", ret);

		spin_lock_irqsave(&priv->cmd_state_lock, flags);
		if (priv->cmd_running) {
			priv->resp_len = 0;
			priv->cmd_state = CMD_STATE_ERROR_RECEIVED;
			complete(&priv->cmd_done);
		}
		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);

		if (ret != -EINTR)
			olpc_xo175_ec_read_packet(priv);

		return;
	}

	channel = priv->rx_buf.resp.channel;
	byte = priv->rx_buf.resp.byte;

	switch (channel) {
	case CHAN_NONE:
		spin_lock_irqsave(&priv->cmd_state_lock, flags);

		if (!priv->cmd_running) {
			/* We can safely ignore these */
			dev_err(dev, "spurious FIFO read packet\n");
			spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
			return;
		}

		priv->cmd_state = CMD_STATE_CMD_SENT;
		if (!priv->expected_resp_len)
			complete(&priv->cmd_done);
		olpc_xo175_ec_read_packet(priv);

		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
		return;

	case CHAN_SWITCH:
		spin_lock_irqsave(&priv->cmd_state_lock, flags);

		if (!priv->cmd_running) {
			/* Just go with the flow */
			dev_err(dev, "spurious SWITCH packet\n");
			memset(&priv->cmd, 0, sizeof(priv->cmd));
			priv->cmd.command = CMD_ECHO;
		}

		priv->cmd_state = CMD_STATE_CMD_IN_TX_FIFO;

		/* Throw command into TxFIFO */
		gpiod_set_value_cansleep(priv->gpio_cmd, 0);
		olpc_xo175_ec_send_command(priv, &priv->cmd, sizeof(priv->cmd));

		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
		return;

	case CHAN_CMD_RESP:
		spin_lock_irqsave(&priv->cmd_state_lock, flags);

		if (!priv->cmd_running) {
			dev_err(dev, "spurious response packet\n");
		} else if (priv->resp_len >= priv->expected_resp_len) {
			dev_err(dev, "too many response packets\n");
		} else {
			priv->resp_data[priv->resp_len++] = byte;
			if (priv->resp_len == priv->expected_resp_len) {
				priv->cmd_state = CMD_STATE_RESP_RECEIVED;
				complete(&priv->cmd_done);
			}
		}

		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
		break;

	case CHAN_CMD_ERROR:
		spin_lock_irqsave(&priv->cmd_state_lock, flags);

		if (!priv->cmd_running) {
			dev_err(dev, "spurious cmd error packet\n");
		} else {
			priv->resp_data[0] = byte;
			priv->resp_len = 1;
			priv->cmd_state = CMD_STATE_ERROR_RECEIVED;
			complete(&priv->cmd_done);
		}
		spin_unlock_irqrestore(&priv->cmd_state_lock, flags);
		break;

	case CHAN_KEYBOARD:
		dev_warn(dev, "keyboard is not supported\n");
		break;

	case CHAN_TOUCHPAD:
		dev_warn(dev, "touchpad is not supported\n");
		break;

	case CHAN_EVENT:
		dev_dbg(dev, "got event %.2x\n", byte);
		switch (byte) {
		case EVENT_AC_CHANGE:
			psy = power_supply_get_by_name("olpc-ac");
			if (psy) {
				power_supply_changed(psy);
				power_supply_put(psy);
			}
			break;
		case EVENT_BATTERY_STATUS:
		case EVENT_BATTERY_CRITICAL:
		case EVENT_BATTERY_SOC_CHANGE:
		case EVENT_BATTERY_ERROR:
			psy = power_supply_get_by_name("olpc-battery");
			if (psy) {
				power_supply_changed(psy);
				power_supply_put(psy);
			}
			break;
		case EVENT_POWER_PRESSED:
			input_report_key(priv->pwrbtn, KEY_POWER, 1);
			input_sync(priv->pwrbtn);
			input_report_key(priv->pwrbtn, KEY_POWER, 0);
			input_sync(priv->pwrbtn);
			/* fall through */
		case EVENT_POWER_PRESS_WAKE:
		case EVENT_TIMED_HOST_WAKE:
			pm_wakeup_event(priv->pwrbtn->dev.parent,
						PM_WAKEUP_TIME);
			break;
		default:
			dev_dbg(dev, "ignored unknown event %.2x\n", byte);
			break;
		}
		break;

	case CHAN_DEBUG:
		if (byte == '\n') {
			olpc_xo175_ec_flush_logbuf(priv);
		} else if (isprint(byte)) {
			priv->logbuf[priv->logbuf_len++] = byte;
			if (priv->logbuf_len == LOG_BUF_SIZE)
				olpc_xo175_ec_flush_logbuf(priv);
		}
		break;

	default:
		dev_warn(dev, "unknown channel: %d, %.2x\n", channel, byte);
		break;
	}

	/* Most non-command packets get the TxFIFO refilled and an ACK. */
	olpc_xo175_ec_read_packet(priv);
}
Пример #18
0
void sm5504_lanhub_callback(enum cable_type_t cable_type, int attached, bool lanhub_ta)
{
	union power_supply_propval value;
	struct power_supply *psy;
	int i, ret = 0;

	pr_info("SM5504 Lanhub Callback called, cable %d, attached %d, TA: %s \n",
				cable_type,attached,(lanhub_ta ? "Yes":"No"));
	if(lanhub_ta)
		set_cable_status = attached ? CABLE_TYPE_LANHUB : POWER_SUPPLY_TYPE_OTG;
	else
		set_cable_status = attached ? CABLE_TYPE_LANHUB : CABLE_TYPE_NONE;

	pr_info("%s:sm5504 cable type : %d", __func__, set_cable_status);

	for (i = 0; i < 10; i++) {
		psy = power_supply_get_by_name("battery");
		if (psy)
			break;
	}

	if (i == 10) {
		pr_err("%s: fail to get battery ps\n", __func__);
		return;
	}

	if (!psy || !psy->set_property)
                pr_err("%s: fail to set battery psy\n", __func__);
        else {
		switch (set_cable_status) {
		case CABLE_TYPE_LANHUB:
			value.intval = POWER_SUPPLY_TYPE_LAN_HUB;
			break;
	        case POWER_SUPPLY_TYPE_OTG:
	        case CABLE_TYPE_NONE:
			value.intval = lanhub_ta ? POWER_SUPPLY_TYPE_OTG : POWER_SUPPLY_TYPE_BATTERY;
			break;
		default:
	                pr_err("%s invalid status:%d\n", __func__,attached);
	                return;
		}

	        ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &value);
		if (ret) {
			pr_err("%s: fail to set power_suppy ONLINE property(%d)\n",
				__func__, ret);
	        }

	}

#ifdef CONFIG_USB_HOST_NOTIFY
	if (attached){
		if(lanhub_ta) {
			pr_info("USB Host HNOTIFY LANHUB_N_TA_ON\n");
		}
		else{
			pr_info("USB Host HNOTIFY_LANHUB_ON\n");
			//sec_otg_notify(HNOTIFY_LANHUB_ON);
		}
	}else{
		if(lanhub_ta) {
                        pr_info("USB Host HNOTIFY LANHUB ON\n");
                }
                else{
			pr_info("USB Host HNOTIFY_LANHUB_OFF");
			//sec_otg_notify(HNOTIFY_LANHUB_OFF);
		}
	}
#endif

}
Пример #19
0
static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA)
{
	static int power_supply_type;
	struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);

	if (!dotg->psy || !dotg->charger) {
		dev_err(phy->dev, "no usb power supply/charger registered\n");
		return 0;
	}

	if (dotg->charger->charging_disabled)
		return 0;

#ifdef CONFIG_LGE_PM
	if (dotg->charger->chg_type == DWC3_SDP_CHARGER ||
			dotg->charger->chg_type == DWC3_FLOATED_CHARGER)
#else
	if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
#endif
		power_supply_type = POWER_SUPPLY_TYPE_USB;
	else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_CDP;
	else if (dotg->charger->chg_type == DWC3_DCP_CHARGER ||
			dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
	else
		power_supply_type = POWER_SUPPLY_TYPE_UNKNOWN;

#ifndef CONFIG_LGE_PM
	power_supply_set_supply_type(dotg->psy, power_supply_type);
#endif

#if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_G3) && defined (CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)
	update_status(1, dotg->charger->chg_type);
#endif

#if defined (CONFIG_TOUCHSCREEN_ATMEL_2954) || defined(CONFIG_TOUCHSCREEN_ATMEL_mxT2954)
	pr_info("%s : chg_type is %d. previous_usb_status is %d.\n", __func__, dotg->charger->chg_type,previous_usb_status);
	if(previous_usb_status!=dotg->charger->chg_type)
		trigger_usb_state_from_otg(dotg->charger->chg_type);
        else
		pr_info("%s : previous_usb_status and current_usb_status is same.\n", __func__);
        previous_usb_status = dotg->charger->chg_type;
#endif

#ifdef CONFIG_LGE_PM
	if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) {
		if (dotg->charger->chg_type == DWC3_SDP_CHARGER) {
			if (dotg->dwc->gadget.speed == USB_SPEED_SUPER) {
				if (dotg->charger->max_power > 2)
					dotg->charger->max_power = 0;
				mA = DWC3_USB30_CHG_CURRENT;
			} else {
				mA = lge_pm_get_usb_current();
			}
#ifdef CONFIG_QPNP_CHARGER
			/* For MST, boost current up over 900mA in spite of USB */
			if (pseudo_batt_info.mode && mA == 500 )
				mA = DWC3_USB30_CHG_CURRENT;
#endif
		} else if (dotg->charger->chg_type == DWC3_DCP_CHARGER) {
			mA = lge_pm_get_ta_current();
		} else if (dotg->charger->chg_type == DWC3_FLOATED_CHARGER) {
			mA = lge_pm_get_usb_current();
		}
	}
#endif

	if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		mA = DWC3_IDEV_CHG_MAX;

	if (dotg->charger->max_power == mA)
		return 0;

	dev_info(phy->dev, "Avail curr from USB = %u\n", mA);

/* [email protected] make psy getter and move it above power_supply_type setter. 2014-02-06 */
#ifdef CONFIG_LGE_PM
#ifndef CONFIG_USB_DWC3_LGE_SINGLE_PSY
	if (dwc3_otg_get_psy(phy) < 0)
		goto psy_error;
#else
	if (strcmp(dotg->psy->name, "usb")) {
		pr_info("%s psy name is %s, so change psy to usb.\n", __func__, dotg->psy->name);
		dotg->psy = power_supply_get_by_name("usb");
		if (!dotg->psy)
			goto psy_error;
	}
#endif
	power_supply_set_supply_type(dotg->psy, power_supply_type);
#endif

#ifdef CONFIG_LGE_PM
	if (mA > 2) {
#else
	if (dotg->charger->max_power <= 2 && mA > 2) {
#endif
		/* Enable charging */
		if (power_supply_set_online(dotg->psy, true))
			goto psy_error;
		if (power_supply_set_current_limit(dotg->psy, 1000*mA))
			goto psy_error;
#ifdef CONFIG_QPNP_CHARGER
		if (!strncmp(dotg->psy->name, "ac", 2)) {
			dotg->psy = power_supply_get_by_name("usb");
			if (!dotg->psy)
				goto psy_error;

			if (power_supply_set_online(dotg->psy, true))
				goto psy_error;

			if (power_supply_set_supply_type(dotg->psy, power_supply_type))
				goto psy_error;

			if (power_supply_set_current_limit(dotg->psy, 1000*mA))
				goto psy_error;

			dotg->psy = power_supply_get_by_name("ac");
			if (!dotg->psy)
				goto psy_error;
		}
#endif
	} else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) {
		/* Disable charging */
		if (power_supply_set_online(dotg->psy, false))
			goto psy_error;
		/* Set max current limit */
		if (power_supply_set_current_limit(dotg->psy, 0))
			goto psy_error;

#ifdef CONFIG_QPNP_CHARGER
		if (!strncmp(dotg->psy->name, "ac", 2)) {
			dotg->psy = power_supply_get_by_name("usb");
			if (!dotg->psy)
				goto psy_error;

			if (power_supply_set_online(dotg->psy, false))
				goto psy_error;

			if (power_supply_set_supply_type(dotg->psy, power_supply_type))
				goto psy_error;

			if (power_supply_set_current_limit(dotg->psy, 0))
				goto psy_error;

			dotg->psy = power_supply_get_by_name("ac");
			if (!dotg->psy)
				goto psy_error;
		}
#endif
#ifndef CONFIG_USB_DWC3_LGE_SINGLE_PSY
		dotg->charger->chg_type = DWC3_INVALID_CHARGER;
#endif
	}

	power_supply_changed(dotg->psy);

	dotg->charger->max_power = mA;

#if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) || defined(CONFIG_TOUCHSCREEN_ATMEL_S540)
#if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_G2) || defined (CONFIG_MACH_MSM8974_TIGERS) || defined(CONFIG_MACH_MSM8974_B1_KR) || defined(CONFIG_MACH_MSM8974_B1W)
	queue_work(touch_otg_wq, &dotg->touch_work);
#endif
#endif

	return 0;

psy_error:
	dev_dbg(phy->dev, "power supply error when setting property\n");
	return -ENXIO;
}

/* IRQs which OTG driver is interested in handling */
#define DWC3_OEVT_MASK		(DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
				 DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)

/**
 * dwc3_otg_interrupt - interrupt handler for dwc3 otg events.
 * @_dotg: Pointer to out controller context structure
 *
 * Returns IRQ_HANDLED on success otherwise IRQ_NONE.
 */
static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)
{
	struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
	u32 osts, oevt_reg;
	int ret = IRQ_NONE;
	int handled_irqs = 0;
	struct usb_phy *phy = dotg->otg.phy;

	oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);

	if (!(oevt_reg & DWC3_OEVT_MASK))
		return IRQ_NONE;

	osts = dwc3_readl(dotg->regs, DWC3_OSTS);

	if ((oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ||
	    (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)) {
		/*
		 * ID sts has changed, set inputs later, in the workqueue
		 * function, switch from A to B or from B to A.
		 */

		if (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) {
			if (osts & DWC3_OTG_OSTS_CONIDSTS) {
				dev_dbg(phy->dev, "ID set\n");
				set_bit(ID, &dotg->inputs);
			} else {
				dev_dbg(phy->dev, "ID clear\n");
				clear_bit(ID, &dotg->inputs);
			}
			handled_irqs |= DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT;
		}

		if (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) {
			if (osts & DWC3_OTG_OSTS_BSESVALID) {
				dev_dbg(phy->dev, "BSV set\n");
				set_bit(B_SESS_VLD, &dotg->inputs);
			} else {
				dev_dbg(phy->dev, "BSV clear\n");
				clear_bit(B_SESS_VLD, &dotg->inputs);
			}
			handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
		}

		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);

		ret = IRQ_HANDLED;

		/* Clear the interrupts we handled */
		dwc3_writel(dotg->regs, DWC3_OEVT, handled_irqs);
	}

	return ret;
}

/**
 * dwc3_otg_init_sm - initialize OTG statemachine input
 * @dotg: Pointer to the dwc3_otg structure
 *
 */
void dwc3_otg_init_sm(struct dwc3_otg *dotg)
{
	u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS);
	struct usb_phy *phy = dotg->otg.phy;
	struct dwc3_ext_xceiv *ext_xceiv;
	int ret;

	dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts);

	/*
	 * VBUS initial state is reported after PMIC
	 * driver initialization. Wait for it.
	 */
	ret = wait_for_completion_timeout(&dotg->dwc3_xcvr_vbus_init, HZ * 5);
	if (!ret) {
		dev_err(phy->dev, "%s: completion timeout\n", __func__);
		/* We can safely assume no cable connected */
		set_bit(ID, &dotg->inputs);
	}

	ext_xceiv = dotg->ext_xceiv;
	dwc3_otg_reset(dotg);
	if (ext_xceiv && !ext_xceiv->otg_capability) {
		if (osts & DWC3_OTG_OSTS_CONIDSTS)
			set_bit(ID, &dotg->inputs);
		else
			clear_bit(ID, &dotg->inputs);

		if (osts & DWC3_OTG_OSTS_BSESVALID)
			set_bit(B_SESS_VLD, &dotg->inputs);
		else
			clear_bit(B_SESS_VLD, &dotg->inputs);
	}
}
Пример #20
0
void sm5504_callback(enum cable_type_t cable_type, int attached)
{
	union power_supply_propval value;
	struct power_supply *psy = power_supply_get_by_name("battery");
#if defined(CONFIG_MUIC_SUPPORT_CHARGING_CABLE)
	struct power_supply *psy_ps = power_supply_get_by_name("ps");
#endif
	static enum cable_type_t previous_cable_type = CABLE_TYPE_NONE;
#if defined(CONFIG_USB_NOTIFY_LAYER)
	struct otg_notify *n = get_otg_notify();
#endif
	pr_info("%s, called : cable_type :%d \n",__func__, cable_type);

	set_cable_status = attached ? cable_type : CABLE_TYPE_NONE;

	switch (cable_type) {
	case CABLE_TYPE_USB:
#if defined(USE_TSP_TA_CALLBACKS)
		if (charger_callbacks && charger_callbacks->inform_charger)
			charger_callbacks->inform_charger(charger_callbacks,
			attached);
#endif
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s USB Cable status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s USB Cable Status detached (%d) \n", __func__,status_count);
               }
#endif
#if defined(CONFIG_USB_NOTIFY_LAYER)
		send_otg_notify(n, NOTIFY_EVENT_VBUS, attached);
#else
		sec_otg_set_vbus_state(attached);
#endif
		break;
	case CABLE_TYPE_AC:
#if defined(USE_TSP_TA_CALLBACKS)
		if (charger_callbacks && charger_callbacks->inform_charger)
			charger_callbacks->inform_charger(charger_callbacks,
			attached);
#endif
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s Charger status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s charger status detached (%d) \n", __func__,status_count);
               }
#endif
		break;
	case CABLE_TYPE_UARTOFF:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s UART Status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s UART status detached (%d) \n", __func__,status_count);
               }
#endif
		break;
	case CABLE_TYPE_JIG_UART_OFF_VB:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s UART OFF VBUS Status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s UART OFF VBUS status detached (%d) \n", __func__,status_count);
               }
#endif
		break;
	case CABLE_TYPE_JIG:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s JIG cable status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s JIG cable status detached (%d) \n", __func__,status_count);
               }
#endif
		return;
	case CABLE_TYPE_CDP:
#if defined(USE_TSP_TA_CALLBACKS)
		if (charger_callbacks && charger_callbacks->inform_charger)
			charger_callbacks->inform_charger(charger_callbacks,
			attached);
#endif
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s CDP status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s CDP Status detached (%d) \n", __func__,status_count);
               }
#endif
#if defined(CONFIG_USB_NOTIFY_LAYER)
		send_otg_notify(n, NOTIFY_EVENT_VBUS, attached);
#else
		sec_otg_set_vbus_state(attached);
#endif
		break;
	case CABLE_TYPE_OTG:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s OTG status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s OTG status detached (%d) \n", __func__,status_count);
               }
#endif
#if defined(CONFIG_USB_HOST_NOTIFY)
		if (attached) {
			send_otg_notify(n, NOTIFY_EVENT_DRIVE_VBUS, 1);
			send_otg_notify(n, NOTIFY_EVENT_HOST, 1);
		} else {
			send_otg_notify(n, NOTIFY_EVENT_HOST, 0);
			send_otg_notify(n, NOTIFY_EVENT_DRIVE_VBUS, 0);
		}
#endif
	       return;
	case CABLE_TYPE_AUDIO_DOCK:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s Audiodock status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s Audiodock status detached (%d) \n", __func__,status_count);
               }
#endif
		break;
	case CABLE_TYPE_CARDOCK:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s Cardock status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s Cardock status detached (%d) \n", __func__,status_count);
               }
#endif
		switch_set_state(&switch_dock, attached ? 2 : 0);
		break;
	case CABLE_TYPE_DESK_DOCK:
	case CABLE_TYPE_DESK_DOCK_NO_VB:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s Deskdock %s status attached (%d) \n",__func__,
				((cable_type == CABLE_TYPE_DESK_DOCK)? "VBUS" : "NOVBUS"),status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s Deskdock %s status detached (%d) \n", __func__,
				((cable_type == CABLE_TYPE_DESK_DOCK)? "VBUS" : "NOVBUS"),status_count);
               }
#endif
		switch_set_state(&switch_dock, attached);
		break;
	case CABLE_TYPE_219KUSB:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s 219K USB status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s 219K USB status detached (%d) \n", __func__,status_count);
               }
#endif
#if defined(CONFIG_USB_NOTIFY_LAYER)
		send_otg_notify(n, NOTIFY_EVENT_VBUS, attached);
#else
		sec_otg_set_vbus_state(attached);
#endif
		break;
	case CABLE_TYPE_INCOMPATIBLE:
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s Incompatible Charger status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s Incomabtible Charger status detached (%d) \n", __func__,status_count);
               }
#endif
		break;
#if defined(CONFIG_MUIC_SUPPORT_CHARGING_CABLE)
	case CABLE_TYPE_CHARGING_CABLE:
		if (attached)
			value.intval = POWER_SUPPLY_TYPE_POWER_SHARING;
		else
			value.intval = POWER_SUPPLY_TYPE_BATTERY;

		if (psy_ps) {
			if (psy_ps->set_property(psy_ps, POWER_SUPPLY_PROP_ONLINE, &value)) {
				pr_err("%s: fail to set power sharing ONLINE property\n",__func__);
			}
		}
#if defined(DEBUG_STATUS)
               if (attached)
               {
                       status_count = status_count+1;
                       pr_err("%s Charging Cable status attached (%d) \n",__func__, status_count);
               } else {
                       status_count = status_count-1;
                       pr_err("%s Charging Cable status detached (%d) \n", __func__,status_count);
               }
#endif
		break;
#endif
	default:
		break;
	}

	if (previous_cable_type == set_cable_status) {
		pr_info("%s: SKIP cable setting\n", __func__);
		return;
	}
	previous_cable_type = set_cable_status;

#if defined(CONFIG_FUELGAUGE_MAX17050)
	if(check_sm5504_jig_state())
	{
		struct power_supply *fuel_psy = power_supply_get_by_name("sec-fuelgauge");
		if (!fuel_psy || !fuel_psy->set_property)
			pr_err("%s: fail to get sec-fuelgauge psy\n", __func__);
		else {
			fuel_psy->set_property(fuel_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &value);
		}
	}
#endif
#if defined(CONFIG_QPNP_BMS)
	if(check_sm5504_jig_state())
	{
	  struct power_supply *fuel_psy = power_supply_get_by_name("bms");
	  if (!fuel_psy || !fuel_psy->set_property)
		pr_err("%s: fail to get BMS psy\n", __func__);
		else {
			fuel_psy->set_property(fuel_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &value);
		}
	}
#endif

	switch (set_cable_status) {
	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_219KUSB:
	case CABLE_TYPE_AC:
	case CABLE_TYPE_AUDIO_DOCK:
	case CABLE_TYPE_UNDEFINED:
		value.intval = POWER_SUPPLY_TYPE_MAINS;
		break;
	case CABLE_TYPE_CARDOCK:
		value.intval = POWER_SUPPLY_TYPE_CARDOCK;
		break;
	case CABLE_TYPE_CDP:
		value.intval = POWER_SUPPLY_TYPE_USB_CDP;
		break;
	case CABLE_TYPE_INCOMPATIBLE:
		value.intval = POWER_SUPPLY_TYPE_UNKNOWN;
		break;
	case CABLE_TYPE_DESK_DOCK:
		value.intval = POWER_SUPPLY_TYPE_MAINS;
		break;
        case CABLE_TYPE_JIG_UART_OFF_VB:
                value.intval = POWER_SUPPLY_TYPE_UARTOFF;
                break;
	case CABLE_TYPE_DESK_DOCK_NO_VB:
	case CABLE_TYPE_UARTOFF:
	case CABLE_TYPE_NONE:
		value.intval = POWER_SUPPLY_TYPE_BATTERY;
		break;
	default:
		pr_err("%s: invalid cable :%d\n", __func__, set_cable_status);
		return;
	}
	current_cable_type = value.intval;
	pr_info("%s:MUIC setting the cable type as (%d)\n",__func__,value.intval);
	if (!psy || !psy->set_property)
		pr_err("%s: fail to get battery psy\n", __func__);
	else {
		psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &value);
	}
}
/*
 * BCL imax calculation and trigger notification to user space
 * if imax cross threshold
 */
static void bcl_calculate_imax_trigger(void)
{
	int ibatt_ua, vbatt_uv;
	int imax_ma;
	int ibatt_ma, vbatt_mv;
	int imax_low_threshold;
	int imax_high_threshold;
	bool threshold_cross = false;
	union power_supply_propval ret = {0,};
	static struct power_supply *psy;

	if (!gbcl) {
		pr_err("called before initialization\n");
		return;
	}

	if (psy == NULL) {
		psy = power_supply_get_by_name("battery");
		if (psy == NULL) {
			pr_err("failed to get ps battery\n");
			return;
		}
	}

	if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &ret))
		return;
	ibatt_ua = ret.intval;

	if (psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret))
		return;
	vbatt_uv = ret.intval;

	if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX, &ret))
		return;
	imax_ma = ret.intval/1000;

	ibatt_ma = ibatt_ua/1000;
	vbatt_mv = vbatt_uv/1000;

	gbcl->bcl_ibat_ma = ibatt_ma;
	gbcl->bcl_imax_ma = imax_ma;
	gbcl->bcl_vbat_mv = vbatt_mv;

	pr_debug("ibatt %d, imax %d, vbatt %d\n", ibatt_ma, imax_ma, vbatt_mv);
	if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
		== BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
		imax_high_threshold =
		imax_ma - gbcl->bcl_threshold_value_ma
			[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH];
		if (ibatt_ma >= imax_high_threshold)
			threshold_cross = true;
	}

	if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
		== BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
		imax_low_threshold =
		imax_ma - gbcl->bcl_threshold_value_ma
			[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW];
		if (ibatt_ma <= imax_low_threshold)
			threshold_cross = true;
	}

	if (threshold_cross) {
		sysfs_notify(&gbcl->dev->kobj,
				NULL, "type");
	}
}
Пример #22
0
static int smb349_dual_charger_probe(struct i2c_client *client,
				const struct i2c_device_id *id)
{
	int rc, irq;
	struct smb349_dual_charger *chip;

	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
	if (!chip) {
		dev_err(&client->dev, "Couldn't allocate memory\n");
		return -ENOMEM;
	}

	chip->client = client;
	chip->dev = &client->dev;
	chip->chg_present = -EINVAL;

	INIT_DELAYED_WORK(&chip->irq_handler_dwork, stat_irq_work);
	INIT_DELAYED_WORK(&chip->periodic_charge_handler_dwork,
							periodic_charge_work);

	rc = smb_parse_dt(chip);
	if (rc) {
		dev_err(&client->dev, "Couldn't parse DT nodes rc=%d\n", rc);
		return rc;
	}

	i2c_set_clientdata(client, chip);

	chip->cradle_psy.name		= "cradle-charger";
	chip->cradle_psy.type		= POWER_SUPPLY_TYPE_MAINS;
	chip->cradle_psy.get_property	= smb349_cradle_get_property;
	chip->cradle_psy.set_property	= smb349_cradle_set_property;
	chip->cradle_psy.property_is_writeable =
					smb349_cradle_property_is_writeable;
	chip->cradle_psy.properties	= smb349_cradle_properties;
	chip->cradle_psy.num_properties	= ARRAY_SIZE(smb349_cradle_properties);

	chip->ext_psy = power_supply_get_by_name((char *)chip->ext_psy_name);
	if (!chip->ext_psy) {
		dev_err(chip->dev,
			"Waiting for '%s' psy to become available\n",
			(char *)chip->ext_psy_name);
		return -EPROBE_DEFER;
	}

	mutex_init(&chip->irq_complete);
	mutex_init(&chip->pm_lock);

	rc = power_supply_register(chip->dev, &chip->cradle_psy);
	if (rc < 0) {
		dev_err(&client->dev, "Couldn't register '%s' psy rc=%d\n",
				chip->cradle_psy.name, rc);
		return rc;
	}

	rc = gpio_request(chip->chg_stat_gpio, "smb349_chg_stat");
	if (rc) {
		dev_err(&client->dev,
			"gpio_request for %d failed rc=%d\n",
			chip->chg_stat_gpio, rc);
		goto fail_chg_stat_irq;
	}

	irq = gpio_to_irq(chip->chg_stat_gpio);
	if (irq < 0) {
		dev_err(&client->dev,
			"Invalid chg_stat irq = %d\n", irq);
		goto fail_chg_stat_irq;
	}
	rc = devm_request_threaded_irq(&client->dev, irq,
		NULL, smb349_chg_stat_handler,
		IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
		"smb349_chg_stat_irq", chip);
	if (rc) {
		dev_err(&client->dev,
			"Failed request_irq irq=%d, gpio=%d rc=%d\n",
					irq, chip->chg_stat_gpio, rc);
		goto fail_chg_stat_irq;
	}

	determine_initial_state(chip);

	dev_info(chip->dev, "SMB349 successfully initialized in STAT driven mode. charger=%d\n",
			chip->chg_present);
	return 0;

fail_chg_stat_irq:
	if (gpio_is_valid(chip->chg_stat_gpio))
		gpio_free(chip->chg_stat_gpio);
	power_supply_unregister(&chip->cradle_psy);
	return rc;
}
int max77693_muic_charger_cb(enum cable_type_muic cable_type)
{
#if !defined(USE_CHGIN_INTR)
#ifdef CONFIG_BATTERY_MAX77693_CHARGER
	struct power_supply *psy = power_supply_get_by_name("max77693-charger");
	union power_supply_propval value;
#endif
#endif

#ifdef CONFIG_CHARGER_MAX77693_BAT
	struct power_supply *psy = power_supply_get_by_name("battery");
	union power_supply_propval value;
#endif
	static enum cable_type_muic previous_cable_type = CABLE_TYPE_NONE_MUIC;
	struct power_supply *psy_p = power_supply_get_by_name("ps");

	pr_info("%s: %d\n", __func__, cable_type);

	switch (cable_type) {
	case CABLE_TYPE_NONE_MUIC:
	case CABLE_TYPE_OTG_MUIC:
	case CABLE_TYPE_JIG_UART_OFF_MUIC:
	case CABLE_TYPE_MHL_MUIC:
#ifdef CONFIG_MUIC_MAX77693_SUPPORT_PS_CABLE
	case CABLE_TYPE_POWER_SHARING_MUIC:
#endif
		is_cable_attached = false;
		break;
	case CABLE_TYPE_USB_MUIC:
	case CABLE_TYPE_JIG_USB_OFF_MUIC:
	case CABLE_TYPE_JIG_USB_ON_MUIC:
		is_cable_attached = true;
		break;
	case CABLE_TYPE_MHL_VB_MUIC:
		is_cable_attached = true;
		break;
	case CABLE_TYPE_TA_MUIC:
	case CABLE_TYPE_CARDOCK_MUIC:
	case CABLE_TYPE_DESKDOCK_MUIC:
	case CABLE_TYPE_SMARTDOCK_MUIC:
	case CABLE_TYPE_AUDIODOCK_MUIC:
	case CABLE_TYPE_JIG_UART_OFF_VB_MUIC:
		is_cable_attached = true;
		break;
	default:
		pr_err("%s: invalid type:%d\n", __func__, cable_type);
		return -EINVAL;
	}

#if !defined(USE_CHGIN_INTR)
#ifdef CONFIG_BATTERY_MAX77693_CHARGER
	if (!psy || !psy->set_property) {
		pr_err("%s: fail to get max77693-charger psy\n", __func__);
		return 0;
	}

	value.intval = cable_type;
	psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &value);
#endif
#endif

	if (previous_cable_type == cable_type) {
		pr_info("%s : SKIP cable setting\n", __func__);
		goto skip_cable_setting;
	}

#ifdef CONFIG_CHARGER_MAX77693_BAT
	/* charger setting */
	switch (cable_type) {
	case CABLE_TYPE_NONE_MUIC:
	case CABLE_TYPE_JIG_UART_OFF_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_BATTERY;
		break;
	case CABLE_TYPE_MHL_VB_MUIC:
		if (lpcharge)
			current_cable_type = POWER_SUPPLY_TYPE_USB;
		else
			goto skip;
		break;
	case CABLE_TYPE_MHL_MUIC:
		if (lpcharge) {
			current_cable_type = POWER_SUPPLY_TYPE_BATTERY;
		} else {
			goto skip;
		}
		break;
	case CABLE_TYPE_OTG_MUIC:
		goto skip;
	case CABLE_TYPE_USB_MUIC:
	case CABLE_TYPE_JIG_USB_OFF_MUIC:
	case CABLE_TYPE_JIG_USB_ON_MUIC:
	case CABLE_TYPE_SMARTDOCK_USB_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_USB;
		break;
	case CABLE_TYPE_JIG_UART_OFF_VB_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_UARTOFF;
		break;
	case CABLE_TYPE_TA_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_MAINS;
		break;
	case CABLE_TYPE_CARDOCK_MUIC:
	case CABLE_TYPE_DESKDOCK_MUIC:
	case CABLE_TYPE_SMARTDOCK_MUIC:
	case CABLE_TYPE_AUDIODOCK_MUIC:
	case CABLE_TYPE_SMARTDOCK_TA_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_MISC;
		break;
#ifdef CONFIG_MUIC_MAX77693_SUPPORT_PS_CABLE
	case CABLE_TYPE_POWER_SHARING_MUIC:
		current_cable_type = POWER_SUPPLY_TYPE_POWER_SHARING;
		break;
#endif
	default:
		pr_err("%s: invalid type for charger:%d\n",
				__func__, cable_type);
		goto skip;
	}

	if (!psy || !psy->set_property || !psy_p || !psy_p->set_property) {
		pr_err("%s: fail to get battery psy\n", __func__);
		return 0;
	} else {
#ifdef CONFIG_MUIC_MAX77693_SUPPORT_PS_CABLE
		if (current_cable_type == POWER_SUPPLY_TYPE_POWER_SHARING) {
			value.intval = current_cable_type;
			psy_p->set_property(psy_p, POWER_SUPPLY_PROP_ONLINE, &value);
		} else {
			if (previous_cable_type == CABLE_TYPE_POWER_SHARING_MUIC) {
				value.intval = current_cable_type;
				psy_p->set_property(psy_p, POWER_SUPPLY_PROP_ONLINE, &value);
			}
#endif
			value.intval = current_cable_type<<ONLINE_TYPE_MAIN_SHIFT;
			psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &value);
#ifdef CONFIG_MUIC_MAX77693_SUPPORT_PS_CABLE
		}
#endif
	}
skip:
#endif
	previous_cable_type = cable_type;
skip_cable_setting:
#if defined(CONFIG_MACH_SLP_NAPLES) \
	|| defined(CONFIG_MACH_MIDAS) \
	|| defined(CONFIG_MACH_GC1) \
	|| defined(CONFIG_MACH_T0) \
	|| defined(CONFIG_MACH_GD2)

#ifndef CONFIG_TOUCHSCREEN_CYPRESS_TMA46X
#ifndef CONFIG_MACH_KONA
	tsp_charger_infom(is_cable_attached);
#endif
#endif
#endif
#ifdef CONFIG_JACK_MON
	jack_event_handler("charger", is_cable_attached);
#endif

	return 0;
}
Пример #24
0
/**
 * dwc3_otg_sm_work - workqueue function.
 *
 * @w: Pointer to the dwc3 otg workqueue
 *
 * NOTE: After any change in phy->state,
 * we must reschdule the state machine.
 */
static void dwc3_otg_sm_work(struct work_struct *w)
{
	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work);
	struct usb_phy *phy = dotg->otg.phy;
	struct dwc3_charger *charger = dotg->charger;
	bool work = 0;
	int ret = 0;
	unsigned long delay = 0;

	pm_runtime_resume(phy->dev);
	dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));

	/* Check OTG state */
	switch (phy->state) {
	case OTG_STATE_UNDEFINED:
		dwc3_otg_init_sm(dotg);
		if (!dotg->psy) {
			dotg->psy = power_supply_get_by_name("usb");

			if (!dotg->psy)
				dev_err(phy->dev,
					 "couldn't get usb power supply\n");
		}

		/* Switch to A or B-Device according to ID / BSV */
		if (!test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "!id\n");
			phy->state = OTG_STATE_A_IDLE;
			work = 1;
		} else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
			dev_dbg(phy->dev, "b_sess_vld\n");
			phy->state = OTG_STATE_B_IDLE;
			work = 1;
		} else {
			phy->state = OTG_STATE_B_IDLE;
			dev_dbg(phy->dev, "No device, trying to suspend\n");
			pm_runtime_put_sync(phy->dev);
		}
		break;

	case OTG_STATE_B_IDLE:
		if (!test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "!id\n");
			phy->state = OTG_STATE_A_IDLE;
			work = 1;
			dotg->charger_retry_count = 0;
			if (charger) {
				if (charger->chg_type == DWC3_INVALID_CHARGER)
					charger->start_detection(dotg->charger,
									false);
				else
					charger->chg_type =
							DWC3_INVALID_CHARGER;
			}
		} else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
			dev_dbg(phy->dev, "b_sess_vld\n");
			if (charger) {
				/* Has charger been detected? If no detect it */
				switch (charger->chg_type) {
				case DWC3_DCP_CHARGER:
				case DWC3_PROPRIETARY_CHARGER:
					dev_dbg(phy->dev, "lpm, DCP charger\n");
					dwc3_otg_set_power(phy,
							DWC3_IDEV_CHG_MAX);
					pm_runtime_put_sync(phy->dev);
					break;
				case DWC3_CDP_CHARGER:
					dwc3_otg_set_power(phy,
							DWC3_IDEV_CHG_MAX);
					dwc3_otg_start_peripheral(&dotg->otg,
									1);
					phy->state = OTG_STATE_B_PERIPHERAL;
					work = 1;
					break;
				case DWC3_SDP_CHARGER:
					dwc3_otg_start_peripheral(&dotg->otg,
									1);
					phy->state = OTG_STATE_B_PERIPHERAL;
					pr_info("DWC3_SDP_CHARGER\n");
					work = 1;
					break;
				case DWC3_FLOATED_CHARGER:
					if (dotg->charger_retry_count <
							max_chgr_retry_count)
						dotg->charger_retry_count++;
					/*
					 * In case of floating charger, if
					 * retry count equal to max retry count
					 * notify PMIC about floating charger
					 * and put Hw in low power mode. Else
					 * perform charger detection again by
					 * calling start_detection() with false
					 * and then with true argument.
					 */
					if (dotg->charger_retry_count ==
						max_chgr_retry_count) {
						dwc3_otg_set_power(phy, 0);
						pm_runtime_put_sync(phy->dev);
						break;
					}
					charger->start_detection(dotg->charger,
									false);

				default:
					dev_dbg(phy->dev, "chg_det started\n");
					charger->start_detection(charger, true);
					break;
				}
			} else {
				/* no charger registered, start peripheral */
				if (dwc3_otg_start_peripheral(&dotg->otg, 1)) {
					/*
					 * Probably set_peripheral not called
					 * yet. We will re-try as soon as it
					 * will be called
					 */
					dev_err(phy->dev, "enter lpm as\n"
						"unable to start B-device\n");
					phy->state = OTG_STATE_UNDEFINED;
					pm_runtime_put_sync(phy->dev);
					return;
				}
			}
		} else {
			if (charger)
				charger->start_detection(dotg->charger, false);

			dotg->charger_retry_count = 0;
			dwc3_otg_set_power(phy, 0);
			dev_dbg(phy->dev, "No device, trying to suspend\n");
			pm_runtime_put_sync(phy->dev);
		}
		break;

	case OTG_STATE_B_PERIPHERAL:
#ifdef CONFIG_PANTECH_USB_BLOCKING_MDMSTATE
		if (0 < get_pantech_mdm_state())
			dwc3_otg_set_power(phy, DWC3_BLOCKING_USB_MDMSTATE_MAX);
#endif
#ifndef CONFIG_PANTECH_SIO_BUG_FIX
		if (!test_bit(B_SESS_VLD, &dotg->inputs) ||
				!test_bit(ID, &dotg->inputs)) {
#else
		if (!test_bit(B_SESS_VLD, &dotg->inputs)) {
		
#endif
			dev_dbg(phy->dev, "!id || !bsv\n");
			dwc3_otg_start_peripheral(&dotg->otg, 0);
			phy->state = OTG_STATE_B_IDLE;
			if (charger)
				charger->chg_type = DWC3_INVALID_CHARGER;
			work = 1;
		}
		break;

	case OTG_STATE_A_IDLE:
		/* Switch to A-Device*/
		if (test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "id\n");
			phy->state = OTG_STATE_B_IDLE;
			dotg->vbus_retry_count = 0;
			work = 1;
		} else {
			phy->state = OTG_STATE_A_HOST;
			ret = dwc3_otg_start_host(&dotg->otg, 1);
			if ((ret == -EPROBE_DEFER) &&
						dotg->vbus_retry_count < 3) {
				/*
				 * Get regulator failed as regulator driver is
				 * not up yet. Will try to start host after 1sec
				 */
				phy->state = OTG_STATE_A_IDLE;
				dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n");
				delay = VBUS_REG_CHECK_DELAY;
				work = 1;
				dotg->vbus_retry_count++;
			} else if (ret) {
				/*
				 * Probably set_host was not called yet.
				 * We will re-try as soon as it will be called
				 */
				dev_dbg(phy->dev, "enter lpm as\n"
					"unable to start A-device\n");
				phy->state = OTG_STATE_A_IDLE;
				pm_runtime_put_sync(phy->dev);
				return;
			}
		}
		break;

	case OTG_STATE_A_HOST:
		if (test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "id\n");
#ifdef CONFIG_PANTECH_SIO_BUG_FIX
			/* FIXME : If OTG cable is disconnecting, below process is must completed 
			 * before pm_runtime_suspend.
			 * So we are ignored pm_runtime_suspend request.
			 * LS4-USB tarial
			 */
			pm_runtime_get_noresume(phy->dev);
#endif
			dwc3_otg_start_host(&dotg->otg, 0);
			phy->state = OTG_STATE_B_IDLE;
			dotg->vbus_retry_count = 0;
			work = 1;
#ifdef CONFIG_PANTECH_SIO_BUG_FIX
			pm_runtime_put_noidle(phy->dev);
#endif
		}
		break;

	default:
		dev_err(phy->dev, "%s: invalid otg-state\n", __func__);

	}

	if (work)
		queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay);
}


/**
 * dwc3_otg_reset - reset dwc3 otg registers.
 *
 * @w: Pointer to the dwc3 otg workqueue
 */
static void dwc3_otg_reset(struct dwc3_otg *dotg)
{
	static int once;
	struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;

	/*
	 * OCFG[2] - OTG-Version = 1
	 * OCFG[1] - HNPCap = 0
	 * OCFG[0] - SRPCap = 0
	 */
	if (ext_xceiv && !ext_xceiv->otg_capability)
		dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);

	/*
	 * OCTL[6] - PeriMode = 1
	 * OCTL[5] - PrtPwrCtl = 0
	 * OCTL[4] - HNPReq = 0
	 * OCTL[3] - SesReq = 0
	 * OCTL[2] - TermSelDLPulse = 0
	 * OCTL[1] - DevSetHNPEn = 0
	 * OCTL[0] - HstSetHNPEn = 0
	 */
	if (!once) {
		if (ext_xceiv && !ext_xceiv->otg_capability)
			dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
		once++;
	}

	/* Clear all otg events (interrupts) indications  */
	dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF);

	/* Enable ID/BSV StsChngEn event*/
	if (ext_xceiv && !ext_xceiv->otg_capability)
		dwc3_writel(dotg->regs, DWC3_OEVTEN,
				DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
				DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
}

/**
 * dwc3_otg_init - Initializes otg related registers
 * @dwc: Pointer to out controller context structure
 *
 * Returns 0 on success otherwise negative errno.
 */
int dwc3_otg_init(struct dwc3 *dwc)
{
	u32	reg;
	int ret = 0;
	struct dwc3_otg *dotg;

	dev_dbg(dwc->dev, "dwc3_otg_init\n");

	/*
	 * GHWPARAMS6[10] bit is SRPSupport.
	 * This bit also reflects DWC_USB3_EN_OTG
	 */
	reg = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
	if (!(reg & DWC3_GHWPARAMS6_SRP_SUPPORT)) {
		/*
		 * No OTG support in the HW core.
		 * We return 0 to indicate no error, since this is acceptable
		 * situation, just continue probe the dwc3 driver without otg.
		 */
		dev_dbg(dwc->dev, "dwc3_otg address space is not supported\n");
		return 0;
	}

	/* Allocate and init otg instance */
	dotg = kzalloc(sizeof(struct dwc3_otg), GFP_KERNEL);
	if (!dotg) {
		dev_err(dwc->dev, "unable to allocate dwc3_otg\n");
		return -ENOMEM;
	}

	/* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
	dotg->irq = platform_get_irq_byname(to_platform_device(dwc->dev),
								"otg_irq");
	if (dotg->irq < 0) {
		dev_err(dwc->dev, "%s: missing OTG IRQ\n", __func__);
		ret = -ENODEV;
		goto err1;
	}

	dotg->regs = dwc->regs;

	dotg->otg.set_peripheral = dwc3_otg_set_peripheral;
	dotg->otg.set_host = dwc3_otg_set_host;

	/* This reference is used by dwc3 modules for checking otg existance */
	dwc->dotg = dotg;

	dotg->otg.phy = kzalloc(sizeof(struct usb_phy), GFP_KERNEL);
	if (!dotg->otg.phy) {
		dev_err(dwc->dev, "unable to allocate dwc3_otg.phy\n");
		ret = -ENOMEM;
		goto err1;
	}

	dotg->dwc = dwc;
	dotg->otg.phy->otg = &dotg->otg;
	dotg->otg.phy->dev = dwc->dev;
	dotg->otg.phy->set_power = dwc3_otg_set_power;
	dotg->otg.phy->set_suspend = dwc3_otg_set_suspend;

	ret = usb_set_transceiver(dotg->otg.phy);
	if (ret) {
		dev_err(dotg->otg.phy->dev,
			"%s: failed to set transceiver, already exists\n",
			__func__);
		goto err2;
	}

	dotg->otg.phy->state = OTG_STATE_UNDEFINED;

	init_completion(&dotg->dwc3_xcvr_vbus_init);
	INIT_DELAYED_WORK(&dotg->sm_work, dwc3_otg_sm_work);

	ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
				"dwc3_otg", dotg);
	if (ret) {
		dev_err(dotg->otg.phy->dev, "failed to request irq #%d --> %d\n",
				dotg->irq, ret);
		goto err3;
	}

	pm_runtime_get(dwc->dev);

	return 0;

err3:
	cancel_delayed_work_sync(&dotg->sm_work);
	usb_set_transceiver(NULL);
err2:
	kfree(dotg->otg.phy);
err1:
	dwc->dotg = NULL;
	kfree(dotg);

	return ret;
}
Пример #25
0
/**
 * dwc3_otg_sm_work - workqueue function.
 *
 * @w: Pointer to the dwc3 otg workqueue
 *
 * NOTE: After any change in phy->state,
 * we must reschdule the state machine.
 */
static void dwc3_otg_sm_work(struct work_struct *w)
{
	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work);
	struct usb_phy *phy = dotg->otg.phy;
	struct dwc3_charger *charger = dotg->charger;
	bool work = 0;
	int ret = 0;
	unsigned long delay = 0;

	pm_runtime_resume(phy->dev);
	dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));

	/* Check OTG state */
	switch (phy->state) {
	case OTG_STATE_UNDEFINED:
		dwc3_otg_init_sm(dotg);
		if (!dotg->psy) {
			dotg->psy = power_supply_get_by_name("usb");

			if (!dotg->psy)
				dev_err(phy->dev,
					 "couldn't get usb power supply\n");
		}

		/* Switch to A or B-Device according to ID / BSV */
		if (!test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "!id\n");
			phy->state = OTG_STATE_A_IDLE;
			work = 1;
		} else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
			dev_dbg(phy->dev, "b_sess_vld\n");
			phy->state = OTG_STATE_B_IDLE;
			work = 1;
		} else {
			phy->state = OTG_STATE_B_IDLE;
			dev_dbg(phy->dev, "No device, trying to suspend\n");
			pm_runtime_put_sync(phy->dev);
		}
		break;

	case OTG_STATE_B_IDLE:
		if (!test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "!id\n");
			phy->state = OTG_STATE_A_IDLE;
			work = 1;
			dotg->charger_retry_count = 0;
			if (charger) {
				if (charger->chg_type == DWC3_INVALID_CHARGER)
					charger->start_detection(dotg->charger,
									false);
				else
					charger->chg_type =
							DWC3_INVALID_CHARGER;
			}
		} else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
			dev_dbg(phy->dev, "b_sess_vld\n");
			if (charger) {
				/* Has charger been detected? If no detect it */
				switch (charger->chg_type) {
				case DWC3_DCP_CHARGER:
				case DWC3_PROPRIETARY_CHARGER:
					dev_dbg(phy->dev, "lpm, DCP charger\n");
					dwc3_otg_set_power(phy,
							DWC3_IDEV_CHG_MAX);
					pm_runtime_put_sync(phy->dev);
					break;
				case DWC3_CDP_CHARGER:
					dwc3_otg_set_power(phy,
							DWC3_IDEV_CHG_MAX);
					dwc3_otg_start_peripheral(&dotg->otg,
									1);
					phy->state = OTG_STATE_B_PERIPHERAL;
					work = 1;
					break;
				case DWC3_SDP_CHARGER:
					dwc3_otg_start_peripheral(&dotg->otg,
									1);
					phy->state = OTG_STATE_B_PERIPHERAL;
					work = 1;
					break;
				case DWC3_FLOATED_CHARGER:
					if (dotg->charger_retry_count <
							max_chgr_retry_count)
						dotg->charger_retry_count++;
					/*
					 * In case of floating charger, if
					 * retry count equal to max retry count
					 * notify PMIC about floating charger
					 * and put Hw in low power mode. Else
					 * perform charger detection again by
					 * calling start_detection() with false
					 * and then with true argument.
					 */
					if (dotg->charger_retry_count ==
						max_chgr_retry_count) {
						dwc3_otg_set_power(phy, 0);
						pm_runtime_put_sync(phy->dev);
						break;
					}
					charger->start_detection(dotg->charger,
									false);

				default:
					dev_dbg(phy->dev, "chg_det started\n");
					charger->start_detection(charger, true);
					break;
				}
			} else {
				/* no charger registered, start peripheral */
				if (dwc3_otg_start_peripheral(&dotg->otg, 1)) {
					/*
					 * Probably set_peripheral not called
					 * yet. We will re-try as soon as it
					 * will be called
					 */
					dev_err(phy->dev, "enter lpm as\n"
						"unable to start B-device\n");
					phy->state = OTG_STATE_UNDEFINED;
					pm_runtime_put_sync(phy->dev);
					return;
				}
			}
		} else {
			if (charger)
				charger->start_detection(dotg->charger, false);

			dotg->charger_retry_count = 0;
			dwc3_otg_set_power(phy, 0);
			dev_dbg(phy->dev, "No device, trying to suspend\n");
			pm_runtime_put_sync(phy->dev);
		}
		break;

	case OTG_STATE_B_PERIPHERAL:
		if (!test_bit(B_SESS_VLD, &dotg->inputs) ||
				!test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "!id || !bsv\n");
			dwc3_otg_start_peripheral(&dotg->otg, 0);
			phy->state = OTG_STATE_B_IDLE;
			if (charger)
				charger->chg_type = DWC3_INVALID_CHARGER;
			work = 1;
		}
		break;

	case OTG_STATE_A_IDLE:
		/* Switch to A-Device*/
		if (test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "id\n");
			phy->state = OTG_STATE_B_IDLE;
			dotg->vbus_retry_count = 0;
			work = 1;
		} else {
			phy->state = OTG_STATE_A_HOST;
			ret = dwc3_otg_start_host(&dotg->otg, 1);
			if ((ret == -EPROBE_DEFER) &&
						dotg->vbus_retry_count < 3) {
				/*
				 * Get regulator failed as regulator driver is
				 * not up yet. Will try to start host after 1sec
				 */
				phy->state = OTG_STATE_A_IDLE;
				dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n");
				delay = VBUS_REG_CHECK_DELAY;
				work = 1;
				dotg->vbus_retry_count++;
			} else if (ret) {
				/*
				 * Probably set_host was not called yet.
				 * We will re-try as soon as it will be called
				 */
				dev_dbg(phy->dev, "enter lpm as\n"
					"unable to start A-device\n");
				phy->state = OTG_STATE_A_IDLE;
				pm_runtime_put_sync(phy->dev);
				return;
			}
		}
		break;

	case OTG_STATE_A_HOST:
		if (test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "id\n");
			dwc3_otg_start_host(&dotg->otg, 0);
			phy->state = OTG_STATE_B_IDLE;
			dotg->vbus_retry_count = 0;
			work = 1;
		}
		break;

	default:
		dev_err(phy->dev, "%s: invalid otg-state\n", __func__);

	}

	if (work)
		queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay);
}
static void bq5101xb_worker(struct work_struct *work)
{
	int batt_temp;
	int batt_volt;
	int batt_soc;
	int batt_status;
	int powered = 0;
	int wired = 0;
	int i;
	struct delayed_work *dwork;
	struct bq5101xb_chip *chip;
	struct bq5101xb_charger_platform_data *pdata;
	struct blocking_notifier_head *ntfy_hd;
	struct notifier_block *batt_ntfy;

	dwork = to_delayed_work(work);
	chip = container_of(dwork, struct bq5101xb_chip, bq5101xb_work);
	pdata = chip->dev->platform_data;

	if (!chip->batt_psy) {
		for (i = 0; i < pdata->num_supplies; i++) {
			chip->batt_psy =
				power_supply_get_by_name(pdata->supply_list[i]);

			if (!chip->batt_psy) {
				pr_err_once("Batt PSY Not Found\n");
				continue;
			}

			/* Confirm a batt psy */
			if (chip->batt_psy->type != POWER_SUPPLY_TYPE_BATTERY)
				chip->batt_psy = NULL;

			if (chip->batt_psy) {
				ntfy_hd = &chip->batt_psy->notify_head;
				batt_ntfy = &chip->psy_notifier;
				blocking_notifier_chain_register(ntfy_hd,
								 batt_ntfy);
				break;
			}
		}
	}

	if (chip->batt_psy) {
		if (pdata->check_powered)
			powered = pdata->check_powered();
		else if (pdata->chrg_b_pin > 0)
			powered = !gpio_get_value(pdata->chrg_b_pin);

		if (pdata->check_wired)
			wired = pdata->check_wired();

		if (bq5101xb_get_batt_info(chip->batt_psy,
					   POWER_SUPPLY_PROP_TEMP,
					   &batt_temp)) {
			dev_err(chip->dev, "Error Reading Temperature\n");
			return;
		}
		/* Convert Units to Celsius */
		batt_temp /= 10;

		if (bq5101xb_get_batt_info(chip->batt_psy,
					   POWER_SUPPLY_PROP_VOLTAGE_NOW,
					   &batt_volt)) {
			dev_err(chip->dev, "Error Reading Voltage\n");
			return;
		}

		if (bq5101xb_get_batt_info(chip->batt_psy,
					   POWER_SUPPLY_PROP_CAPACITY,
					   &batt_soc)) {
			dev_err(chip->dev, "Error Reading Capacity\n");
			return;
		}
		if (bq5101xb_get_batt_info(chip->batt_psy,
					   POWER_SUPPLY_PROP_STATUS,
					   &batt_status)) {
			dev_err(chip->dev, "Error Reading Status\n");
			return;
		}
	} else {
		pr_err_once("batt_psy not found\n");
		schedule_delayed_work(&chip->bq5101xb_work,
				      msecs_to_jiffies(100));
		return;
	}

	dev_dbg(chip->dev, "State Before = %d\n", chip->state);

	switch (chip->state) {
	case BQ5101XB_WAIT:
		if (wired && (pdata->priority == BQ5101XB_WIRED)) {
			bq5101xb_set_pins(pdata, 1, 1, 0, 0);
			chip->state = BQ5101XB_WIRED_CONN;
		} else if (powered) {
			chip->state = BQ5101XB_RUNNING;
		} else if (batt_temp >= pdata->hot_temp) {
			bq5101xb_set_pins(pdata, 0, 0, 1, 1);
			chip->state = BQ5101XB_OUT_OF_TEMP_HOT;
		} else if (batt_temp <= pdata->cold_temp) {
			bq5101xb_set_pins(pdata, 0, 0, 1, 1);
			chip->state = BQ5101XB_OUT_OF_TEMP_COLD;
		}
		break;
	case BQ5101XB_WIRED_CONN:
		if (!wired) {
			bq5101xb_set_pins(pdata, 0, 0, 1, 0);
			chip->state = BQ5101XB_WAIT;
		}
		break;
	case BQ5101XB_RUNNING:
		if (wired && (pdata->priority == BQ5101XB_WIRED)) {
			bq5101xb_set_pins(pdata, 1, 1, 0, 0);
			chip->state = BQ5101XB_WIRED_CONN;
		} else if (!powered) {
			bq5101xb_set_pins(pdata, 0, 0, 1, 0);
			chip->state = BQ5101XB_WAIT;
		} else if (batt_temp >= pdata->hot_temp) {
			bq5101xb_set_pins(pdata, 0, 0, 1, 1);
			chip->state = BQ5101XB_OUT_OF_TEMP_HOT;
		} else if (batt_temp <= pdata->cold_temp) {
			bq5101xb_set_pins(pdata, 0, 0, 1, 1);
			chip->state = BQ5101XB_OUT_OF_TEMP_COLD;
		} else if ((batt_soc >= BQ5101XB_CHRG_CMPLT_SOC) &&
			   (batt_status == POWER_SUPPLY_STATUS_FULL)) {
			bq5101xb_set_pins(pdata, 1, 1, 0, 0);
			chip->state = BQ5101XB_CHRG_CMPLT;
		}
		break;
	case BQ5101XB_OUT_OF_TEMP_HOT:
		if (wired && (pdata->priority == BQ5101XB_WIRED)) {
			bq5101xb_set_pins(pdata, 1, 1, 0, 0);
			chip->state = BQ5101XB_WIRED_CONN;
		} else if (batt_temp < (pdata->hot_temp -
					BQ5101XB_TEMP_HYS)) {
			if ((batt_soc >= BQ5101XB_CHRG_CMPLT_SOC) &&
			    (batt_status == POWER_SUPPLY_STATUS_FULL)) {
				bq5101xb_set_pins(pdata, 1, 1, 0, 0);
				chip->state = BQ5101XB_CHRG_CMPLT;
			} else {
				bq5101xb_set_pins(pdata, 0, 0, 1, 0);
				chip->state = BQ5101XB_WAIT;
			}
		}
		break;
	case BQ5101XB_OUT_OF_TEMP_COLD:
		if (wired && (pdata->priority == BQ5101XB_WIRED)) {
			bq5101xb_set_pins(pdata, 1, 1, 0, 0);
			chip->state = BQ5101XB_WIRED_CONN;
		} else if (batt_temp > (pdata->cold_temp +
					BQ5101XB_TEMP_HYS)) {
			if ((batt_soc >= BQ5101XB_CHRG_CMPLT_SOC) &&
			    (batt_status == POWER_SUPPLY_STATUS_FULL)) {
				bq5101xb_set_pins(pdata, 1, 1, 0, 0);
				chip->state = BQ5101XB_CHRG_CMPLT;
			} else {
				bq5101xb_set_pins(pdata, 0, 0, 1, 0);
				chip->state = BQ5101XB_WAIT;
			}
		}
		break;
	case BQ5101XB_CHRG_CMPLT:
		if (wired && (pdata->priority == BQ5101XB_WIRED)) {
			bq5101xb_set_pins(pdata, 1, 1, 0, 0);
			chip->state = BQ5101XB_WIRED_CONN;
		} else if (batt_temp >= pdata->hot_temp) {
			bq5101xb_set_pins(pdata, 0, 0, 1, 1);
			chip->state = BQ5101XB_OUT_OF_TEMP_HOT;
		} else if (batt_temp <= pdata->cold_temp) {
			bq5101xb_set_pins(pdata, 0, 0, 1, 1);
			chip->state = BQ5101XB_OUT_OF_TEMP_COLD;
		} else if ((batt_soc <= pdata->resume_soc) ||
			   (batt_volt <= pdata->resume_vbatt)){
			bq5101xb_set_pins(pdata, 0, 0, 1, 0);
			chip->state = BQ5101XB_WAIT;
		}
		break;
	}

	dev_dbg(chip->dev, "State After = %d\n", chip->state);

	return;
}
/**
 * dwc3_otg_sm_work - workqueue function.
 *
 * @w: Pointer to the dwc3 otg workqueue
 *
 * NOTE: After any change in phy->state,
 * we must reschdule the state machine.
 */
static void dwc3_otg_sm_work(struct work_struct *w)
{
	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work);
	struct usb_phy *phy = dotg->otg.phy;
	struct dwc3_charger *charger = dotg->charger;
	bool work = 0;
	int ret = 0;
	unsigned long delay = 0;

	pm_runtime_resume(phy->dev);
	dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));

	/* Check OTG state */
	switch (phy->state) {
	case OTG_STATE_UNDEFINED:
		dwc3_otg_init_sm(dotg);
		if (!dotg->psy) {
			dotg->psy = power_supply_get_by_name("usb");

			if (!dotg->psy)
				dev_err(phy->dev,
					 "couldn't get usb power supply\n");
		}

		/* Switch to A or B-Device according to ID / BSV */
		if (!test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "!id\n");
			phy->state = OTG_STATE_A_IDLE;
			work = 1;
		} else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
			dev_dbg(phy->dev, "b_sess_vld\n");
			phy->state = OTG_STATE_B_IDLE;
			work = 1;
		} else {
			phy->state = OTG_STATE_B_IDLE;
			dev_dbg(phy->dev, "No device, trying to suspend\n");
			pm_runtime_put_sync(phy->dev);
		}
		break;

	case OTG_STATE_B_IDLE:
		if (!test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "!id\n");
			phy->state = OTG_STATE_A_IDLE;
			work = 1;
			dotg->charger_retry_count = 0;
			if (charger) {
				if (charger->chg_type == DWC3_INVALID_CHARGER)
					charger->start_detection(dotg->charger,
									false);
				else
					charger->chg_type =
							DWC3_INVALID_CHARGER;
			}
		} else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
			dev_dbg(phy->dev, "b_sess_vld\n");
			if (charger) {
				/* Has charger been detected? If no detect it */
				switch (charger->chg_type) {
				case DWC3_DCP_CHARGER:
				case DWC3_PROPRIETARY_CHARGER:
					dev_dbg(phy->dev, "lpm, DCP charger\n");
					dwc3_otg_set_power(phy,
							DWC3_IDEV_CHG_MAX);
					pm_runtime_put_sync(phy->dev);
					break;
				case DWC3_CDP_CHARGER:
					dwc3_otg_set_power(phy,
							DWC3_IDEV_CHG_MAX);
					dwc3_otg_start_peripheral(&dotg->otg,
									1);
					phy->state = OTG_STATE_B_PERIPHERAL;
					work = 1;
					break;
				case DWC3_SDP_CHARGER:
					dwc3_otg_start_peripheral(&dotg->otg,
									1);
					phy->state = OTG_STATE_B_PERIPHERAL;
					work = 1;
/* OPPO 2013-10-05 wangjc Add begin for support non-standard charger, HW_VERSION__12 is dvt */
#ifdef CONFIG_MACH_MSM8974_14001
#if defined(CONFIG_OPPO_DEVICE_FIND7) || defined(CONFIG_OPPO_DEVICE_FIND7WX)
					if(get_pcb_version() < HW_VERSION__12) {
						cancel_delayed_work_sync(&dotg->non_standard_charger_work);
						non_standard = true;

						schedule_delayed_work(&dotg->non_standard_charger_work,
							round_jiffies_relative(msecs_to_jiffies
							(5000)));

					} else {
						/* [email protected], 2014/01/23  Add for notify usb online earlier */
						power_supply_set_online(dotg->psy, true);
						power_supply_changed(dotg->psy);
					}
#else
					power_supply_set_online(dotg->psy, true);
					power_supply_changed(dotg->psy);
#endif
#endif
/* OPPO 2013-10-05 wangjc Add end */
					break;
				case DWC3_FLOATED_CHARGER:
/* OPPO 2013-10-05 wangjc Modify begin for support non-standard charger */
#ifndef CONFIG_MACH_MSM8974_14001
					if (dotg->charger_retry_count <
							max_chgr_retry_count)
						dotg->charger_retry_count++;
					/*
					 * In case of floating charger, if
					 * retry count equal to max retry count
					 * notify PMIC about floating charger
					 * and put Hw in low power mode. Else
					 * perform charger detection again by
					 * calling start_detection() with false
					 * and then with true argument.
					 */
					if (dotg->charger_retry_count ==
						max_chgr_retry_count) {
						dwc3_otg_set_power(phy, 0);
						pm_runtime_put_sync(phy->dev);
						break;
					}
					charger->start_detection(dotg->charger,
									false);
#else
					dev_dbg(phy->dev, "lpm, FLOATED charger\n");
					dwc3_otg_set_power(phy,
							DWC3_IDEV_CHG_FLOATED);
					pm_runtime_put_sync(phy->dev);
					break;
#endif
/* OPPO 2013-10-05 wangjc Modify end */

				default:
					dev_dbg(phy->dev, "chg_det started\n");
/* OPPO 2013-11-18 wangjc Modify begin for detect charger type later */
#ifndef CONFIG_MACH_MSM8974_14001
					charger->start_detection(charger, true);
#else
					/* [email protected], 2014/02/24  Add for solve usb reboot problem */
					cancel_delayed_work_sync(&dotg->detect_work);
					/* [email protected], 2014/03/25  Add for solve usb reboot problem,bug 422328 */
					if (charger)
						charger->start_detection(dotg->charger, false);

					dotg->charger_retry_count = 0;
					dwc3_otg_set_power(phy, 0);
					
					queue_delayed_work(system_nrt_wq, &dotg->detect_work, msecs_to_jiffies(600));
#endif
/* OPPO 2013-11-18 wangjc Modify end */
					break;
				}
			} else {
				/* no charger registered, start peripheral */
				if (dwc3_otg_start_peripheral(&dotg->otg, 1)) {
					/*
					 * Probably set_peripheral not called
					 * yet. We will re-try as soon as it
					 * will be called
					 */
					dev_err(phy->dev, "enter lpm as\n"
						"unable to start B-device\n");
					phy->state = OTG_STATE_UNDEFINED;
					pm_runtime_put_sync(phy->dev);
					return;
				}
			}
		} else {
/* OPPO 2013-12-01 wangjc Add begin for for non standard charger detect, HW_VERSION__12 is dvt */
#ifdef CONFIG_MACH_MSM8974_14001
//#ifdef CONFIG_OPPO_DEVICE_FIND7
#if defined(CONFIG_OPPO_DEVICE_FIND7) || defined(CONFIG_OPPO_DEVICE_FIND7WX)
			if(get_pcb_version() < HW_VERSION__12) {
				cancel_delayed_work_sync(&dotg->non_standard_charger_work);
			}
#endif
#endif
/* OPPO 2013-12-01 wangjc Add end */
#ifdef CONFIG_MACH_MSM8974_14001
/* [email protected], 2014/01/06  Add for solve usb reboot problem */
			cancel_delayed_work_sync(&dotg->detect_work);
#endif /*CONFIG_MACH_MSM8974_14001*/

			if (charger)
				charger->start_detection(dotg->charger, false);

			dotg->charger_retry_count = 0;
			dwc3_otg_set_power(phy, 0);
			dev_dbg(phy->dev, "No device, trying to suspend\n");
			pm_runtime_put_sync(phy->dev);
		}
		break;

	case OTG_STATE_B_PERIPHERAL:
		if (!test_bit(B_SESS_VLD, &dotg->inputs) ||
				!test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "!id || !bsv\n");
			dwc3_otg_start_peripheral(&dotg->otg, 0);
			phy->state = OTG_STATE_B_IDLE;
			if (charger)
				charger->chg_type = DWC3_INVALID_CHARGER;
			work = 1;
		}
		break;

	case OTG_STATE_A_IDLE:
		/* Switch to A-Device*/
		if (test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "id\n");
			phy->state = OTG_STATE_B_IDLE;
			dotg->vbus_retry_count = 0;
			work = 1;
		} else {
			phy->state = OTG_STATE_A_HOST;
			ret = dwc3_otg_start_host(&dotg->otg, 1);
			if ((ret == -EPROBE_DEFER) &&
						dotg->vbus_retry_count < 3) {
				/*
				 * Get regulator failed as regulator driver is
				 * not up yet. Will try to start host after 1sec
				 */
				phy->state = OTG_STATE_A_IDLE;
				dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n");
				delay = VBUS_REG_CHECK_DELAY;
				work = 1;
				dotg->vbus_retry_count++;
			} else if (ret) {
				/*
				 * Probably set_host was not called yet.
				 * We will re-try as soon as it will be called
				 */
				dev_dbg(phy->dev, "enter lpm as\n"
					"unable to start A-device\n");
				phy->state = OTG_STATE_A_IDLE;
				pm_runtime_put_sync(phy->dev);
				return;
			}
		}
		break;

	case OTG_STATE_A_HOST:
		if (test_bit(ID, &dotg->inputs)) {
			dev_dbg(phy->dev, "id\n");
			dwc3_otg_start_host(&dotg->otg, 0);
			phy->state = OTG_STATE_B_IDLE;
			dotg->vbus_retry_count = 0;
			work = 1;
		}
		break;

	default:
		dev_err(phy->dev, "%s: invalid otg-state\n", __func__);

	}

	if (work)
		queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay);
}
Пример #28
0
static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA)
{
	static int power_supply_type;
	struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);
	struct power_supply *saved_usb_psy = NULL;
	struct power_supply *ac_psy = NULL;

	if (!dotg->psy || !dotg->charger) {
		dev_err(phy->dev, "no usb power supply/charger registered\n");
		return 0;
	}

	if (dotg->charger->charging_disabled)
		return 0;

	if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB;
	else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_CDP;
	else if (dotg->charger->chg_type == DWC3_DCP_CHARGER ||
			dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
	else
		power_supply_type = POWER_SUPPLY_TYPE_BATTERY;

	power_supply_set_supply_type(dotg->psy, power_supply_type);

	if ((dotg->charger->chg_type == DWC3_CDP_CHARGER) && mA > 0)
		mA = DWC3_IDEV_CHG_MAX;

	if (slimport_is_connected() && mA) {
		mA = slimport_get_chg_current();
		if (mA > DWC3_IDEV_CHG_MIN)
			dotg->charger->chg_type = DWC3_DCP_CHARGER;
	}

	if (dotg->charger->max_power == mA)
		return 0;

	dev_info(phy->dev, "Avail curr from USB = %u\n", mA);

	ac_psy = power_supply_get_by_name("ac");

	if (dotg->charger->chg_type == DWC3_DCP_CHARGER && ac_psy) {
		pr_info("%s: override dotg->psy to ac->psy\n", __func__);
		saved_usb_psy = dotg->psy;
		dotg->psy = ac_psy;
	}
	pr_info("dotg->charger->max_power = %d "\
			"ma = %d\n", dotg->charger->max_power, mA);

	if (dotg->charger->max_power <= 2 && mA > 2) {
		/* Enable charging */
		if (power_supply_set_online(dotg->psy, true))
			goto psy_error;
		if (!strcmp(dotg->psy->name, "usb")) {
			if (power_supply_set_current_limit(dotg->psy, 1000*mA))
				goto psy_error;
		}
	} else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) {
		/* Disable charging */
		if (power_supply_set_online(dotg->psy, false))
			goto psy_error;
		if (!strcmp(dotg->psy->name, "usb")) {
			if (power_supply_set_online(ac_psy, false))
				goto psy_error;
			/* Set max current limit */
			if (power_supply_set_current_limit(dotg->psy, 0))
				goto psy_error;
		}
	}

	if (saved_usb_psy)
		dotg->psy = saved_usb_psy;

	power_supply_changed(dotg->psy);
	dotg->charger->max_power = mA;
	return 0;

psy_error:
	dev_dbg(phy->dev, "power supply error when setting property\n");
	return -ENXIO;
}
static void muic_mhl_cb(bool otg_enable, int plim)
{
	union power_supply_propval value;
	int i, ret = 0;
	struct power_supply *psy;
	int current_cable_type = POWER_SUPPLY_TYPE_MISC;
	int sub_type = ONLINE_SUB_TYPE_MHL;
	int power_type = ONLINE_POWER_TYPE_UNKNOWN;
	int muic_cable_type = max77803_muic_get_charging_type();

	pr_info("%s: muic cable_type = %d\n",
		__func__, muic_cable_type);
	switch (muic_cable_type) {
	case CABLE_TYPE_SMARTDOCK_MUIC:
	case CABLE_TYPE_SMARTDOCK_TA_MUIC:
	case CABLE_TYPE_SMARTDOCK_USB_MUIC:
		return;
	default:
		break;
	}
	pr_info("muic_mhl_cb:otg_enable=%d, plim=%d\n", otg_enable, plim);

	if (plim == 0x00) {
		pr_info("TA charger 500mA\n");
		power_type = ONLINE_POWER_TYPE_MHL_500;
	} else if (plim == 0x01) {
		pr_info("TA charger 900mA\n");
		power_type = ONLINE_POWER_TYPE_MHL_900;
	} else if (plim == 0x02) {
		pr_info("TA charger 1500mA\n");
		power_type = ONLINE_POWER_TYPE_MHL_1500;
	} else if (plim == 0x03) {
		pr_info("USB charger\n");
		power_type = ONLINE_POWER_TYPE_USB;
	} else
		current_cable_type = POWER_SUPPLY_TYPE_BATTERY;

	if (otg_enable) {
		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_WPC) {
			if (!lpcharge) {
				otg_control(true);
				current_cable_type = POWER_SUPPLY_TYPE_BATTERY;
				power_type = ONLINE_POWER_TYPE_UNKNOWN;
			}
		}
	} else
		otg_control(false);

	for (i = 0; i < 10; i++) {
		psy = power_supply_get_by_name("battery");
		if (psy)
			break;
	}
	if (i == 10) {
		pr_err("%s: fail to get battery ps\n", __func__);
		return;
	}

	value.intval = current_cable_type<<ONLINE_TYPE_MAIN_SHIFT
		| sub_type<<ONLINE_TYPE_SUB_SHIFT
		| power_type<<ONLINE_TYPE_PWR_SHIFT;
	ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE,
		&value);
	if (ret) {
		pr_err("%s: fail to set power_suppy ONLINE property(%d)\n",
			__func__, ret);
	}
}
Пример #30
0
static void bq24297_status_func(struct work_struct *work)
{
	int ret;

	ret = bq24297_read_reg(SYSTEM_STATUS_REG);

	this_chip->pg_stat = (ret & PG_STAT_MASK)>>PG_STAT_SHIFT;
	this_chip->chrg_stat = (ret & CHRG_STAT_MASK)>>CHRG_STAT_SHIFT;
	this_chip->vbus_stat = (ret & VBUS_STAT_MASK)>>VBUS_STAT_SHIFT;

	bq24297_print("%s(), reg[8] = 0x%x\n", __FUNCTION__, ret);

	if (this_chip->pg_stat == 0)
	{
		this_chip->usb_online = 0;
		this_chip->ac_online = 0;
	}
	else if (this_chip->pg_stat == 1 && this_chip->vbus_stat == 0x01)
	{
		this_chip->usb_online = 1;
		this_chip->ac_online = 0;
	}
	else if (this_chip->pg_stat == 1 && this_chip->vbus_stat == 0x02)
	{
		this_chip->usb_online = 0;
		this_chip->ac_online = 1;
	}
	else
	{
		return ;
	}

	if (this_chip->chrg_stat == 0x00)
	{
		this_chip->chrg_stat = POWER_SUPPLY_STATUS_NOT_CHARGING;
	}
	else if (this_chip->chrg_stat == 0x01)
	{
		this_chip->chrg_stat = POWER_SUPPLY_STATUS_CHARGING;
	}
	else if (this_chip->chrg_stat == 0x02)
	{
		this_chip->chrg_stat = POWER_SUPPLY_STATUS_CHARGING;
	}
	else if (this_chip->chrg_stat == 0x03)
	{
		this_chip->chrg_stat = POWER_SUPPLY_STATUS_FULL;
	}

	if (this_chip->ac_online)
		bq24297_set_ac_charge_current();
	else if (this_chip->usb_online)
		bq24297_set_usb_charge_current();
	else
		bq24297_set_usb_charge_current();


	if (!this_chip->battery)
		this_chip->battery = power_supply_get_by_name("battery");
	if (this_chip->battery)
		power_supply_changed(this_chip->battery);
}