Ejemplo n.º 1
0
static int chg_uv(struct smb349_charger *chip, u8 status)
{
	/* use this to detect USB insertion only if !apsd */
	if (chip->disable_apsd && status == 0) {
		chip->chg_present = true;
		dev_dbg(chip->dev, "%s updating usb_psy present=%d",
				__func__, chip->chg_present);
		power_supply_set_supply_type(chip->usb_psy,
						POWER_SUPPLY_TYPE_USB);
		power_supply_set_present(chip->usb_psy, chip->chg_present);
	}

	if (status != 0) {
		chip->chg_present = false;
		dev_dbg(chip->dev, "%s updating usb_psy present=%d",
				__func__, chip->chg_present);
		power_supply_set_supply_type(chip->usb_psy,
						POWER_SUPPLY_TYPE_UNKNOWN);
		power_supply_set_present(chip->usb_psy, chip->chg_present);
	}

	dev_dbg(chip->dev, "chip->chg_present = %d\n", chip->chg_present);

	return 0;
}
Ejemplo n.º 2
0
static ssize_t switch_store_usb_lock(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	int lock;
	struct power_supply *psy;

	psy = power_supply_get_by_name("dwc-usb");
	if (!psy) {
		pr_info("%s: couldn't get usb power supply\n", __func__);
		return -EINVAL;
	}

	if (!strncmp(buf, "0", 1))
		lock = 0;
	else if (!strncmp(buf, "1", 1))
		lock = 1;
	else {
		pr_warn("%s: Wrong command\n", __func__);
		return count;
	}

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

	if (lock != is_usb_locked) {
		is_usb_locked = lock;

		if (lock)
			power_supply_set_present(psy, USB_CABLE_DETACHED);
	}

	return count;
}
Ejemplo n.º 3
0
/* usb cable call back function */
void max77803_muic_usb_cb(u8 usb_mode)
{
	struct power_supply *psy;

	psy = power_supply_get_by_name("dwc-usb");
	if (!psy) {
		pr_info("%s: couldn't get usb power supply\n", __func__);
		return;
	}

    pr_info("%s: MUIC attached: %d\n", __func__, usb_mode);

#ifdef CONFIG_SEC_LOCALE_KOR
	if (is_usb_locked) {
		pr_info("%s: usb locked by mdm\n", __func__);
		return;
	}
#endif

	if (usb_mode == USB_CABLE_DETACHED
		|| usb_mode == USB_CABLE_ATTACHED) {
		if (usb_mode == USB_CABLE_ATTACHED)
			max77803_muic_set_safeout(AP_USB_MODE);
#if defined(CONFIG_SEC_H_PROJECT)
			set_redriver_power(usb_mode);
#endif
		pr_info("usb: dwc3 power supply set(%d)", usb_mode);
		power_supply_set_present(psy, usb_mode);
		if (usb_mode == USB_CABLE_DETACHED) {
			set_ncm_ready(0);
#if defined(CONFIG_SEC_H_PROJECT)
			usb30en = 0;
			set_redriver_power(usb_mode);
#endif
		}
#ifdef CONFIG_USB_HOST_NOTIFY
	} else if (usb_mode == USB_OTGHOST_DETACHED
		|| usb_mode == USB_OTGHOST_ATTACHED) {

		if (usb_mode == USB_OTGHOST_DETACHED) {
			pr_info("USB Host detached");
			sec_otg_notify(HNOTIFY_ID_PULL);
		} else {
			pr_info("USB Host attached");
			sec_otg_notify(HNOTIFY_ID);
		}

	} else if (usb_mode == USB_POWERED_HOST_DETACHED
		|| usb_mode == USB_POWERED_HOST_ATTACHED) {
		if (usb_mode == USB_POWERED_HOST_DETACHED){
			pr_info("USB Host HNOTIFY_SMARTDOCK_OFF");
			sec_otg_notify(HNOTIFY_SMARTDOCK_OFF);
		}else{
			pr_info("USB Host HNOTIFY_SMARTDOCK_ON");
			sec_otg_notify(HNOTIFY_SMARTDOCK_ON);
		}
#endif
	}
}
Ejemplo n.º 4
0
int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
			 struct msc_command_struct *req)
{
	switch (req->command) {
	case MHL_WRITE_STAT:
		if (req->offset == MHL_STATUS_REG_LINK_MODE) {
			if (req->payload.data[0]
			    & MHL_STATUS_PATH_ENABLED) {
				/* Enable TMDS output */
				mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
				if (mhl_ctrl->devcap_state == MHL_DEVCAP_ALL) {
					mhl_drive_hpd(mhl_ctrl, HPD_UP);
					mhl_ctrl->tmds_ctrl_en = true;
				}
			} else {
				/* Disable TMDS output */
				mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
				mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
			}
		}
		break;
	case MHL_READ_DEVCAP:
		mhl_update_devcap(mhl_ctrl,
			req->offset, req->retval);
		mhl_ctrl->devcap_state |= BIT(req->offset);
		switch (req->offset) {
		case MHL_DEV_CATEGORY_OFFSET:
			if (req->retval & MHL_DEV_CATEGORY_POW_BIT)
				pr_debug("%s: devcap pow bit set\n",
					 __func__);
			else
				pr_debug("%s: devcap pow bit unset\n",
					 __func__);
			power_supply_set_present(&mhl_ctrl->mhl_psy,
				!!(req->retval & MHL_DEV_CATEGORY_POW_BIT));
			break;
		case DEVCAP_OFFSET_FEATURE_FLAG:
			mhl_rap_send_msc_msg(mhl_ctrl, MHL_RAP_CONTENT_ON);
			break;
		case DEVCAP_OFFSET_RESERVED:
			if (mhl_qualify_path_enable(mhl_ctrl)) {
				mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
				mhl_drive_hpd(mhl_ctrl, HPD_UP);
				mhl_ctrl->tmds_ctrl_en = true;
			}
			break;
		}
		break;
	case MHL_WRITE_BURST:
		mhl_msc_send_set_int(
			mhl_ctrl,
			MHL_RCHANGE_INT,
			MHL_INT_DSCR_CHG,
			MSC_PRIORITY_SEND);
		break;
	}
	return 0;
}
static irqreturn_t qpnp_usbdetect_vbus_irq(int irq, void *data)
{
	struct qpnp_usbdetect *usb = data;
	int vbus;

	vbus = !!irq_read_line(irq);
	power_supply_set_present(usb->usb_psy, vbus);

	return IRQ_HANDLED;
}
Ejemplo n.º 6
0
/* usb cable call back function */
static void muic_usb_cb(u8 usb_mode)
{
	struct power_supply *psy;
	int ret;

	psy = power_supply_get_by_name("usb");
	if (!psy) {
		pr_err("%s: couldn't get usb power supply\n", __func__);
		return;
	}
	pr_info("%s:%s MUIC usb_cb:%d\n", MUIC_DEV_NAME, __func__, usb_mode);
	switch (usb_mode) {
	case USB_CABLE_DETACHED:
		pr_info("usb: muic: USB_CABLE_DETACHED(%d)\n", usb_mode);
		ret = power_supply_set_present(psy, usb_mode);
		if (ret < 0) {
			pr_err("%s:coundn't set power supply state detached\n",
				 __func__);
			return;
		}
		#ifdef CONFIG_SWITCH
		switch_set_state(&switch_usb, usb_mode);
		#endif
		break;
	case USB_CABLE_ATTACHED:
		pr_info("usb: muic: USB_CABLE_ATTACHED(%d)\n", usb_mode);

		#ifdef CONFIG_SWITCH
		switch_set_state(&switch_usb, usb_mode);
		#endif

		ret = power_supply_set_present(psy, usb_mode);
		if (ret < 0) {
			pr_err("%s:couldn't set power supply state attached\n",
				 __func__);
			return;
		}
		break;
	default:
		pr_info("usb: muic: invalid mode%d\n", usb_mode);
	}
}
Ejemplo n.º 7
0
static void fsa9485_usb_cdp_cb(bool attached)
{
	union power_supply_propval value;
	int i, ret = 0;
	struct power_supply *psy;

	pr_info("fsa9485_usb_cdp_cb attached %d\n", attached);

	set_cable_status =
		attached ? CABLE_TYPE_CDP : CABLE_TYPE_NONE;

	psy = power_supply_get_by_name("dwc-usb");
	if (!psy) {
		pr_info("%s: couldn't get usb power supply\n", __func__);
		return;
	}
	pr_info("%s: MUIC attached: %d\n", __func__, attached);

	power_supply_set_present(psy, attached);


	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;
	}

	switch (set_cable_status) {
	case CABLE_TYPE_CDP:
		value.intval = POWER_SUPPLY_TYPE_USB_CDP;
		break;
	case CABLE_TYPE_NONE:
		value.intval = POWER_SUPPLY_TYPE_BATTERY;
		break;
	default:
		pr_err("invalid status:%d\n", attached);
		return;
	}

	current_cable_type = value.intval;

	value.intval = current_cable_type<<ONLINE_TYPE_MAIN_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);
	}
}
Ejemplo n.º 8
0
static irqreturn_t smb349_chg_valid_handler(int irq, void *dev_id)
{
	struct smb349_charger *chip = dev_id;
	int present;

	present = gpio_get_value_cansleep(chip->chg_valid_gpio);
	if (present < 0) {
		dev_err(chip->dev, "Couldn't read chg_valid gpio=%d\n",
						chip->chg_valid_gpio);
		return IRQ_HANDLED;
	}
	present ^= chip->chg_valid_act_low;

	dev_dbg(chip->dev, "%s: chg_present = %d\n", __func__, present);

	if (present != chip->chg_present) {
		chip->chg_present = present;
		dev_dbg(chip->dev, "%s updating usb_psy present=%d",
				__func__, chip->chg_present);
		power_supply_set_present(chip->usb_psy, chip->chg_present);
	}

	return IRQ_HANDLED;
}
Ejemplo n.º 9
0
static void bq24192_irq_worker(struct work_struct *work)
{
	struct bq24192_chip *chip =
		container_of(work, struct bq24192_chip, irq_work);
	union power_supply_propval ret = {0,};
	bool ext_pwr;
	bool wlc_pwr = 0;
	bool chg_done = false;
	u8 temp;
	int rc;
	unsigned long flags;

	wake_lock(&chip->irq_wake_lock);

	msleep(100 * chip->irq_scheduled_time_status);

	rc = bq24192_read_reg(chip->client, SYSTEM_STATUS_REG, &temp);
	/* Open up for next possible interrupt handler beyond read reg
	 * asap, lest we miss an interrupt
	 */
	spin_lock_irqsave(&chip->irq_work_lock, flags);
	chip->irq_scheduled_time_status = 0;
	spin_unlock_irqrestore(&chip->irq_work_lock, flags);

	if (rc) {
		pr_err("failed to read SYSTEM_STATUS_REG rc=%d\n", rc);
		goto irq_worker_exit;
	}

	ext_pwr = !!(temp & PG_STAT_MASK);
	chg_done = (temp & CHARGING_MASK) == 0x30 ? true : false;
	if (chg_done) {
		if (chip->batt_health != POWER_SUPPLY_HEALTH_OVERHEAT &&
				bq24192_get_soc_from_batt_psy(chip) < 100) {
			wake_lock(&chip->extra_chg_lock);
			bq24192_enable_chg_term(chip, false);
			bq24192_trigger_recharge(chip);
			schedule_delayed_work(&chip->extra_chg_work,
					msecs_to_jiffies(EXTRA_CHG_TIME_MS));
		} else {
			if (chip->batt_health != POWER_SUPPLY_HEALTH_OVERHEAT)
				bq24192_set_rechg_voltage(chip, VRECHG_300MV);
			power_supply_changed(&chip->ac_psy);
			pr_info("charge done!!\n");
		}
	}

	if (chip->wlc_psy) {
		chip->wlc_psy->get_property(chip->wlc_psy,
				POWER_SUPPLY_PROP_PRESENT, &ret);
		wlc_pwr = ret.intval;
	}

	if ((chip->ext_pwr ^ ext_pwr) || (chip->wlc_pwr ^ wlc_pwr)) {
		pr_info("power source changed! ext_pwr = %d wlc_pwr = %d\n",
				ext_pwr, wlc_pwr);
		if (wake_lock_active(&chip->icl_wake_lock))
			wake_unlock(&chip->icl_wake_lock);
		if (wake_lock_active(&chip->extra_chg_lock))
			wake_unlock(&chip->extra_chg_lock);
		cancel_delayed_work_sync(&chip->input_limit_work);
		cancel_delayed_work_sync(&chip->therm_work);
		cancel_delayed_work_sync(&chip->extra_chg_work);
		bq24192_enable_chg_term(chip, true);
		bq24192_step_down_detect_disable(chip);
		chip->saved_ibat_ma = 0;
		chip->set_chg_current_ma = chip->chg_current_ma;
		chip->max_input_i_ma = INPUT_CURRENT_LIMIT_MAX_MA;

		if (chip->wlc_psy) {
			if (wlc_pwr && ext_pwr) {
				chip->wlc_pwr = true;
				power_supply_set_online(chip->wlc_psy, true);
			} else if (chip->wlc_pwr && !(ext_pwr && wlc_pwr)) {
				chip->wlc_pwr = false;
				power_supply_set_online(chip->wlc_psy, false);
			}
		}

		if (!wlc_pwr) {
			pr_info("notify vbus to usb otg ext_pwr = %d\n", ext_pwr);
			power_supply_set_present(chip->usb_psy, ext_pwr);
		}

		chip->ext_pwr = ext_pwr;
	}

irq_worker_exit:
	wake_lock_timeout(&chip->irq_wake_lock, 2*HZ);
}
Ejemplo n.º 10
0
static void fsa9485_otg_cb(bool attached)
{
#ifdef CONFIG_USB_HOST_NOTIFY
	static bool is_active;
	if (is_active == attached) {
		pr_info("fsa9485_otg_cb attached %d duplicated, skip\n", attached);
		return;
	}
	is_active = attached;
#endif
#if 0
	union power_supply_propval value;
	int i, ret = 0;
	struct power_supply *psy;
#endif

	pr_info("fsa9485_otg_cb attached %d\n", attached);

#if 0
	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 (attached)
		current_cable_type = POWER_SUPPLY_TYPE_OTG;
	else
		current_cable_type = POWER_SUPPLY_TYPE_BATTERY;

	value.intval = current_cable_type<<ONLINE_TYPE_MAIN_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);
