/* * Intel Penwell USB OTG transceiver driver * Copyright (C) 2009 - 2010, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef __DWC3_OTG_H #define __DWC3_OTG_H #include #include #include #include #include #include #include struct dwc_device_par { void __iomem *io_addr; int len; }; #define DWC3_DEVICE_NAME "dwc3-device" #define DWC3_HOST_NAME "dwc3-host" #define GADGET_DEVID 1 #define HOST_DEVID 2 #define DRIVER_VERSION "0.1" #ifdef CONFIG_USB_DWC3_OTG_DEBUG #define DWC_OTG_DEBUG 1 #else #define DWC_OTG_DEBUG 0 #endif #define otg_dbg(d, fmt, args...) \ do { dev_dbg((d)->dev, \ "%s(): " fmt , __func__, ## args); } while (0) #define otg_vdbg(d, fmt, args...) \ do { if (DWC_OTG_DEBUG) dev_dbg((d)->dev, \ "%s(): " fmt , __func__, ## args); } while (0) #define otg_err(d, fmt, args...) \ do { dev_err((d)->dev, \ "%s(): " fmt , __func__, ## args); } while (0) #define otg_warn(d, fmt, args...) \ do { dev_warn((d)->dev, \ "%s(): " fmt , __func__, ## args); } while (0) #define otg_info(d, fmt, args...) \ do { dev_info((d)->dev, \ "%s(): " fmt , __func__, ## args); } while (0) #ifdef DEBUG #define otg_write(o, reg, val) do { \ otg_dbg(o, "OTG_WRITE: reg=0x%05x, val=0x%08x\n", reg, val); \ writel(val, ((void *)((o)->usb2_phy.io_priv)) + reg); \ } while (0) #define otg_read(o, reg) ({ \ u32 __r; \ __r = readl(((void *)((o)->usb2_phy.io_priv)) + reg); \ otg_dbg(o, "OTG_READ: reg=0x%05x, val=0x%08x\n", reg, __r); \ __r; \ }) #else #define otg_write(o, reg, val) \ writel(val, ((void *)((o)->usb2_phy.io_priv)) + reg); #define otg_read(o, reg) ({ \ readl(((void *)((o)->usb2_phy.io_priv)) + reg); \ }) #endif #define GUSB2PHYCFG0 0xc200 #define GUSB2PHYCFG_SUS_PHY 0x40 #define GUSB2PHYCFG_PHYSOFTRST (1 << 31) #define GUSB2PHYCFG_ULPI_AUTO_RESUME (1 << 15) #define EXTEND_ULPI_REGISTER_ACCESS_MASK 0xC0 #define GUSB2PHYACC0 0xc280 #define GUSB2PHYACC0_DISULPIDRVR (1 << 26) #define GUSB2PHYACC0_NEWREGREQ (1 << 25) #define GUSB2PHYACC0_VSTSDONE (1 << 24) #define GUSB2PHYACC0_VSTSBSY (1 << 23) #define GUSB2PHYACC0_REGWR (1 << 22) #define GUSB2PHYACC0_REGADDR(v) ((v & 0x3F) << 16) #define GUSB2PHYACC0_EXTREGADDR(v) ((v & 0x3F) << 8) #define GUSB2PHYACC0_VCTRL(v) ((v & 0xFF) << 8) #define GUSB2PHYACC0_REGDATA(v) (v & 0xFF) #define GUSB2PHYACC0_REGDATA_MASK 0xFF #define GUSB3PIPECTL0 0xc2c0 #define GUSB3PIPECTL_SUS_EN 0x20000 #define GUSB3PIPE_DISRXDETP3 (1 << 28) #define GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define GHWPARAMS6 0xc158 #define GHWPARAMS6_SRP_SUPPORT_ENABLED 0x0400 #define GHWPARAMS6_HNP_SUPPORT_ENABLED 0x0800 #define GHWPARAMS6_ADP_SUPPORT_ENABLED 0x1000 #define GUCTL 0xC12C #define GUCTL_CMDEVADDR (1 << 15) #define GCTL 0xc110 #define GCTL_PRT_CAP_DIR 0x3000 #define GCTL_PRT_CAP_DIR_SHIFT 12 #define GCTL_PRT_CAP_DIR_HOST 1 #define GCTL_PRT_CAP_DIR_DEV 2 #define GCTL_PRT_CAP_DIR_OTG 3 #define GCTL_GBL_HIBERNATION_EN 0x2 #define GCTL_CORESOFTRESET (1 << 11) #define GCTL_PWRDNSCALE(x) (x << 19) #define GCTL_PWRDNSCALE_MASK (0x1fff << 19) #define OCFG 0xcc00 #define OCFG_SRP_CAP 0x01 #define OCFG_SRP_CAP_SHIFT 0 #define OCFG_HNP_CAP 0x02 #define OCFG_HNP_CAP_SHIFT 1 #define OCFG_OTG_VERSION 0x04 #define OCFG_OTG_VERSION_SHIFT 2 #define GCTL 0xc110 #define OCTL 0xcc04 #define OCTL_HST_SET_HNP_EN 0x01 #define OCTL_HST_SET_HNP_EN_SHIFT 0 #define OCTL_DEV_SET_HNP_EN 0x02 #define OCTL_DEV_SET_HNP_EN_SHIFT 1 #define OCTL_TERM_SEL_DL_PULSE 0x04 #define OCTL_TERM_SEL_DL_PULSE_SHIFT 2 #define OCTL_SES_REQ 0x08 #define OCTL_SES_REQ_SHIFT 3 #define OCTL_HNP_REQ 0x10 #define OCTL_HNP_REQ_SHIFT 4 #define OCTL_PRT_PWR_CTL 0x20 #define OCTL_PRT_PWR_CTL_SHIFT 5 #define OCTL_PERI_MODE 0x40 #define OCTL_PERI_MODE_SHIFT 6 #define OEVT 0xcc08 #define OEVT_ERR 0x00000001 #define OEVT_ERR_SHIFT 0 #define OEVT_SES_REQ_SCS 0x00000002 #define OEVT_SES_REQ_SCS_SHIFT 1 #define OEVT_HST_NEG_SCS 0x00000004 #define OEVT_HST_NEG_SCS_SHIFT 2 #define OEVT_B_SES_VLD_EVT 0x00000008 #define OEVT_B_SES_VLD_EVT_SHIFT 3 #define OEVT_B_DEV_VBUS_CHNG_EVNT 0x00000100 #define OEVT_B_DEV_VBUS_CHNG_EVNT_SHIFT 8 #define OEVT_B_DEV_SES_VLD_DET_EVNT 0x00000200 #define OEVT_B_DEV_SES_VLD_DET_EVNT_SHIFT 9 #define OEVT_B_DEV_HNP_CHNG_EVNT 0x00000400 #define OEVT_B_DEV_HNP_CHNG_EVNT_SHIFT 10 #define OEVT_B_DEV_B_HOST_END_EVNT 0x00000800 #define OEVT_B_DEV_B_HOST_END_EVNT_SHIFT 11 #define OEVT_A_DEV_SESS_END_DET_EVNT 0x00010000 #define OEVT_A_DEV_SESS_END_DET_EVNT_SHIFT 16 #define OEVT_A_DEV_SRP_DET_EVNT 0x00020000 #define OEVT_A_DEV_SRP_DET_EVNT_SHIFT 17 #define OEVT_A_DEV_HNP_CHNG_EVNT 0x00040000 #define OEVT_A_DEV_HNP_CHNG_EVNT_SHIFT 18 #define OEVT_A_DEV_HOST_EVNT 0x00080000 #define OEVT_A_DEV_HOST_EVNT_SHIFT 19 #define OEVT_A_DEV_B_DEV_HOST_END_EVNT 0x00100000 #define OEVT_A_DEV_B_DEV_HOST_END_EVNT_SHIFT 20 #define OEVT_HOST_ROLE_REQ_INIT_EVNT 0x00400000 #define OEVT_HOST_ROLE_REQ_INIT_EVNT_SHIFT 22 #define OEVT_HOST_ROLE_REQ_CONFIRM_EVNT 0x00800000 #define OEVT_HOST_ROLE_REQ_CONFIRM_EVNT_SHIFT 23 #define OEVT_CONN_ID_STS_CHNG_EVNT 0x01000000 #define OEVT_CONN_ID_STS_CHNG_EVNT_SHIFT 24 #define OEVT_DEV_MOD_EVNT 0x80000000 #define OEVT_DEV_MOD_EVNT_SHIFT 31 #define OEVTEN 0xcc0c #define OEVT_ALL (OEVT_CONN_ID_STS_CHNG_EVNT | \ OEVT_HOST_ROLE_REQ_INIT_EVNT | \ OEVT_HOST_ROLE_REQ_CONFIRM_EVNT | \ OEVT_A_DEV_B_DEV_HOST_END_EVNT | \ OEVT_A_DEV_HOST_EVNT | \ OEVT_A_DEV_HNP_CHNG_EVNT | \ OEVT_A_DEV_SRP_DET_EVNT | \ OEVT_A_DEV_SESS_END_DET_EVNT | \ OEVT_B_DEV_B_HOST_END_EVNT | \ OEVT_B_DEV_HNP_CHNG_EVNT | \ OEVT_B_DEV_SES_VLD_DET_EVNT | \ OEVT_B_DEV_VBUS_CHNG_EVNT) #define OSTS 0xcc10 #define OSTS_CONN_ID_STS 0x0001 #define OSTS_CONN_ID_STS_SHIFT 0 #define OSTS_A_SES_VLD 0x0002 #define OSTS_A_SES_VLD_SHIFT 1 #define OSTS_B_SES_VLD 0x0004 #define OSTS_B_SES_VLD_SHIFT 2 #define OSTS_XHCI_PRT_PWR 0x0008 #define OSTS_XHCI_PRT_PWR_SHIFT 3 #define OSTS_PERIP_MODE 0x0010 #define OSTS_PERIP_MODE_SHIFT 4 #define OSTS_OTG_STATES 0x0f00 #define OSTS_OTG_STATE_SHIFT 8 #define ADPCFG 0xcc20 #define ADPCFG_PRB_DSCHGS 0x0c000000 #define ADPCFG_PRB_DSCHG_SHIFT 26 #define ADPCFG_PRB_DELTAS 0x30000000 #define ADPCFG_PRB_DELTA_SHIFT 28 #define ADPCFG_PRB_PERS 0xc0000000 #define ADPCFG_PRB_PER_SHIFT 30 #define ADPCTL 0xcc24 #define ADPCTL_WB 0x01000000 #define ADPCTL_WB_SHIFT 24 #define ADPCTL_ADP_RES 0x02000000 #define ADPCTL_ADP_RES_SHIFT 25 #define ADPCTL_ADP_EN 0x04000000 #define ADPCTL_ADP_EN_SHIFT 26 #define ADPCTL_ENA_SNS 0x08000000 #define ADPCTL_ENA_SNS_SHIFT 27 #define ADPCTL_ENA_PRB 0x10000000 #define ADPCTL_ENA_PRB_SHIFT 28 #define ADPEVT 0xcc28 #define ADPEVT_RTIM_EVNTS 0x000007ff #define ADPEVT_RTIM_EVNT_SHIFT 0 #define ADPEVT_ADP_RST_CMPLT_EVNT 0x02000000 #define ADPEVT_ADP_RST_CMPLT_EVNT_SHIFT 25 #define ADPEVT_ADP_TMOUT_EVNT 0x04000000 #define ADPEVT_ADP_TMOUT_EVNT_SHIFT 26 #define ADPEVT_ADP_SNS_EVNT 0x08000000 #define ADPEVT_ADP_SNS_EVNT_SHIFT 27 #define ADPEVT_ADP_PRB_EVNT 0x10000000 #define ADPEVT_ADP_PRB_EVNT_SHIFT 28 #define ADPEVTEN 0xcc2c #define ADPEVTEN_ACC_DONE_EN 0x01000000 #define ADPEVTEN_ACC_DONE_EN_SHIFT 24 #define ADPEVTEN_ADP_RST_CMPLT_EVNT_EN 0x02000000 #define ADPEVTEN_ADP_RST_CMPLT_EVNT_EN_SHIFT 25 #define ADPEVTEN_ADP_TMOUT_EVNT_EN 0x04000000 #define ADPEVTEN_ADP_TMOUT_EVNT_EN_SHIFT 26 #define ADPEVTEN_ADP_SNS_EVNT_EN 0x08000000 #define ADPEVTEN_ADP_SNS_EVNT_EN_SHIFT 27 #define ADPEVTEN_ADP_PRB_EVNT_EN 0x10000000 #define ADPEVTEN_ADP_PRB_EVNT_EN_SHIFT 28 #define RID_A 0x01 #define RID_B 0x02 #define RID_C 0x03 #define RID_FLOAT 0x04 #define RID_GND 0x05 #define RID_UNKNOWN 0x00 /** The states for the OTG driver */ enum dwc_otg_state { DWC_STATE_INVALID = -1, /** The initial state, check the connector * id status and determine what mode * (A-device or B-device) to operate in. */ DWC_STATE_B_IDLE = 0, /* A-Host states */ DWC_STATE_A_PROBE, DWC_STATE_A_HOST, DWC_STATE_A_HNP_INIT, /* A-Peripheral states */ DWC_STATE_A_PERIPHERAL, /* B-Peripheral states */ DWC_STATE_B_SENSE, DWC_STATE_B_PROBE, DWC_STATE_B_PERIPHERAL, DWC_STATE_B_HNP_INIT, /* B-Host states */ DWC_STATE_B_HOST, /* RSP */ DWC_STATE_B_RSP_INIT, /* USB charger detection */ DWC_STATE_CHARGER_DETECTION, /* VBUS */ DWC_STATE_WAIT_VBUS_RAISE, DWC_STATE_WAIT_VBUS_FALL, /* Charging*/ DWC_STATE_CHARGING, /* Exit */ DWC_STATE_EXIT, DWC_STATE_TERMINATED }; /** The main structure to keep track of OTG driver state. */ struct dwc_otg2 { /** OTG transceiver */ struct usb_otg otg; struct usb_phy usb2_phy; struct usb_phy usb3_phy; struct device *dev; int irqnum; int main_wakeup_needed; struct task_struct *main_thread; wait_queue_head_t main_wq; spinlock_t lock; /* Events */ u32 otg_events; u32 user_events; /** User space ID switch event */ #define USER_ID_A_CHANGE_EVENT 0x01 #define USER_ID_B_CHANGE_EVENT 0x02 /** a_bus_drop event from userspace */ #define USER_A_BUS_DROP 0x40 /* States */ enum dwc_otg_state prev; enum dwc_otg_state state; struct platform_device *host; struct platform_device *gadget; /* Charger detection */ struct power_supply_cable_props charging_cap; struct notifier_block nb; /* Interfaces between host/device driver */ int (*start_host) (struct usb_hcd *hcd); int (*stop_host) (struct usb_hcd *hcd); int (*start_device)(struct usb_gadget *); int (*stop_device)(struct usb_gadget *); int (*vbus_draw) (struct usb_gadget *, unsigned ma); /* host driver suspend/resume flow callback which * need host driver to register them if need call by * otg driver.*/ int (*suspend_host) (struct usb_hcd *hcd); int (*resume_host) (struct usb_hcd *hcd); /* Vendor driver private date */ void *otg_data; }; #define sleep_main_thread_until_condition_timeout(otg, condition, msecs) ({ \ int __timeout = msecs; \ while (!(condition)) { \ otg_dbg(otg, " ... sleeping for %d\n", __timeout); \ __timeout = sleep_main_thread_timeout(otg, __timeout); \ if (__timeout <= 0) { \ break; \ } \ } \ __timeout; \ }) #define sleep_main_thread_until_condition(otg, condition) ({ \ int __rc = 0; \ do { \ __rc = sleep_main_thread_until_condition_timeout(otg, \ condition, 50000); \ } while (__rc == 0); \ __rc; \ }) #define VBUS_TIMEOUT 20 #define PCI_DEVICE_ID_DWC 0x119E #define PCI_DEVICE_ID_DWC_VLV 0x0F37 #define PCI_DEVICE_ID_DWC_CHT 0x22B7 enum dwc3_otg_mode { DWC3_DEVICE_ONLY, DWC3_HOST_ONLY, DWC3_DRD, }; enum driver_bus_type { DWC3_PLAT, DWC3_PCI, }; struct dwc3_otg_hw_ops { enum dwc3_otg_mode mode; enum driver_bus_type bus; int (*set_power)(struct usb_phy *_otg, unsigned ma); int (*platform_init)(struct dwc_otg2 *otg); int (*platform_exit)(struct dwc_otg2 *otg); int (*otg_notifier_handler)(struct notifier_block *nb, unsigned long event, void *data); int (*prepare_start_peripheral)(struct dwc_otg2 *otg); int (*prepare_start_host)(struct dwc_otg2 *otg); int (*after_stop_peripheral)(struct dwc_otg2 *otg); int (*after_stop_host)(struct dwc_otg2 *otg); int (*b_idle)(struct dwc_otg2 *otg); int (*do_charging)(struct dwc_otg2 *otg); int (*notify_charger_type)(struct dwc_otg2 *otg, enum power_supply_charger_event event); enum power_supply_charger_cable_type (*get_charger_type)(struct dwc_otg2 *otg); int (*enable_vbus)(struct dwc_otg2 *otg, int enable); int (*get_id)(struct dwc_otg2 *otg); int (*idle)(struct dwc_otg2 *otg); int (*suspend)(struct dwc_otg2 *otg); int (*resume)(struct dwc_otg2 *otg); }; #define OTG_USB2_0MA 0xfff0 #define OTG_USB2_100MA 0xfff1 #define OTG_USB3_150MA 0xfff2 #define OTG_USB2_500MA 0xfff3 #define OTG_USB3_900MA 0xfff4 #define OTG_DEVICE_SUSPEND 0xfffe #define OTG_DEVICE_RESUME 0xffff void dwc3_wakeup_otg_thread(struct dwc_otg2 *otg); struct dwc_otg2 *dwc3_get_otg(void); int dwc3_otg_register(struct dwc3_otg_hw_ops *pdata); int dwc3_otg_unregister(struct dwc3_otg_hw_ops *pdata); int dwc3_is_cht(void); #endif /* __DWC3_OTG_H */