diff options
Diffstat (limited to 'drivers/usb/dwc3/otg.h')
-rw-r--r-- | drivers/usb/dwc3/otg.h | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/otg.h b/drivers/usb/dwc3/otg.h new file mode 100644 index 00000000000..feac6f59b76 --- /dev/null +++ b/drivers/usb/dwc3/otg.h @@ -0,0 +1,443 @@ +/* + * 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 <linux/usb.h> +#include <linux/device.h> +#include <linux/compiler.h> +#include <linux/usb/gadget.h> +#include <linux/usb/hcd.h> +#include <linux/usb/ulpi.h> + + +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 { if (DWC_OTG_DEBUG) 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 { if (DWC_OTG_DEBUG) dev_err((d)->dev, \ + "%s(): " fmt , __func__, ## args); } while (0) +#define otg_warn(d, fmt, args...) \ + do { if (DWC_OTG_DEBUG) dev_warn((d)->dev, \ + "%s(): " fmt , __func__, ## args); } while (0) +#define otg_info(d, fmt, args...) \ + do { if (DWC_OTG_DEBUG) 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 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 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 + + +/* charger defined in BC 1.2 */ +enum usb_charger_type { + CHRG_UNKNOWN, + CHRG_SDP, /* Standard Downstream Port */ + CHRG_CDP, /* Charging Downstream Port */ + CHRG_DCP, /* Dedicated Charging Port */ + CHRG_ACA, /* Accessory Charger Adapter */ + CHRG_ACA_DOCK, /* Accessory Charger Adapter - Dock */ + CHRG_ACA_A, /* Accessory Charger Adapter - RID_A */ + CHRG_ACA_B, /* Accessory Charger Adapter - RID_B */ + CHRG_ACA_C, /* Accessory Charger Adapter - RID_C */ + CHRG_SE1, /* SE1 (Apple)*/ + CHRG_MHL, /* Moblie High-Definition Link */ + B_DEVICE /* Normal B Device */ +}; + +#define RID_A 0x01 +#define RID_B 0x02 +#define RID_C 0x03 +#define RID_FLOAT 0x04 +#define RID_GND 0x05 +#define RID_UNKNOWN 0x00 + +enum usb_charger_state { + OTG_CHR_STATE_CONNECTED, /* charger is connected */ + OTG_CHR_STATE_DISCONNECTED, /* USB port is disconnected */ + OTG_CHR_STATE_SUSPENDED, /* PORT goes to suspend */ + OTG_CHR_STATE_HOST, /* USB in host mode */ +}; + +struct otg_bc_cap { + enum usb_charger_type chrg_type; + enum usb_charger_state chrg_state; + unsigned int ma; +}; + +/** 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 + + /* States */ + enum dwc_otg_state prev; + enum dwc_otg_state state; + struct platform_device *host; + struct platform_device *gadget; + + /* Charger detection */ + struct otg_bc_cap 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); + + /* 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 300 +#define PCI_DEVICE_ID_DWC 0x119E + +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 (*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 usb_charger_state state); + enum usb_charger_type (*get_charger_type)(struct dwc_otg2 *otg); + int (*enable_vbus)(struct dwc_otg2 *otg, int enable); + int (*get_id)(struct dwc_otg2 *otg); +}; + +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); +#endif /* __DWC3_OTG_H */ |