443 lines
13 KiB
C
443 lines
13 KiB
C
/*
|
|
* 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 { 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 */
|