162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * USB PHY defines 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * These APIs may be used between USB controllers. USB device drivers 662306a36Sopenharmony_ci * (for either host or peripheral roles) don't use these calls; they 762306a36Sopenharmony_ci * continue to use just usb_device and usb_gadget. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#ifndef __LINUX_USB_PHY_H 1162306a36Sopenharmony_ci#define __LINUX_USB_PHY_H 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/extcon.h> 1462306a36Sopenharmony_ci#include <linux/notifier.h> 1562306a36Sopenharmony_ci#include <linux/usb.h> 1662306a36Sopenharmony_ci#include <uapi/linux/usb/charger.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cienum usb_phy_interface { 1962306a36Sopenharmony_ci USBPHY_INTERFACE_MODE_UNKNOWN, 2062306a36Sopenharmony_ci USBPHY_INTERFACE_MODE_UTMI, 2162306a36Sopenharmony_ci USBPHY_INTERFACE_MODE_UTMIW, 2262306a36Sopenharmony_ci USBPHY_INTERFACE_MODE_ULPI, 2362306a36Sopenharmony_ci USBPHY_INTERFACE_MODE_SERIAL, 2462306a36Sopenharmony_ci USBPHY_INTERFACE_MODE_HSIC, 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cienum usb_phy_events { 2862306a36Sopenharmony_ci USB_EVENT_NONE, /* no events or cable disconnected */ 2962306a36Sopenharmony_ci USB_EVENT_VBUS, /* vbus valid event */ 3062306a36Sopenharmony_ci USB_EVENT_ID, /* id was grounded */ 3162306a36Sopenharmony_ci USB_EVENT_CHARGER, /* usb dedicated charger */ 3262306a36Sopenharmony_ci USB_EVENT_ENUMERATED, /* gadget driver enumerated */ 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* associate a type with PHY */ 3662306a36Sopenharmony_cienum usb_phy_type { 3762306a36Sopenharmony_ci USB_PHY_TYPE_UNDEFINED, 3862306a36Sopenharmony_ci USB_PHY_TYPE_USB2, 3962306a36Sopenharmony_ci USB_PHY_TYPE_USB3, 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* OTG defines lots of enumeration states before device reset */ 4362306a36Sopenharmony_cienum usb_otg_state { 4462306a36Sopenharmony_ci OTG_STATE_UNDEFINED = 0, 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* single-role peripheral, and dual-role default-b */ 4762306a36Sopenharmony_ci OTG_STATE_B_IDLE, 4862306a36Sopenharmony_ci OTG_STATE_B_SRP_INIT, 4962306a36Sopenharmony_ci OTG_STATE_B_PERIPHERAL, 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* extra dual-role default-b states */ 5262306a36Sopenharmony_ci OTG_STATE_B_WAIT_ACON, 5362306a36Sopenharmony_ci OTG_STATE_B_HOST, 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* dual-role default-a */ 5662306a36Sopenharmony_ci OTG_STATE_A_IDLE, 5762306a36Sopenharmony_ci OTG_STATE_A_WAIT_VRISE, 5862306a36Sopenharmony_ci OTG_STATE_A_WAIT_BCON, 5962306a36Sopenharmony_ci OTG_STATE_A_HOST, 6062306a36Sopenharmony_ci OTG_STATE_A_SUSPEND, 6162306a36Sopenharmony_ci OTG_STATE_A_PERIPHERAL, 6262306a36Sopenharmony_ci OTG_STATE_A_WAIT_VFALL, 6362306a36Sopenharmony_ci OTG_STATE_A_VBUS_ERR, 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistruct usb_phy; 6762306a36Sopenharmony_cistruct usb_otg; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* for phys connected thru an ULPI interface, the user must 7062306a36Sopenharmony_ci * provide access ops 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_cistruct usb_phy_io_ops { 7362306a36Sopenharmony_ci int (*read)(struct usb_phy *x, u32 reg); 7462306a36Sopenharmony_ci int (*write)(struct usb_phy *x, u32 val, u32 reg); 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct usb_charger_current { 7862306a36Sopenharmony_ci unsigned int sdp_min; 7962306a36Sopenharmony_ci unsigned int sdp_max; 8062306a36Sopenharmony_ci unsigned int dcp_min; 8162306a36Sopenharmony_ci unsigned int dcp_max; 8262306a36Sopenharmony_ci unsigned int cdp_min; 8362306a36Sopenharmony_ci unsigned int cdp_max; 8462306a36Sopenharmony_ci unsigned int aca_min; 8562306a36Sopenharmony_ci unsigned int aca_max; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistruct usb_phy { 8962306a36Sopenharmony_ci struct device *dev; 9062306a36Sopenharmony_ci const char *label; 9162306a36Sopenharmony_ci unsigned int flags; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci enum usb_phy_type type; 9462306a36Sopenharmony_ci enum usb_phy_events last_event; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci struct usb_otg *otg; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci struct device *io_dev; 9962306a36Sopenharmony_ci struct usb_phy_io_ops *io_ops; 10062306a36Sopenharmony_ci void __iomem *io_priv; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* to support extcon device */ 10362306a36Sopenharmony_ci struct extcon_dev *edev; 10462306a36Sopenharmony_ci struct extcon_dev *id_edev; 10562306a36Sopenharmony_ci struct notifier_block vbus_nb; 10662306a36Sopenharmony_ci struct notifier_block id_nb; 10762306a36Sopenharmony_ci struct notifier_block type_nb; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Support USB charger */ 11062306a36Sopenharmony_ci enum usb_charger_type chg_type; 11162306a36Sopenharmony_ci enum usb_charger_state chg_state; 11262306a36Sopenharmony_ci struct usb_charger_current chg_cur; 11362306a36Sopenharmony_ci struct work_struct chg_work; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* for notification of usb_phy_events */ 11662306a36Sopenharmony_ci struct atomic_notifier_head notifier; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* to pass extra port status to the root hub */ 11962306a36Sopenharmony_ci u16 port_status; 12062306a36Sopenharmony_ci u16 port_change; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* to support controllers that have multiple phys */ 12362306a36Sopenharmony_ci struct list_head head; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* initialize/shutdown the phy */ 12662306a36Sopenharmony_ci int (*init)(struct usb_phy *x); 12762306a36Sopenharmony_ci void (*shutdown)(struct usb_phy *x); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* enable/disable VBUS */ 13062306a36Sopenharmony_ci int (*set_vbus)(struct usb_phy *x, int on); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* effective for B devices, ignored for A-peripheral */ 13362306a36Sopenharmony_ci int (*set_power)(struct usb_phy *x, 13462306a36Sopenharmony_ci unsigned mA); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Set phy into suspend mode */ 13762306a36Sopenharmony_ci int (*set_suspend)(struct usb_phy *x, 13862306a36Sopenharmony_ci int suspend); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* 14162306a36Sopenharmony_ci * Set wakeup enable for PHY, in that case, the PHY can be 14262306a36Sopenharmony_ci * woken up from suspend status due to external events, 14362306a36Sopenharmony_ci * like vbus change, dp/dm change and id. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci int (*set_wakeup)(struct usb_phy *x, bool enabled); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* notify phy connect status change */ 14862306a36Sopenharmony_ci int (*notify_connect)(struct usb_phy *x, 14962306a36Sopenharmony_ci enum usb_device_speed speed); 15062306a36Sopenharmony_ci int (*notify_disconnect)(struct usb_phy *x, 15162306a36Sopenharmony_ci enum usb_device_speed speed); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * Charger detection method can be implemented if you need to 15562306a36Sopenharmony_ci * manually detect the charger type. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci enum usb_charger_type (*charger_detect)(struct usb_phy *x); 15862306a36Sopenharmony_ci}; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/* for board-specific init logic */ 16162306a36Sopenharmony_ciextern int usb_add_phy(struct usb_phy *, enum usb_phy_type type); 16262306a36Sopenharmony_ciextern int usb_add_phy_dev(struct usb_phy *); 16362306a36Sopenharmony_ciextern void usb_remove_phy(struct usb_phy *); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* helpers for direct access thru low-level io interface */ 16662306a36Sopenharmony_cistatic inline int usb_phy_io_read(struct usb_phy *x, u32 reg) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci if (x && x->io_ops && x->io_ops->read) 16962306a36Sopenharmony_ci return x->io_ops->read(x, reg); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return -EINVAL; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci if (x && x->io_ops && x->io_ops->write) 17762306a36Sopenharmony_ci return x->io_ops->write(x, val, reg); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic inline int 18362306a36Sopenharmony_ciusb_phy_init(struct usb_phy *x) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci if (x && x->init) 18662306a36Sopenharmony_ci return x->init(x); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return 0; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic inline void 19262306a36Sopenharmony_ciusb_phy_shutdown(struct usb_phy *x) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci if (x && x->shutdown) 19562306a36Sopenharmony_ci x->shutdown(x); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic inline int 19962306a36Sopenharmony_ciusb_phy_vbus_on(struct usb_phy *x) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci if (!x || !x->set_vbus) 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return x->set_vbus(x, true); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic inline int 20862306a36Sopenharmony_ciusb_phy_vbus_off(struct usb_phy *x) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci if (!x || !x->set_vbus) 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return x->set_vbus(x, false); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* for usb host and peripheral controller drivers */ 21762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_PHY) 21862306a36Sopenharmony_ciextern struct usb_phy *usb_get_phy(enum usb_phy_type type); 21962306a36Sopenharmony_ciextern struct usb_phy *devm_usb_get_phy(struct device *dev, 22062306a36Sopenharmony_ci enum usb_phy_type type); 22162306a36Sopenharmony_ciextern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, 22262306a36Sopenharmony_ci const char *phandle, u8 index); 22362306a36Sopenharmony_ciextern struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, 22462306a36Sopenharmony_ci struct device_node *node, struct notifier_block *nb); 22562306a36Sopenharmony_ciextern void usb_put_phy(struct usb_phy *); 22662306a36Sopenharmony_ciextern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); 22762306a36Sopenharmony_ciextern void usb_phy_set_event(struct usb_phy *x, unsigned long event); 22862306a36Sopenharmony_ciextern void usb_phy_set_charger_current(struct usb_phy *usb_phy, 22962306a36Sopenharmony_ci unsigned int mA); 23062306a36Sopenharmony_ciextern void usb_phy_get_charger_current(struct usb_phy *usb_phy, 23162306a36Sopenharmony_ci unsigned int *min, unsigned int *max); 23262306a36Sopenharmony_ciextern void usb_phy_set_charger_state(struct usb_phy *usb_phy, 23362306a36Sopenharmony_ci enum usb_charger_state state); 23462306a36Sopenharmony_ci#else 23562306a36Sopenharmony_cistatic inline struct usb_phy *usb_get_phy(enum usb_phy_type type) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic inline struct usb_phy *devm_usb_get_phy(struct device *dev, 24162306a36Sopenharmony_ci enum usb_phy_type type) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, 24762306a36Sopenharmony_ci const char *phandle, u8 index) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic inline struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, 25362306a36Sopenharmony_ci struct device_node *node, struct notifier_block *nb) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic inline void usb_put_phy(struct usb_phy *x) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic inline void usb_phy_set_event(struct usb_phy *x, unsigned long event) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic inline void usb_phy_set_charger_current(struct usb_phy *usb_phy, 27162306a36Sopenharmony_ci unsigned int mA) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic inline void usb_phy_get_charger_current(struct usb_phy *usb_phy, 27662306a36Sopenharmony_ci unsigned int *min, 27762306a36Sopenharmony_ci unsigned int *max) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic inline void usb_phy_set_charger_state(struct usb_phy *usb_phy, 28262306a36Sopenharmony_ci enum usb_charger_state state) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci#endif 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic inline int 28862306a36Sopenharmony_ciusb_phy_set_power(struct usb_phy *x, unsigned mA) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci if (!x) 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci usb_phy_set_charger_current(x, mA); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (x->set_power) 29662306a36Sopenharmony_ci return x->set_power(x, mA); 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* Context: can sleep */ 30162306a36Sopenharmony_cistatic inline int 30262306a36Sopenharmony_ciusb_phy_set_suspend(struct usb_phy *x, int suspend) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci if (x && x->set_suspend != NULL) 30562306a36Sopenharmony_ci return x->set_suspend(x, suspend); 30662306a36Sopenharmony_ci else 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic inline int 31162306a36Sopenharmony_ciusb_phy_set_wakeup(struct usb_phy *x, bool enabled) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci if (x && x->set_wakeup) 31462306a36Sopenharmony_ci return x->set_wakeup(x, enabled); 31562306a36Sopenharmony_ci else 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic inline int 32062306a36Sopenharmony_ciusb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci if (x && x->notify_connect) 32362306a36Sopenharmony_ci return x->notify_connect(x, speed); 32462306a36Sopenharmony_ci else 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic inline int 32962306a36Sopenharmony_ciusb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci if (x && x->notify_disconnect) 33262306a36Sopenharmony_ci return x->notify_disconnect(x, speed); 33362306a36Sopenharmony_ci else 33462306a36Sopenharmony_ci return 0; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/* notifiers */ 33862306a36Sopenharmony_cistatic inline int 33962306a36Sopenharmony_ciusb_register_notifier(struct usb_phy *x, struct notifier_block *nb) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci return atomic_notifier_chain_register(&x->notifier, nb); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic inline void 34562306a36Sopenharmony_ciusb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci atomic_notifier_chain_unregister(&x->notifier, nb); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic inline const char *usb_phy_type_string(enum usb_phy_type type) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci switch (type) { 35362306a36Sopenharmony_ci case USB_PHY_TYPE_USB2: 35462306a36Sopenharmony_ci return "USB2 PHY"; 35562306a36Sopenharmony_ci case USB_PHY_TYPE_USB3: 35662306a36Sopenharmony_ci return "USB3 PHY"; 35762306a36Sopenharmony_ci default: 35862306a36Sopenharmony_ci return "UNKNOWN PHY TYPE"; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci#endif /* __LINUX_USB_PHY_H */ 362