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