| /* |
| * 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/power_supply.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 GUSB2PHYCFG_ULPI_AUTO_RESUME (1 << 15) |
| #define GUSB2PHYCFG_ULPI_EXT_VBUS_DRV (1 << 17) |
| |
| #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); |
| |
| /* 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 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_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); |
| #endif /* __DWC3_OTG_H */ |