static void bcmpmu_otg_xceiv_vbus_a_invalid_handler(struct work_struct *work)
{
	struct bcmpmu_otg_xceiv_data *xceiv_data =
	    container_of(work, struct bcmpmu_otg_xceiv_data,
			 bcm_otg_vbus_a_invalid_work);

	dev_info(xceiv_data->dev, "A session invalid\n");

	if (!bcm_hsotgctrl_get_clk_count())
		bcm_hsotgctrl_en_clock(true);

	/* Inform the core of session invalid level  */
	bcm_hsotgctrl_phy_set_vbus_stat(false);

	if (xceiv_data->otg_enabled) {
		/* Stop Vbus discharge */
		bcmpmu_usb_set(xceiv_data->bcmpmu, BCMPMU_USB_CTRL_DISCHRG_VBUS,
			       0);

		if (bcmpmu_otg_xceiv_check_id_gnd(xceiv_data)) {
			/* Use n-1 method for ADP rise time comparison */
			bcmpmu_usb_set(xceiv_data->bcmpmu,
				       BCMPMU_USB_CTRL_SET_ADP_COMP_METHOD, 1);
			if (xceiv_data->otg_xceiver.otg_vbus_off)
				schedule_delayed_work(&xceiv_data->
					bcm_otg_delayed_adp_work,
					msecs_to_jiffies
					  (T_NO_ADP_DELAY_MIN_IN_MS));
			else
				bcm_otg_do_adp_probe(xceiv_data);
		} else if (!bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data)) {
			if (xceiv_data->otg_xceiver.otg_srp_reqd) {
				/* Start Session End SRP timer */
				xceiv_data->otg_xceiver.sess_end_srp_timer.
				    expires =
				    jiffies +
				    msecs_to_jiffies
				    (T_SESS_END_SRP_START_IN_MS);
				add_timer(&xceiv_data->otg_xceiver.
					  sess_end_srp_timer);
			} else
				bcm_otg_do_adp_sense(xceiv_data);
		}
	} else {
		bool id_default_host = false;

		id_default_host =
			bcmpmu_otg_xceiv_check_id_gnd(xceiv_data) ||
			bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data);

		if (!id_default_host) {
			atomic_notifier_call_chain(&xceiv_data->otg_xceiver.
						   xceiver.notifier,
						   USB_EVENT_NONE, NULL);
		}
	}
}
static int bcmpmu_otg_xceiv_set_vbus_power(struct otg_transceiver *otg,
					   unsigned int ma)
{
	struct bcmpmu_otg_xceiv_data *xceiv_data = dev_get_drvdata(otg->dev);

	return bcmpmu_usb_set(xceiv_data->bcmpmu,
			       BCMPMU_USB_CTRL_CHRG_CURR_LMT, ma);
}
static void bcmpmu_otg_xceiv_vbus_invalid_handler(struct work_struct *work)
{
	struct bcmpmu_otg_xceiv_data *xceiv_data =
	    container_of(work, struct bcmpmu_otg_xceiv_data,
			 bcm_otg_vbus_invalid_work);
	dev_info(xceiv_data->dev, "Vbus invalid\n");

	if (xceiv_data->otg_enabled) {
		/* Need to discharge Vbus quickly to session invalid level */
		bcmpmu_usb_set(xceiv_data->bcmpmu, BCMPMU_USB_CTRL_DISCHRG_VBUS,
			       1);
	}
}
static int bcmpmu_otg_xceiv_set_otg_enable(struct otg_transceiver *otg, bool enable)
{
    struct bcmpmu_otg_xceiv_data *xceiv_data = dev_get_drvdata(otg->dev);

    if (!xceiv_data)
        return -EINVAL;

    xceiv_data->otg_enabled = enable;

    bcmpmu_usb_set(xceiv_data->bcmpmu,
                   BCMPMU_USB_CTRL_SET_OTG_ENABLE,
                   enable ? 1 : 0);

    return 0;
}
static int bcmpmu_otg_xceiv_set_vbus_power(struct otg_transceiver *otg, unsigned int ma)
{
    struct bcmpmu_otg_xceiv_data *xceiv_data = dev_get_drvdata(otg->dev);
    int ret = 0;

    /* We need not make use of USB_EVENT_CHARGER event */
    if (xceiv_data->usb_charger_type == PMU_USB_TYPE_SDP) {
        /* Set charging current from USB stack only
         * if it is SDP
         */
        ret = bcmpmu_usb_set(xceiv_data->bcmpmu,
                             BCMPMU_USB_CTRL_CHRG_CURR_LMT, ma);
    }

    return ret;
}
static void bcmpmu_otg_xceiv_id_change_handler(struct work_struct *work)
{
    struct bcmpmu_otg_xceiv_data *xceiv_data =
        container_of(work, struct bcmpmu_otg_xceiv_data,
                     bcm_otg_id_status_change_work);
    unsigned int new_id;

    bool id_gnd = false;
    bool id_rid_a = false;
    bool id_rid_c = false;

    dev_info(xceiv_data->dev, "ID change detected\n");

    bcmpmu_usb_get(xceiv_data->bcmpmu,
                   BCMPMU_USB_CTRL_GET_ID_VALUE,
                   &new_id);

    if (xceiv_data->otg_enabled) {
        /* Stop any stale ADP probe/sense attempts */
        bcm_otg_do_adp_probe(xceiv_data, false);
        bcm_otg_do_adp_sense(xceiv_data, false);

        /* Use n and n-1 comparison method */
        bcmpmu_usb_set(xceiv_data->bcmpmu,
                       BCMPMU_USB_CTRL_SET_ADP_COMP_METHOD, 1);
    }

    if ((xceiv_data->prev_otg_id != new_id) ||
            xceiv_data->otg_enabled) {
        id_gnd = bcmpmu_otg_xceiv_check_id_gnd(xceiv_data);
        id_rid_a = bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data);
        id_rid_c = bcmpmu_otg_xceiv_check_id_rid_c(xceiv_data);

        bcm_hsotgctrl_phy_set_id_stat(!(id_gnd || id_rid_a));

        atomic_notifier_call_chain(&xceiv_data->otg_xceiver.
                                   xceiver.notifier, USB_EVENT_ID, NULL);
    }

    /* Update local ID copy */
    xceiv_data->prev_otg_id = new_id;

}