#endif
#ifdef CONFIG_USB_HOST_NOTIFY
	if (attached) {
		pr_info("%s USB Host attached", __func__);
		sec_otg_notify(HNOTIFY_ID);
	} else {
		pr_info("%s USB Host detached", __func__);
		sec_otg_notify(HNOTIFY_ID_PULL);
	}
#endif
}

extern int vienna_usb_rdrv_pin;

static void fsa9485_usb_cb(bool attached)
{
	union power_supply_propval value;
	int i, ret = 0;
	struct power_supply *psy;

	pr_info("fsa9485_usb_cb attached %d\n", attached);
	set_cable_status = attached ? CABLE_TYPE_USB : CABLE_TYPE_NONE;

        /* Vienna SS - USB 3.0 redriver enable/disable */
#if defined(CONFIG_MACH_VIENNAEUR)
	gpio_set_value(vienna_usb_rdrv_pin, attached);
	pr_info("%s vienna_usb_rdrv_pin = %d, enable=%d\n",
		__func__,
		vienna_usb_rdrv_pin,
		attached);
#endif

	psy = power_supply_get_by_name("dwc-usb");
	if (!psy) {
		pr_info("%s: couldn't get usb power supply\n", __func__);
		return;
	}
	pr_info("%s: MUIC attached: %d\n", __func__, attached);

	power_supply_set_present(psy, attached);

#if defined(CONFIG_TOUCHSCREEN_ATMEL_MXT1664S)
	mxt_tsp_charger_infom(attached);
#endif

	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;
	}

	switch (set_cable_status) {
	case CABLE_TYPE_USB:
		value.intval = POWER_SUPPLY_TYPE_USB;
		break;
	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;

	value.intval = current_cable_type<<ONLINE_TYPE_MAIN_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);
	}
}

