162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * phy.c -- USB phy handling 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004-2013 Texas Instruments 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/export.h> 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/usb/phy.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Default current range by charger type. */ 1862306a36Sopenharmony_ci#define DEFAULT_SDP_CUR_MIN 2 1962306a36Sopenharmony_ci#define DEFAULT_SDP_CUR_MAX 500 2062306a36Sopenharmony_ci#define DEFAULT_SDP_CUR_MIN_SS 150 2162306a36Sopenharmony_ci#define DEFAULT_SDP_CUR_MAX_SS 900 2262306a36Sopenharmony_ci#define DEFAULT_DCP_CUR_MIN 500 2362306a36Sopenharmony_ci#define DEFAULT_DCP_CUR_MAX 5000 2462306a36Sopenharmony_ci#define DEFAULT_CDP_CUR_MIN 1500 2562306a36Sopenharmony_ci#define DEFAULT_CDP_CUR_MAX 5000 2662306a36Sopenharmony_ci#define DEFAULT_ACA_CUR_MIN 1500 2762306a36Sopenharmony_ci#define DEFAULT_ACA_CUR_MAX 5000 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic LIST_HEAD(phy_list); 3062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(phy_lock); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct phy_devm { 3362306a36Sopenharmony_ci struct usb_phy *phy; 3462306a36Sopenharmony_ci struct notifier_block *nb; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const char *const usb_chger_type[] = { 3862306a36Sopenharmony_ci [UNKNOWN_TYPE] = "USB_CHARGER_UNKNOWN_TYPE", 3962306a36Sopenharmony_ci [SDP_TYPE] = "USB_CHARGER_SDP_TYPE", 4062306a36Sopenharmony_ci [CDP_TYPE] = "USB_CHARGER_CDP_TYPE", 4162306a36Sopenharmony_ci [DCP_TYPE] = "USB_CHARGER_DCP_TYPE", 4262306a36Sopenharmony_ci [ACA_TYPE] = "USB_CHARGER_ACA_TYPE", 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const char *const usb_chger_state[] = { 4662306a36Sopenharmony_ci [USB_CHARGER_DEFAULT] = "USB_CHARGER_DEFAULT", 4762306a36Sopenharmony_ci [USB_CHARGER_PRESENT] = "USB_CHARGER_PRESENT", 4862306a36Sopenharmony_ci [USB_CHARGER_ABSENT] = "USB_CHARGER_ABSENT", 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic struct usb_phy *__usb_find_phy(struct list_head *list, 5262306a36Sopenharmony_ci enum usb_phy_type type) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct usb_phy *phy = NULL; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci list_for_each_entry(phy, list, head) { 5762306a36Sopenharmony_ci if (phy->type != type) 5862306a36Sopenharmony_ci continue; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return phy; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic struct usb_phy *__of_usb_find_phy(struct device_node *node) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct usb_phy *phy; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (!of_device_is_available(node)) 7162306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci list_for_each_entry(phy, &phy_list, head) { 7462306a36Sopenharmony_ci if (node != phy->dev->of_node) 7562306a36Sopenharmony_ci continue; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return phy; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic struct usb_phy *__device_to_usb_phy(const struct device *dev) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct usb_phy *usb_phy; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci list_for_each_entry(usb_phy, &phy_list, head) { 8862306a36Sopenharmony_ci if (usb_phy->dev == dev) 8962306a36Sopenharmony_ci return usb_phy; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return NULL; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void usb_phy_set_default_current(struct usb_phy *usb_phy) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN; 9862306a36Sopenharmony_ci usb_phy->chg_cur.sdp_max = DEFAULT_SDP_CUR_MAX; 9962306a36Sopenharmony_ci usb_phy->chg_cur.dcp_min = DEFAULT_DCP_CUR_MIN; 10062306a36Sopenharmony_ci usb_phy->chg_cur.dcp_max = DEFAULT_DCP_CUR_MAX; 10162306a36Sopenharmony_ci usb_phy->chg_cur.cdp_min = DEFAULT_CDP_CUR_MIN; 10262306a36Sopenharmony_ci usb_phy->chg_cur.cdp_max = DEFAULT_CDP_CUR_MAX; 10362306a36Sopenharmony_ci usb_phy->chg_cur.aca_min = DEFAULT_ACA_CUR_MIN; 10462306a36Sopenharmony_ci usb_phy->chg_cur.aca_max = DEFAULT_ACA_CUR_MAX; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/** 10862306a36Sopenharmony_ci * usb_phy_notify_charger_work - notify the USB charger state 10962306a36Sopenharmony_ci * @work: the charger work to notify the USB charger state 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * This work can be issued when USB charger state has been changed or 11262306a36Sopenharmony_ci * USB charger current has been changed, then we can notify the current 11362306a36Sopenharmony_ci * what can be drawn to power user and the charger state to userspace. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * If we get the charger type from extcon subsystem, we can notify the 11662306a36Sopenharmony_ci * charger state to power user automatically by usb_phy_get_charger_type() 11762306a36Sopenharmony_ci * issuing from extcon subsystem. 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * If we get the charger type from ->charger_detect() instead of extcon 12062306a36Sopenharmony_ci * subsystem, the usb phy driver should issue usb_phy_set_charger_state() 12162306a36Sopenharmony_ci * to set charger state when the charger state has been changed. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_cistatic void usb_phy_notify_charger_work(struct work_struct *work) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work); 12662306a36Sopenharmony_ci unsigned int min, max; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci switch (usb_phy->chg_state) { 12962306a36Sopenharmony_ci case USB_CHARGER_PRESENT: 13062306a36Sopenharmony_ci usb_phy_get_charger_current(usb_phy, &min, &max); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy); 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci case USB_CHARGER_ABSENT: 13562306a36Sopenharmony_ci usb_phy_set_default_current(usb_phy); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy); 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci default: 14062306a36Sopenharmony_ci dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n", 14162306a36Sopenharmony_ci usb_phy->chg_state); 14262306a36Sopenharmony_ci return; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci kobject_uevent(&usb_phy->dev->kobj, KOBJ_CHANGE); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int usb_phy_uevent(const struct device *dev, struct kobj_uevent_env *env) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci const struct usb_phy *usb_phy; 15162306a36Sopenharmony_ci char uchger_state[50] = { 0 }; 15262306a36Sopenharmony_ci char uchger_type[50] = { 0 }; 15362306a36Sopenharmony_ci unsigned long flags; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci spin_lock_irqsave(&phy_lock, flags); 15662306a36Sopenharmony_ci usb_phy = __device_to_usb_phy(dev); 15762306a36Sopenharmony_ci spin_unlock_irqrestore(&phy_lock, flags); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (!usb_phy) 16062306a36Sopenharmony_ci return -ENODEV; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci snprintf(uchger_state, ARRAY_SIZE(uchger_state), 16362306a36Sopenharmony_ci "USB_CHARGER_STATE=%s", usb_chger_state[usb_phy->chg_state]); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci snprintf(uchger_type, ARRAY_SIZE(uchger_type), 16662306a36Sopenharmony_ci "USB_CHARGER_TYPE=%s", usb_chger_type[usb_phy->chg_type]); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (add_uevent_var(env, uchger_state)) 16962306a36Sopenharmony_ci return -ENOMEM; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (add_uevent_var(env, uchger_type)) 17262306a36Sopenharmony_ci return -ENOMEM; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void __usb_phy_get_charger_type(struct usb_phy *usb_phy) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_SDP) > 0) { 18062306a36Sopenharmony_ci usb_phy->chg_type = SDP_TYPE; 18162306a36Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_PRESENT; 18262306a36Sopenharmony_ci } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_CDP) > 0) { 18362306a36Sopenharmony_ci usb_phy->chg_type = CDP_TYPE; 18462306a36Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_PRESENT; 18562306a36Sopenharmony_ci } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_DCP) > 0) { 18662306a36Sopenharmony_ci usb_phy->chg_type = DCP_TYPE; 18762306a36Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_PRESENT; 18862306a36Sopenharmony_ci } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_ACA) > 0) { 18962306a36Sopenharmony_ci usb_phy->chg_type = ACA_TYPE; 19062306a36Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_PRESENT; 19162306a36Sopenharmony_ci } else { 19262306a36Sopenharmony_ci usb_phy->chg_type = UNKNOWN_TYPE; 19362306a36Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_ABSENT; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci schedule_work(&usb_phy->chg_work); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/** 20062306a36Sopenharmony_ci * usb_phy_get_charger_type - get charger type from extcon subsystem 20162306a36Sopenharmony_ci * @nb: the notifier block to determine charger type 20262306a36Sopenharmony_ci * @state: the cable state 20362306a36Sopenharmony_ci * @data: private data 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * Determin the charger type from extcon subsystem which also means the 20662306a36Sopenharmony_ci * charger state has been chaned, then we should notify this event. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic int usb_phy_get_charger_type(struct notifier_block *nb, 20962306a36Sopenharmony_ci unsigned long state, void *data) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct usb_phy *usb_phy = container_of(nb, struct usb_phy, type_nb); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci __usb_phy_get_charger_type(usb_phy); 21462306a36Sopenharmony_ci return NOTIFY_OK; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/** 21862306a36Sopenharmony_ci * usb_phy_set_charger_current - set the USB charger current 21962306a36Sopenharmony_ci * @usb_phy: the USB phy to be used 22062306a36Sopenharmony_ci * @mA: the current need to be set 22162306a36Sopenharmony_ci * 22262306a36Sopenharmony_ci * Usually we only change the charger default current when USB finished the 22362306a36Sopenharmony_ci * enumeration as one SDP charger. As one SDP charger, usb_phy_set_power() 22462306a36Sopenharmony_ci * will issue this function to change charger current when after setting USB 22562306a36Sopenharmony_ci * configuration, or suspend/resume USB. For other type charger, we should 22662306a36Sopenharmony_ci * use the default charger current and we do not suggest to issue this function 22762306a36Sopenharmony_ci * to change the charger current. 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci * When USB charger current has been changed, we need to notify the power users. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_civoid usb_phy_set_charger_current(struct usb_phy *usb_phy, unsigned int mA) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci switch (usb_phy->chg_type) { 23462306a36Sopenharmony_ci case SDP_TYPE: 23562306a36Sopenharmony_ci if (usb_phy->chg_cur.sdp_max == mA) 23662306a36Sopenharmony_ci return; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci usb_phy->chg_cur.sdp_max = (mA > DEFAULT_SDP_CUR_MAX_SS) ? 23962306a36Sopenharmony_ci DEFAULT_SDP_CUR_MAX_SS : mA; 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci case DCP_TYPE: 24262306a36Sopenharmony_ci if (usb_phy->chg_cur.dcp_max == mA) 24362306a36Sopenharmony_ci return; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci usb_phy->chg_cur.dcp_max = (mA > DEFAULT_DCP_CUR_MAX) ? 24662306a36Sopenharmony_ci DEFAULT_DCP_CUR_MAX : mA; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case CDP_TYPE: 24962306a36Sopenharmony_ci if (usb_phy->chg_cur.cdp_max == mA) 25062306a36Sopenharmony_ci return; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci usb_phy->chg_cur.cdp_max = (mA > DEFAULT_CDP_CUR_MAX) ? 25362306a36Sopenharmony_ci DEFAULT_CDP_CUR_MAX : mA; 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci case ACA_TYPE: 25662306a36Sopenharmony_ci if (usb_phy->chg_cur.aca_max == mA) 25762306a36Sopenharmony_ci return; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci usb_phy->chg_cur.aca_max = (mA > DEFAULT_ACA_CUR_MAX) ? 26062306a36Sopenharmony_ci DEFAULT_ACA_CUR_MAX : mA; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci default: 26362306a36Sopenharmony_ci return; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci schedule_work(&usb_phy->chg_work); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_phy_set_charger_current); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/** 27162306a36Sopenharmony_ci * usb_phy_get_charger_current - get the USB charger current 27262306a36Sopenharmony_ci * @usb_phy: the USB phy to be used 27362306a36Sopenharmony_ci * @min: the minimum current 27462306a36Sopenharmony_ci * @max: the maximum current 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * Usually we will notify the maximum current to power user, but for some 27762306a36Sopenharmony_ci * special case, power user also need the minimum current value. Then the 27862306a36Sopenharmony_ci * power user can issue this function to get the suitable current. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_civoid usb_phy_get_charger_current(struct usb_phy *usb_phy, 28162306a36Sopenharmony_ci unsigned int *min, unsigned int *max) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci switch (usb_phy->chg_type) { 28462306a36Sopenharmony_ci case SDP_TYPE: 28562306a36Sopenharmony_ci *min = usb_phy->chg_cur.sdp_min; 28662306a36Sopenharmony_ci *max = usb_phy->chg_cur.sdp_max; 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci case DCP_TYPE: 28962306a36Sopenharmony_ci *min = usb_phy->chg_cur.dcp_min; 29062306a36Sopenharmony_ci *max = usb_phy->chg_cur.dcp_max; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case CDP_TYPE: 29362306a36Sopenharmony_ci *min = usb_phy->chg_cur.cdp_min; 29462306a36Sopenharmony_ci *max = usb_phy->chg_cur.cdp_max; 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci case ACA_TYPE: 29762306a36Sopenharmony_ci *min = usb_phy->chg_cur.aca_min; 29862306a36Sopenharmony_ci *max = usb_phy->chg_cur.aca_max; 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci default: 30162306a36Sopenharmony_ci *min = 0; 30262306a36Sopenharmony_ci *max = 0; 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_phy_get_charger_current); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/** 30962306a36Sopenharmony_ci * usb_phy_set_charger_state - set the USB charger state 31062306a36Sopenharmony_ci * @usb_phy: the USB phy to be used 31162306a36Sopenharmony_ci * @state: the new state need to be set for charger 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * The usb phy driver can issue this function when the usb phy driver 31462306a36Sopenharmony_ci * detected the charger state has been changed, in this case the charger 31562306a36Sopenharmony_ci * type should be get from ->charger_detect(). 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_civoid usb_phy_set_charger_state(struct usb_phy *usb_phy, 31862306a36Sopenharmony_ci enum usb_charger_state state) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci if (usb_phy->chg_state == state || !usb_phy->charger_detect) 32162306a36Sopenharmony_ci return; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci usb_phy->chg_state = state; 32462306a36Sopenharmony_ci if (usb_phy->chg_state == USB_CHARGER_PRESENT) 32562306a36Sopenharmony_ci usb_phy->chg_type = usb_phy->charger_detect(usb_phy); 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci usb_phy->chg_type = UNKNOWN_TYPE; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci schedule_work(&usb_phy->chg_work); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_phy_set_charger_state); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void devm_usb_phy_release(struct device *dev, void *res) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct usb_phy *phy = *(struct usb_phy **)res; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci usb_put_phy(phy); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void devm_usb_phy_release2(struct device *dev, void *_res) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct phy_devm *res = _res; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (res->nb) 34562306a36Sopenharmony_ci usb_unregister_notifier(res->phy, res->nb); 34662306a36Sopenharmony_ci usb_put_phy(res->phy); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int devm_usb_phy_match(struct device *dev, void *res, void *match_data) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct usb_phy **phy = res; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return *phy == match_data; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void usb_charger_init(struct usb_phy *usb_phy) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci usb_phy->chg_type = UNKNOWN_TYPE; 35962306a36Sopenharmony_ci usb_phy->chg_state = USB_CHARGER_DEFAULT; 36062306a36Sopenharmony_ci usb_phy_set_default_current(usb_phy); 36162306a36Sopenharmony_ci INIT_WORK(&usb_phy->chg_work, usb_phy_notify_charger_work); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int usb_add_extcon(struct usb_phy *x) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci int ret; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (of_property_read_bool(x->dev->of_node, "extcon")) { 36962306a36Sopenharmony_ci x->edev = extcon_get_edev_by_phandle(x->dev, 0); 37062306a36Sopenharmony_ci if (IS_ERR(x->edev)) 37162306a36Sopenharmony_ci return PTR_ERR(x->edev); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci x->id_edev = extcon_get_edev_by_phandle(x->dev, 1); 37462306a36Sopenharmony_ci if (IS_ERR(x->id_edev)) { 37562306a36Sopenharmony_ci x->id_edev = NULL; 37662306a36Sopenharmony_ci dev_info(x->dev, "No separate ID extcon device\n"); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (x->vbus_nb.notifier_call) { 38062306a36Sopenharmony_ci ret = devm_extcon_register_notifier(x->dev, x->edev, 38162306a36Sopenharmony_ci EXTCON_USB, 38262306a36Sopenharmony_ci &x->vbus_nb); 38362306a36Sopenharmony_ci if (ret < 0) { 38462306a36Sopenharmony_ci dev_err(x->dev, 38562306a36Sopenharmony_ci "register VBUS notifier failed\n"); 38662306a36Sopenharmony_ci return ret; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } else { 38962306a36Sopenharmony_ci x->type_nb.notifier_call = usb_phy_get_charger_type; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci ret = devm_extcon_register_notifier(x->dev, x->edev, 39262306a36Sopenharmony_ci EXTCON_CHG_USB_SDP, 39362306a36Sopenharmony_ci &x->type_nb); 39462306a36Sopenharmony_ci if (ret) { 39562306a36Sopenharmony_ci dev_err(x->dev, 39662306a36Sopenharmony_ci "register extcon USB SDP failed.\n"); 39762306a36Sopenharmony_ci return ret; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ret = devm_extcon_register_notifier(x->dev, x->edev, 40162306a36Sopenharmony_ci EXTCON_CHG_USB_CDP, 40262306a36Sopenharmony_ci &x->type_nb); 40362306a36Sopenharmony_ci if (ret) { 40462306a36Sopenharmony_ci dev_err(x->dev, 40562306a36Sopenharmony_ci "register extcon USB CDP failed.\n"); 40662306a36Sopenharmony_ci return ret; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ret = devm_extcon_register_notifier(x->dev, x->edev, 41062306a36Sopenharmony_ci EXTCON_CHG_USB_DCP, 41162306a36Sopenharmony_ci &x->type_nb); 41262306a36Sopenharmony_ci if (ret) { 41362306a36Sopenharmony_ci dev_err(x->dev, 41462306a36Sopenharmony_ci "register extcon USB DCP failed.\n"); 41562306a36Sopenharmony_ci return ret; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = devm_extcon_register_notifier(x->dev, x->edev, 41962306a36Sopenharmony_ci EXTCON_CHG_USB_ACA, 42062306a36Sopenharmony_ci &x->type_nb); 42162306a36Sopenharmony_ci if (ret) { 42262306a36Sopenharmony_ci dev_err(x->dev, 42362306a36Sopenharmony_ci "register extcon USB ACA failed.\n"); 42462306a36Sopenharmony_ci return ret; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (x->id_nb.notifier_call) { 42962306a36Sopenharmony_ci struct extcon_dev *id_ext; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (x->id_edev) 43262306a36Sopenharmony_ci id_ext = x->id_edev; 43362306a36Sopenharmony_ci else 43462306a36Sopenharmony_ci id_ext = x->edev; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci ret = devm_extcon_register_notifier(x->dev, id_ext, 43762306a36Sopenharmony_ci EXTCON_USB_HOST, 43862306a36Sopenharmony_ci &x->id_nb); 43962306a36Sopenharmony_ci if (ret < 0) { 44062306a36Sopenharmony_ci dev_err(x->dev, 44162306a36Sopenharmony_ci "register ID notifier failed\n"); 44262306a36Sopenharmony_ci return ret; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (x->type_nb.notifier_call) 44862306a36Sopenharmony_ci __usb_phy_get_charger_type(x); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/** 45462306a36Sopenharmony_ci * devm_usb_get_phy - find the USB PHY 45562306a36Sopenharmony_ci * @dev: device that requests this phy 45662306a36Sopenharmony_ci * @type: the type of the phy the controller requires 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci * Gets the phy using usb_get_phy(), and associates a device with it using 45962306a36Sopenharmony_ci * devres. On driver detach, release function is invoked on the devres data, 46062306a36Sopenharmony_ci * then, devres data is freed. 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * For use by USB host and peripheral drivers. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_cistruct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct usb_phy **ptr, *phy; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); 46962306a36Sopenharmony_ci if (!ptr) 47062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci phy = usb_get_phy(type); 47362306a36Sopenharmony_ci if (!IS_ERR(phy)) { 47462306a36Sopenharmony_ci *ptr = phy; 47562306a36Sopenharmony_ci devres_add(dev, ptr); 47662306a36Sopenharmony_ci } else 47762306a36Sopenharmony_ci devres_free(ptr); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return phy; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_usb_get_phy); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci/** 48462306a36Sopenharmony_ci * usb_get_phy - find the USB PHY 48562306a36Sopenharmony_ci * @type: the type of the phy the controller requires 48662306a36Sopenharmony_ci * 48762306a36Sopenharmony_ci * Returns the phy driver, after getting a refcount to it; or 48862306a36Sopenharmony_ci * -ENODEV if there is no such phy. The caller is responsible for 48962306a36Sopenharmony_ci * calling usb_put_phy() to release that count. 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * For use by USB host and peripheral drivers. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_cistruct usb_phy *usb_get_phy(enum usb_phy_type type) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct usb_phy *phy = NULL; 49662306a36Sopenharmony_ci unsigned long flags; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci spin_lock_irqsave(&phy_lock, flags); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci phy = __usb_find_phy(&phy_list, type); 50162306a36Sopenharmony_ci if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { 50262306a36Sopenharmony_ci pr_debug("PHY: unable to find transceiver of type %s\n", 50362306a36Sopenharmony_ci usb_phy_type_string(type)); 50462306a36Sopenharmony_ci if (!IS_ERR(phy)) 50562306a36Sopenharmony_ci phy = ERR_PTR(-ENODEV); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci goto err0; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci get_device(phy->dev); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cierr0: 51362306a36Sopenharmony_ci spin_unlock_irqrestore(&phy_lock, flags); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return phy; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_get_phy); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/** 52062306a36Sopenharmony_ci * devm_usb_get_phy_by_node - find the USB PHY by device_node 52162306a36Sopenharmony_ci * @dev: device that requests this phy 52262306a36Sopenharmony_ci * @node: the device_node for the phy device. 52362306a36Sopenharmony_ci * @nb: a notifier_block to register with the phy. 52462306a36Sopenharmony_ci * 52562306a36Sopenharmony_ci * Returns the phy driver associated with the given device_node, 52662306a36Sopenharmony_ci * after getting a refcount to it, -ENODEV if there is no such phy or 52762306a36Sopenharmony_ci * -EPROBE_DEFER if the device is not yet loaded. While at that, it 52862306a36Sopenharmony_ci * also associates the device with 52962306a36Sopenharmony_ci * the phy using devres. On driver detach, release function is invoked 53062306a36Sopenharmony_ci * on the devres data, then, devres data is freed. 53162306a36Sopenharmony_ci * 53262306a36Sopenharmony_ci * For use by peripheral drivers for devices related to a phy, 53362306a36Sopenharmony_ci * such as a charger. 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_cistruct usb_phy *devm_usb_get_phy_by_node(struct device *dev, 53662306a36Sopenharmony_ci struct device_node *node, 53762306a36Sopenharmony_ci struct notifier_block *nb) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct usb_phy *phy = ERR_PTR(-ENOMEM); 54062306a36Sopenharmony_ci struct phy_devm *ptr; 54162306a36Sopenharmony_ci unsigned long flags; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci ptr = devres_alloc(devm_usb_phy_release2, sizeof(*ptr), GFP_KERNEL); 54462306a36Sopenharmony_ci if (!ptr) { 54562306a36Sopenharmony_ci dev_dbg(dev, "failed to allocate memory for devres\n"); 54662306a36Sopenharmony_ci goto err0; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci spin_lock_irqsave(&phy_lock, flags); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci phy = __of_usb_find_phy(node); 55262306a36Sopenharmony_ci if (IS_ERR(phy)) { 55362306a36Sopenharmony_ci devres_free(ptr); 55462306a36Sopenharmony_ci goto err1; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (!try_module_get(phy->dev->driver->owner)) { 55862306a36Sopenharmony_ci phy = ERR_PTR(-ENODEV); 55962306a36Sopenharmony_ci devres_free(ptr); 56062306a36Sopenharmony_ci goto err1; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci if (nb) 56362306a36Sopenharmony_ci usb_register_notifier(phy, nb); 56462306a36Sopenharmony_ci ptr->phy = phy; 56562306a36Sopenharmony_ci ptr->nb = nb; 56662306a36Sopenharmony_ci devres_add(dev, ptr); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci get_device(phy->dev); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cierr1: 57162306a36Sopenharmony_ci spin_unlock_irqrestore(&phy_lock, flags); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cierr0: 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return phy; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_usb_get_phy_by_node); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci/** 58062306a36Sopenharmony_ci * devm_usb_get_phy_by_phandle - find the USB PHY by phandle 58162306a36Sopenharmony_ci * @dev: device that requests this phy 58262306a36Sopenharmony_ci * @phandle: name of the property holding the phy phandle value 58362306a36Sopenharmony_ci * @index: the index of the phy 58462306a36Sopenharmony_ci * 58562306a36Sopenharmony_ci * Returns the phy driver associated with the given phandle value, 58662306a36Sopenharmony_ci * after getting a refcount to it, -ENODEV if there is no such phy or 58762306a36Sopenharmony_ci * -EPROBE_DEFER if there is a phandle to the phy, but the device is 58862306a36Sopenharmony_ci * not yet loaded. While at that, it also associates the device with 58962306a36Sopenharmony_ci * the phy using devres. On driver detach, release function is invoked 59062306a36Sopenharmony_ci * on the devres data, then, devres data is freed. 59162306a36Sopenharmony_ci * 59262306a36Sopenharmony_ci * For use by USB host and peripheral drivers. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_cistruct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, 59562306a36Sopenharmony_ci const char *phandle, u8 index) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct device_node *node; 59862306a36Sopenharmony_ci struct usb_phy *phy; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (!dev->of_node) { 60162306a36Sopenharmony_ci dev_dbg(dev, "device does not have a device node entry\n"); 60262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci node = of_parse_phandle(dev->of_node, phandle, index); 60662306a36Sopenharmony_ci if (!node) { 60762306a36Sopenharmony_ci dev_dbg(dev, "failed to get %s phandle in %pOF node\n", phandle, 60862306a36Sopenharmony_ci dev->of_node); 60962306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci phy = devm_usb_get_phy_by_node(dev, node, NULL); 61262306a36Sopenharmony_ci of_node_put(node); 61362306a36Sopenharmony_ci return phy; 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/** 61862306a36Sopenharmony_ci * devm_usb_put_phy - release the USB PHY 61962306a36Sopenharmony_ci * @dev: device that wants to release this phy 62062306a36Sopenharmony_ci * @phy: the phy returned by devm_usb_get_phy() 62162306a36Sopenharmony_ci * 62262306a36Sopenharmony_ci * destroys the devres associated with this phy and invokes usb_put_phy 62362306a36Sopenharmony_ci * to release the phy. 62462306a36Sopenharmony_ci * 62562306a36Sopenharmony_ci * For use by USB host and peripheral drivers. 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_civoid devm_usb_put_phy(struct device *dev, struct usb_phy *phy) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci int r; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy); 63262306a36Sopenharmony_ci dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n"); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_usb_put_phy); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/** 63762306a36Sopenharmony_ci * usb_put_phy - release the USB PHY 63862306a36Sopenharmony_ci * @x: the phy returned by usb_get_phy() 63962306a36Sopenharmony_ci * 64062306a36Sopenharmony_ci * Releases a refcount the caller received from usb_get_phy(). 64162306a36Sopenharmony_ci * 64262306a36Sopenharmony_ci * For use by USB host and peripheral drivers. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_civoid usb_put_phy(struct usb_phy *x) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci if (x) { 64762306a36Sopenharmony_ci struct module *owner = x->dev->driver->owner; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci put_device(x->dev); 65062306a36Sopenharmony_ci module_put(owner); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_put_phy); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/** 65662306a36Sopenharmony_ci * usb_add_phy: declare the USB PHY 65762306a36Sopenharmony_ci * @x: the USB phy to be used; or NULL 65862306a36Sopenharmony_ci * @type: the type of this PHY 65962306a36Sopenharmony_ci * 66062306a36Sopenharmony_ci * This call is exclusively for use by phy drivers, which 66162306a36Sopenharmony_ci * coordinate the activities of drivers for host and peripheral 66262306a36Sopenharmony_ci * controllers, and in some cases for VBUS current regulation. 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ciint usb_add_phy(struct usb_phy *x, enum usb_phy_type type) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci int ret = 0; 66762306a36Sopenharmony_ci unsigned long flags; 66862306a36Sopenharmony_ci struct usb_phy *phy; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (x->type != USB_PHY_TYPE_UNDEFINED) { 67162306a36Sopenharmony_ci dev_err(x->dev, "not accepting initialized PHY %s\n", x->label); 67262306a36Sopenharmony_ci return -EINVAL; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci usb_charger_init(x); 67662306a36Sopenharmony_ci ret = usb_add_extcon(x); 67762306a36Sopenharmony_ci if (ret) 67862306a36Sopenharmony_ci return ret; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci spin_lock_irqsave(&phy_lock, flags); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci list_for_each_entry(phy, &phy_list, head) { 68562306a36Sopenharmony_ci if (phy->type == type) { 68662306a36Sopenharmony_ci ret = -EBUSY; 68762306a36Sopenharmony_ci dev_err(x->dev, "transceiver type %s already exists\n", 68862306a36Sopenharmony_ci usb_phy_type_string(type)); 68962306a36Sopenharmony_ci goto out; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci x->type = type; 69462306a36Sopenharmony_ci list_add_tail(&x->head, &phy_list); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ciout: 69762306a36Sopenharmony_ci spin_unlock_irqrestore(&phy_lock, flags); 69862306a36Sopenharmony_ci return ret; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_add_phy); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic struct device_type usb_phy_dev_type = { 70362306a36Sopenharmony_ci .name = "usb_phy", 70462306a36Sopenharmony_ci .uevent = usb_phy_uevent, 70562306a36Sopenharmony_ci}; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci/** 70862306a36Sopenharmony_ci * usb_add_phy_dev - declare the USB PHY 70962306a36Sopenharmony_ci * @x: the USB phy to be used; or NULL 71062306a36Sopenharmony_ci * 71162306a36Sopenharmony_ci * This call is exclusively for use by phy drivers, which 71262306a36Sopenharmony_ci * coordinate the activities of drivers for host and peripheral 71362306a36Sopenharmony_ci * controllers, and in some cases for VBUS current regulation. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ciint usb_add_phy_dev(struct usb_phy *x) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci unsigned long flags; 71862306a36Sopenharmony_ci int ret; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (!x->dev) { 72162306a36Sopenharmony_ci dev_err(x->dev, "no device provided for PHY\n"); 72262306a36Sopenharmony_ci return -EINVAL; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci usb_charger_init(x); 72662306a36Sopenharmony_ci ret = usb_add_extcon(x); 72762306a36Sopenharmony_ci if (ret) 72862306a36Sopenharmony_ci return ret; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci x->dev->type = &usb_phy_dev_type; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci spin_lock_irqsave(&phy_lock, flags); 73562306a36Sopenharmony_ci list_add_tail(&x->head, &phy_list); 73662306a36Sopenharmony_ci spin_unlock_irqrestore(&phy_lock, flags); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci return 0; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_add_phy_dev); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci/** 74362306a36Sopenharmony_ci * usb_remove_phy - remove the OTG PHY 74462306a36Sopenharmony_ci * @x: the USB OTG PHY to be removed; 74562306a36Sopenharmony_ci * 74662306a36Sopenharmony_ci * This reverts the effects of usb_add_phy 74762306a36Sopenharmony_ci */ 74862306a36Sopenharmony_civoid usb_remove_phy(struct usb_phy *x) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci unsigned long flags; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci spin_lock_irqsave(&phy_lock, flags); 75362306a36Sopenharmony_ci if (x) 75462306a36Sopenharmony_ci list_del(&x->head); 75562306a36Sopenharmony_ci spin_unlock_irqrestore(&phy_lock, flags); 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_remove_phy); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci/** 76062306a36Sopenharmony_ci * usb_phy_set_event - set event to phy event 76162306a36Sopenharmony_ci * @x: the phy returned by usb_get_phy(); 76262306a36Sopenharmony_ci * @event: event to set 76362306a36Sopenharmony_ci * 76462306a36Sopenharmony_ci * This sets event to phy event 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_civoid usb_phy_set_event(struct usb_phy *x, unsigned long event) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci x->last_event = event; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_phy_set_event); 771