static void fsa9485_charger_cb(bool attached)
{
	union power_supply_propval value;
	int i, ret = 0;
	struct power_supply *psy;

	pr_info("%s attached %d\n", __func__, attached);
	set_cable_status = attached ? CABLE_TYPE_AC : CABLE_TYPE_NONE;

//	msm_otg_set_charging_state(attached);

	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 defined(CONFIG_TOUCHSCREEN_ATMEL_MXT1664S)
	mxt_tsp_charger_infom(attached);
#endif

#ifdef CONFIG_TOUCHSCREEN_MMS144
	if (charger_callbacks && charger_callbacks->inform_charger)
		charger_callbacks->inform_charger(charger_callbacks, attached);
#endif

	switch (set_cable_status) {
	case CABLE_TYPE_AC:
		value.intval = POWER_SUPPLY_TYPE_MAINS;
		break;
	case CABLE_TYPE_NONE:
		value.intval = POWER_SUPPLY_TYPE_BATTERY;
		break;
	default:
		pr_err("invalid status:%d\n", attached);
		return;
	}

	current_cable_type = value.intval;

	value.intval = current_cable_type<<ONLINE_TYPE_MAIN_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);
	}
}

static void fsa9485_uart_cb(bool attached)
{
	pr_info("fsa9485_uart_cb attached %d\n", attached);

	set_cable_status = attached ? CABLE_TYPE_UARTOFF : CABLE_TYPE_NONE;
}
int smb358_chg_uv(struct opchg_charger *chip, u8 status)
{
	int rc = 0;

	if(chip->chg_present && (status == 0)){
		pr_err("%s chg has plugged in,return\n",__func__);
		return 0;
	}
	
	opchg_inout_charge_parameters(chip);
	//opchg_switch_to_usbin(chip,!status);

    if (status == 0) {
        chip->g_chg_in = 1;
		if(chip->g_is_wakeup == 0){ //if awake not be lock,lock it here else do nothing
            __pm_stay_awake(&chip->source);
            chip->g_is_wakeup= 1;
        }		
    }
    else {
        chip->g_chg_in = 0;
        schedule_delayed_work(&chip->opchg_delayed_wakeup_work,
                            round_jiffies_relative(msecs_to_jiffies(2000)));
    }
    
    /* use this to detect USB insertion only if !apsd */
    if (chip->disable_apsd && status == 0) {
        chip->chg_present = true;
        dev_dbg(chip->dev, "%s updating usb_psy present=%d", __func__, chip->chg_present);
        power_supply_set_supply_type(chip->usb_psy, POWER_SUPPLY_TYPE_USB);
        power_supply_set_present(chip->usb_psy, chip->chg_present);	
	}
	
    if (status != 0) {
        chip->chg_present = false;
        dev_dbg(chip->dev, "%s updating usb_psy present=%d", __func__, chip->chg_present);
        /* we can't set usb_psy as UNKNOWN so early, it'll lead USERSPACE issue */
        power_supply_set_present(chip->usb_psy, chip->chg_present);

		if (chip->bms_controlled_charging){
			/*
			* Disable SOC based USB suspend to enable charging on
			* USB insertion.
			*/
			rc = smb358_charging_disable(chip, SOC, false);
			if (rc < 0)
				dev_err(chip->dev,"Couldn't disable usb suspend rc = %d\n",rc);
		}
    }
	
    //chip->BMT_status.charger_exist = chip->chg_present;
	
    power_supply_changed(chip->usb_psy);
	
	if(is_project(OPPO_15005)){
		schedule_work(&chip->opchg_modify_tp_param_work);
	}
    dev_dbg(chip->dev, "chip->chg_present = %d\n", chip->chg_present);
    
    return 0;
}
Ejemplo n.º 12
0
static int apsd_complete(struct smb349_charger *chip, u8 status)
{
	int rc;
	u8 reg = 0;
	enum power_supply_type type = POWER_SUPPLY_TYPE_UNKNOWN;

	/*
	 * If apsd is disabled, charger detection is done by
	 * DCIN UV irq.
	 * status = ZERO - indicates charger removed, handled
	 * by DCIN UV irq
	 */
	if (chip->disable_apsd || status == 0) {
		dev_dbg(chip->dev, "APSD %s, status = %d\n",
			chip->disable_apsd ? "disabled" : "enabled", !!status);
		return 0;
	}

	rc = smb349_read_reg(chip, STATUS_D_REG, &reg);
	if (rc) {
		dev_err(chip->dev, "Couldn't read STATUS D rc = %d\n", rc);
		return rc;
	}

	dev_dbg(chip->dev, "%s: STATUS_D_REG=%x\n", __func__, reg);

	switch (reg) {
	case STATUS_D_PORT_ACA_DOCK:
	case STATUS_D_PORT_ACA_C:
	case STATUS_D_PORT_ACA_B:
	case STATUS_D_PORT_ACA_A:
		type = POWER_SUPPLY_TYPE_USB_ACA;
		break;
	case STATUS_D_PORT_CDP:
		type = POWER_SUPPLY_TYPE_USB_CDP;
		break;
	case STATUS_D_PORT_DCP:
		type = POWER_SUPPLY_TYPE_USB_DCP;
		break;
	case STATUS_D_PORT_SDP:
		type = POWER_SUPPLY_TYPE_USB;
		break;
	case STATUS_D_PORT_OTHER:
		type = POWER_SUPPLY_TYPE_USB_DCP;
		break;
	default:
		type = POWER_SUPPLY_TYPE_USB;
		break;
	}

	chip->chg_present = !!status;

	/*
	 * Report the charger type as UNKNOWN if the
	 * apsd-fail flag is set. This nofifies the USB driver
	 * to initiate a s/w based charger type detection.
	 */
	if (chip->workaround_flags & WRKARND_APSD_FAIL)
		type = POWER_SUPPLY_TYPE_UNKNOWN;

	dev_dbg(chip->dev, "APSD complete. USB type detected=%d chg_present=%d",
						type, chip->chg_present);

	power_supply_set_supply_type(chip->usb_psy, type);

	 /* SMB is now done sampling the D+/D- lines, indicate USB driver */
	dev_dbg(chip->dev, "%s updating usb_psy present=%d", __func__,
			chip->chg_present);
	power_supply_set_present(chip->usb_psy, chip->chg_present);

	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;
}