usb: patches for v3.20 merge window

Here's the big pull request for Gadgets and PHYs. It's
 a total of 217 non-merge commits with pretty much everything
 being touched.
 
 The most important bits are a ton of new documentation for
 almost all usb gadget functions, a new isp1760 UDC driver,
 several improvements to the old net2280 UDC driver, and
 some minor tracepoint improvements to dwc3.
 
 Other than that, a big list of minor cleanups, smaller bugfixes
 and new features all over the place.
 
 Signed-off-by: Felipe Balbi <[email protected]>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJU0lRFAAoJEIaOsuA1yqRE17sP/R4iPwrPQGVQBaqg5AOHZGEe
 dKf9GqZZIPzNIs4146Ua5W/9d4U6zQKndy+fRQaNEVc2SR3Tm0IwOSokvSaC3FYr
 NEGHMoRnTWd/JWSVB/6sy0qn8rKRMbkxR7u9lG9M/JACUymn3NJfH4D0jq85ewPR
 0Tjv4g5wGnv3YEmnWgR5ieFgn0OxgUBiGUF7QufgMp7G3F2hjmeligBD0jt3w6tD
 G4oMHp+pRfPCcm8mcdiHoP3aXOtNJ824rI+b1EZkKBKeo7FxRDIe48Vl107XOpOB
 yUFnQVGZazh1Oi6Vxmh9O1mmjpNOir/4dni7gZfh1uGC7cJ7tSkOfbN4jH4Ycsay
 Ckt8XQkmf/z9VWTONsAkDwfPhnMbxCafz8Fi/UdOXsoR69YV1MKnt1zRN5dzgNq9
 7EIqDwPPJi6qwLACoqxVYknSmXQqhW8B0IMPpMqEByvR1mnIOWomlFot63AufMaQ
 +uS7JGJguUmMvkyP1FJRKcPsd9u4PYll5JzymPsvSB6xtDisVFqYb3BbfieZHpBn
 +/ZFqltT71pQ3TxIx2ZiTk1e91PiKJUbEQikV6TBiLhgtkpn2J8obHtF50K4+xHh
 wXOU3VHFd2ZONN+WB5F5EoVtZiwsd3pARr8QJRcVhdXltTWElJ2qsA4Z1+5QVhAy
 mqXYcwsvBe9C+5p2pYwR
 =bGMq
 -----END PGP SIGNATURE-----

Merge tag 'usb-for-v3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

Felipe writes:

usb: patches for v3.20 merge window

Here's the big pull request for Gadgets and PHYs. It's
a total of 217 non-merge commits with pretty much everything
being touched.

The most important bits are a ton of new documentation for
almost all usb gadget functions, a new isp1760 UDC driver,
several improvements to the old net2280 UDC driver, and
some minor tracepoint improvements to dwc3.

Other than that, a big list of minor cleanups, smaller bugfixes
and new features all over the place.

Signed-off-by: Felipe Balbi <[email protected]>
This commit is contained in:
Greg Kroah-Hartman 2015-02-04 11:03:20 -08:00
commit 4d4bac4499
102 changed files with 8135 additions and 2238 deletions

View file

@ -104,6 +104,8 @@ source "drivers/usb/dwc2/Kconfig"
source "drivers/usb/chipidea/Kconfig"
source "drivers/usb/isp1760/Kconfig"
comment "USB port drivers"
if USB

View file

@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_USB_ISP1760) += isp1760/
obj-$(CONFIG_USB_MON) += mon/
@ -23,7 +24,6 @@ obj-$(CONFIG_USB_ISP1362_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/
obj-$(CONFIG_USB_ISP1760_HCD) += host/
obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
obj-$(CONFIG_USB_FUSBH200_HCD) += host/

View file

@ -819,8 +819,8 @@ __acquires(hwep->lock)
}
if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
/* Assume that device is bus powered for now. */
*(u16 *)req->buf = ci->remote_wakeup << 1;
*(u16 *)req->buf = (ci->remote_wakeup << 1) |
ci->gadget.is_selfpowered;
} else if ((setup->bRequestType & USB_RECIP_MASK) \
== USB_RECIP_ENDPOINT) {
dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
@ -1520,6 +1520,19 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
return -ENOTSUPP;
}
static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
struct ci_hw_ep *hwep = ci->ep0in;
unsigned long flags;
spin_lock_irqsave(hwep->lock, flags);
_gadget->is_selfpowered = (is_on != 0);
spin_unlock_irqrestore(hwep->lock, flags);
return 0;
}
/* Change Data+ pullup status
* this func is used by usb_gadget_connect/disconnet
*/
@ -1549,6 +1562,7 @@ static int ci_udc_stop(struct usb_gadget *gadget);
static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_session = ci_udc_vbus_session,
.wakeup = ci_udc_wakeup,
.set_selfpowered = ci_udc_selfpowered,
.pullup = ci_udc_pullup,
.vbus_draw = ci_udc_vbus_draw,
.udc_start = ci_udc_start,

View file

@ -23,7 +23,7 @@ choice
config USB_DWC2_HOST
bool "Host only mode"
depends on USB
depends on USB=y || (USB_DWC2=m && USB)
help
The Designware USB2.0 high-speed host controller
integrated into many SoCs. Select this option if you want the
@ -42,7 +42,7 @@ config USB_DWC2_PERIPHERAL
config USB_DWC2_DUAL_ROLE
bool "Dual Role mode"
depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET)
help
Select this option if you want the driver to work in a dual-role
mode. In this mode both host and gadget features are enabled, and

View file

@ -462,7 +462,7 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
dwc2_enable_common_interrupts(hsotg);
/*
* Do device or host intialization based on mode during PCD and
* Do device or host initialization based on mode during PCD and
* HCD initialization
*/
if (dwc2_is_host_mode(hsotg)) {

View file

@ -108,7 +108,7 @@ struct s3c_hsotg_req;
* @halted: Set if the endpoint has been halted.
* @periodic: Set if this is a periodic ep, such as Interrupt
* @isochronous: Set if this is a isochronous ep
* @sent_zlp: Set if we've sent a zero-length packet.
* @send_zlp: Set if we need to send a zero-length packet.
* @total_data: The total number of data bytes done.
* @fifo_size: The size of the FIFO (for periodic IN endpoints)
* @fifo_load: The amount of data loaded into the FIFO (periodic IN)
@ -149,7 +149,7 @@ struct s3c_hsotg_ep {
unsigned int halted:1;
unsigned int periodic:1;
unsigned int isochronous:1;
unsigned int sent_zlp:1;
unsigned int send_zlp:1;
char name[10];
};
@ -158,14 +158,12 @@ struct s3c_hsotg_ep {
* struct s3c_hsotg_req - data transfer request
* @req: The USB gadget request
* @queue: The list of requests for the endpoint this is queued for.
* @in_progress: Has already had size/packets written to core
* @mapped: DMA buffer for this request has been mapped via dma_map_single().
* @saved_req_buf: variable to save req.buf when bounce buffers are used.
*/
struct s3c_hsotg_req {
struct usb_request req;
struct list_head queue;
unsigned char in_progress;
unsigned char mapped;
void *saved_req_buf;
};
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
@ -193,6 +191,22 @@ enum dwc2_lx_state {
DWC2_L3, /* Off state */
};
/*
* Gadget periodic tx fifo sizes as used by legacy driver
* EP0 is not included
*/
#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
768, 0, 0, 0, 0, 0, 0, 0}
/* Gadget ep0 states */
enum dwc2_ep0_state {
DWC2_EP0_SETUP,
DWC2_EP0_DATA_IN,
DWC2_EP0_DATA_OUT,
DWC2_EP0_STATUS_IN,
DWC2_EP0_STATUS_OUT,
};
/**
* struct dwc2_core_params - Parameters for configuring the core
*
@ -381,7 +395,7 @@ struct dwc2_core_params {
* @power_optimized Are power optimizations enabled?
* @num_dev_ep Number of device endpoints available
* @num_dev_perio_in_ep Number of device periodic IN endpoints
* avaialable
* available
* @dev_token_q_depth Device Mode IN Token Sequence Learning Queue
* Depth
* 0 to 30
@ -434,6 +448,9 @@ struct dwc2_hw_params {
u32 snpsid;
};
/* Size of control and EP0 buffers */
#define DWC2_CTRL_BUFF_SIZE 8
/**
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
* and periodic schedules
@ -552,14 +569,20 @@ struct dwc2_hw_params {
* @num_of_eps: Number of available EPs (excluding EP0)
* @debug_root: Root directrory for debugfs.
* @debug_file: Main status file for debugfs.
* @debug_testmode: Testmode status file for debugfs.
* @debug_fifo: FIFO status file for debugfs.
* @ep0_reply: Request used for ep0 reply.
* @ep0_buff: Buffer for EP0 reply data, if needed.
* @ctrl_buff: Buffer for EP0 control requests.
* @ctrl_req: Request for EP0 control packets.
* @setup: NAK management for EP0 SETUP
* @ep0_state: EP0 control transfers state
* @test_mode: USB test mode requested by the host
* @last_rst: Time of last reset
* @eps: The endpoints being supplied to the gadget framework
* @g_using_dma: Indicate if dma usage is enabled
* @g_rx_fifo_sz: Contains rx fifo size value
* @g_np_g_tx_fifo_sz: Contains Non-Periodic tx fifo size value
* @g_tx_fifo_sz: Contains tx fifo size value per endpoints
*/
struct dwc2_hsotg {
struct device *dev;
@ -591,6 +614,7 @@ struct dwc2_hsotg {
struct dentry *debug_root;
struct dentry *debug_file;
struct dentry *debug_testmode;
struct dentry *debug_fifo;
/* DWC OTG HW Release versions */
@ -684,15 +708,21 @@ struct dwc2_hsotg {
struct usb_request *ep0_reply;
struct usb_request *ctrl_req;
u8 ep0_buff[8];
u8 ctrl_buff[8];
void *ep0_buff;
void *ctrl_buff;
enum dwc2_ep0_state ep0_state;
u8 test_mode;
struct usb_gadget gadget;
unsigned int enabled:1;
unsigned int connected:1;
unsigned int setup:1;
unsigned long last_rst;
struct s3c_hsotg_ep *eps;
struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
u32 g_using_dma;
u32 g_rx_fifo_sz;
u32 g_np_g_tx_fifo_sz;
u32 g_tx_fifo_sz[MAX_EPS_CHANNELS];
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
};
@ -969,7 +999,8 @@ extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2);
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset);
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
#else
@ -981,7 +1012,8 @@ static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
{ return 0; }
static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
{ return 0; }
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {}
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset) {}
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
#endif

File diff suppressed because it is too large Load diff

View file

@ -316,10 +316,12 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
*/
static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
{
if (hsotg->lx_state == DWC2_L2)
if (hsotg->lx_state == DWC2_L2) {
hsotg->flags.b.port_suspend_change = 1;
else
usb_hcd_resume_root_hub(hsotg->priv);
} else {
hsotg->flags.b.port_l1_change = 1;
}
}
/**
@ -1371,7 +1373,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
dwc2_core_init(hsotg, false, -1);
dwc2_enable_global_interrupts(hsotg);
s3c_hsotg_core_init_disconnected(hsotg);
s3c_hsotg_core_init_disconnected(hsotg, false);
s3c_hsotg_core_connect(hsotg);
} else {
/* A-Device connector (Host Mode) */
@ -1473,30 +1475,6 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
}
}
static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
{
u32 hprt0;
/* After clear the Stop PHY clock bit, we should wait for a moment
* for PLL work stable with clock output.
*/
writel(0, hsotg->regs + PCGCTL);
usleep_range(2000, 4000);
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
hprt0 &= ~HPRT0_SUSP;
/* according to USB2.0 Spec 7.1.7.7, the host must send the resume
* signal for at least 20ms
*/
usleep_range(20000, 25000);
hprt0 &= ~HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
hsotg->lx_state = DWC2_L0;
}
/* Handles hub class-specific requests */
static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
u16 wvalue, u16 windex, char *buf, u16 wlength)
@ -1542,7 +1520,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
case USB_PORT_FEAT_SUSPEND:
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
dwc2_port_resume(hsotg);
writel(0, hsotg->regs + PCGCTL);
usleep_range(20000, 40000);
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
hprt0 &= ~HPRT0_SUSP;
usleep_range(100000, 150000);
hprt0 &= ~HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
break;
case USB_PORT_FEAT_POWER:
@ -2317,55 +2305,6 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
usleep_range(1000, 3000);
}
static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
u32 hprt0;
if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
(hsotg->op_state == OTG_STATE_A_HOST)))
return 0;
/* TODO: We get into suspend from 'on' state, maybe we need to do
* something if we get here from DWC2_L1(LPM sleep) state one day.
*/
if (hsotg->lx_state != DWC2_L0)
return 0;
hprt0 = dwc2_read_hprt0(hsotg);
if (hprt0 & HPRT0_CONNSTS) {
dwc2_port_suspend(hsotg, 1);
} else {
u32 pcgctl = readl(hsotg->regs + PCGCTL);
pcgctl |= PCGCTL_STOPPCLK;
writel(pcgctl, hsotg->regs + PCGCTL);
}
return 0;
}
static int _dwc2_hcd_resume(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
u32 hprt0;
if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
(hsotg->op_state == OTG_STATE_A_HOST)))
return 0;
if (hsotg->lx_state != DWC2_L2)
return 0;
hprt0 = dwc2_read_hprt0(hsotg);
if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP))
dwc2_port_resume(hsotg);
else
writel(0, hsotg->regs + PCGCTL);
return 0;
}
/* Returns the current frame number */
static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
{
@ -2736,9 +2675,6 @@ static struct hc_driver dwc2_hc_driver = {
.hub_status_data = _dwc2_hcd_hub_status_data,
.hub_control = _dwc2_hcd_hub_control,
.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
.bus_suspend = _dwc2_hcd_suspend,
.bus_resume = _dwc2_hcd_resume,
};
/*

View file

@ -294,6 +294,7 @@
#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
#define GHWCFG4_NUM_IN_EPS_SHIFT 26
#define GHWCFG4_DED_FIFO_EN (1 << 25)
#define GHWCFG4_DED_FIFO_SHIFT 25
#define GHWCFG4_SESSION_END_FILT_EN (1 << 24)
#define GHWCFG4_B_VALID_FILT_EN (1 << 23)
#define GHWCFG4_A_VALID_FILT_EN (1 << 22)
@ -541,6 +542,7 @@
#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
#define DXEPINT_SETUP_RCVD (1 << 15)
#define DXEPINT_INEPNAKEFF (1 << 6)
#define DXEPINT_BACK2BACKSETUP (1 << 6)
#define DXEPINT_INTKNEPMIS (1 << 5)

View file

@ -155,6 +155,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
struct dwc2_core_params defparams;
struct dwc2_hsotg *hsotg;
struct resource *res;
struct phy *phy;
struct usb_phy *uphy;
int retval;
int irq;
@ -212,6 +214,24 @@ static int dwc2_driver_probe(struct platform_device *dev)
hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
/*
* Attempt to find a generic PHY, then look for an old style
* USB PHY
*/
phy = devm_phy_get(&dev->dev, "usb2-phy");
if (IS_ERR(phy)) {
hsotg->phy = NULL;
uphy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR(uphy))
hsotg->uphy = NULL;
else
hsotg->uphy = uphy;
} else {
hsotg->phy = phy;
phy_power_on(hsotg->phy);
phy_init(hsotg->phy);
}
spin_lock_init(&hsotg->lock);
mutex_init(&hsotg->init_mutex);
retval = dwc2_gadget_init(hsotg, irq);
@ -231,8 +251,15 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
if (dwc2_is_device_mode(dwc2))
if (dwc2_is_device_mode(dwc2)) {
ret = s3c_hsotg_suspend(dwc2);
} else {
if (dwc2->lx_state == DWC2_L0)
return 0;
phy_exit(dwc2->phy);
phy_power_off(dwc2->phy);
}
return ret;
}
@ -241,8 +268,13 @@ static int __maybe_unused dwc2_resume(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
if (dwc2_is_device_mode(dwc2))
if (dwc2_is_device_mode(dwc2)) {
ret = s3c_hsotg_resume(dwc2);
} else {
phy_power_on(dwc2->phy);
phy_init(dwc2->phy);
}
return ret;
}

View file

@ -104,12 +104,6 @@ config USB_DWC3_DEBUG
help
Say Y here to enable debugging messages on DWC3 Driver.
config USB_DWC3_VERBOSE
bool "Enable Verbose Debugging Messages"
depends on USB_DWC3_DEBUG
help
Say Y here to enable verbose debugging messages on DWC3 Driver.
config DWC3_HOST_USB3_LPM_ENABLE
bool "Enable USB3 LPM Capability"
depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y

View file

@ -2,7 +2,6 @@
CFLAGS_trace.o := -I$(src)
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC3) += dwc3.o

View file

@ -345,7 +345,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
dwc->num_in_eps, dwc->num_out_eps);
}

View file

@ -431,7 +431,6 @@ struct dwc3_event_buffer {
* @dwc: pointer to DWC controller
* @saved_state: ep state saved during hibernation
* @flags: endpoint flags (wedged, stalled, ...)
* @current_trb: index of current used trb
* @number: endpoint number (1 - 15)
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
* @resource_index: Resource transfer index
@ -464,8 +463,6 @@ struct dwc3_ep {
/* This last one is specific to EP0 */
#define DWC3_EP0_DIR_IN (1 << 31)
unsigned current_trb;
u8 number;
u8 type;
u8 resource_index;
@ -685,7 +682,6 @@ struct dwc3_scratchpad_array {
* @is_utmi_l1_suspend: the core asserts output signal
* 0 - utmi_sleep_n
* 1 - utmi_l1_suspend_n
* @is_selfpowered: true when we are selfpowered
* @is_fpga: true when we are using the FPGA board
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @pullups_connected: true when Run/Stop bit is set
@ -809,7 +805,6 @@ struct dwc3 {
unsigned has_hibernation:1;
unsigned has_lpm_erratum:1;
unsigned is_utmi_l1_suspend:1;
unsigned is_selfpowered:1;
unsigned is_fpga:1;
unsigned needs_fifo_resize:1;
unsigned pullups_connected:1;

View file

@ -22,9 +22,6 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/usb/otg.h>
#include <linux/usb/usb_phy_generic.h>
#include "platform_data.h"
/* FIXME define these in <linux/pci_ids.h> */
@ -36,66 +33,41 @@
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
struct dwc3_pci {
struct device *dev;
struct platform_device *dwc3;
struct platform_device *usb2_phy;
struct platform_device *usb3_phy;
};
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
static int dwc3_pci_quirks(struct pci_dev *pdev)
{
struct usb_phy_generic_platform_data pdata;
struct platform_device *pdev;
int ret;
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
struct dwc3_platform_data pdata;
memset(&pdata, 0x00, sizeof(pdata));
memset(&pdata, 0, sizeof(pdata));
pdev = platform_device_alloc("usb_phy_generic", 0);
if (!pdev)
return -ENOMEM;
pdata.has_lpm_erratum = true;
pdata.lpm_nyet_threshold = 0xf;
glue->usb2_phy = pdev;
pdata.type = USB_PHY_TYPE_USB2;
pdata.gpio_reset = -1;
pdata.u2exit_lfps_quirk = true;
pdata.u2ss_inp3_quirk = true;
pdata.req_p1p2p3_quirk = true;
pdata.del_p1p2p3_quirk = true;
pdata.del_phy_power_chg_quirk = true;
pdata.lfps_filter_quirk = true;
pdata.rx_detect_poll_quirk = true;
ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
if (ret)
goto err1;
pdata.tx_de_emphasis_quirk = true;
pdata.tx_de_emphasis = 1;
pdev = platform_device_alloc("usb_phy_generic", 1);
if (!pdev) {
ret = -ENOMEM;
goto err1;
/*
* FIXME these quirks should be removed when AMD NL
* taps out
*/
pdata.disable_scramble_quirk = true;
pdata.dis_u3_susphy_quirk = true;
pdata.dis_u2_susphy_quirk = true;
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
sizeof(pdata));
}
glue->usb3_phy = pdev;
pdata.type = USB_PHY_TYPE_USB3;
ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
if (ret)
goto err2;
ret = platform_device_add(glue->usb2_phy);
if (ret)
goto err2;
ret = platform_device_add(glue->usb3_phy);
if (ret)
goto err3;
return 0;
err3:
platform_device_del(glue->usb2_phy);
err2:
platform_device_put(glue->usb3_phy);
err1:
platform_device_put(glue->usb2_phy);
return ret;
}
static int dwc3_pci_probe(struct pci_dev *pci,
@ -103,18 +75,8 @@ static int dwc3_pci_probe(struct pci_dev *pci,
{
struct resource res[2];
struct platform_device *dwc3;
struct dwc3_pci *glue;
int ret;
struct device *dev = &pci->dev;
struct dwc3_platform_data dwc3_pdata;
memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
if (!glue)
return -ENOMEM;
glue->dev = dev;
ret = pcim_enable_device(pci);
if (ret) {
@ -124,12 +86,6 @@ static int dwc3_pci_probe(struct pci_dev *pci,
pci_set_master(pci);
ret = dwc3_pci_register_phys(glue);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
return ret;
}
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
if (!dwc3) {
dev_err(dev, "couldn't allocate dwc3 device\n");
@ -147,70 +103,34 @@ static int dwc3_pci_probe(struct pci_dev *pci,
res[1].name = "dwc_usb3";
res[1].flags = IORESOURCE_IRQ;
if (pci->vendor == PCI_VENDOR_ID_AMD &&
pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
dwc3_pdata.has_lpm_erratum = true;
dwc3_pdata.lpm_nyet_threshold = 0xf;
dwc3_pdata.u2exit_lfps_quirk = true;
dwc3_pdata.u2ss_inp3_quirk = true;
dwc3_pdata.req_p1p2p3_quirk = true;
dwc3_pdata.del_p1p2p3_quirk = true;
dwc3_pdata.del_phy_power_chg_quirk = true;
dwc3_pdata.lfps_filter_quirk = true;
dwc3_pdata.rx_detect_poll_quirk = true;
dwc3_pdata.tx_de_emphasis_quirk = true;
dwc3_pdata.tx_de_emphasis = 1;
/*
* FIXME these quirks should be removed when AMD NL
* taps out
*/
dwc3_pdata.disable_scramble_quirk = true;
dwc3_pdata.dis_u3_susphy_quirk = true;
dwc3_pdata.dis_u2_susphy_quirk = true;
}
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n");
return ret;
}
pci_set_drvdata(pci, glue);
ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
pci_set_drvdata(pci, dwc3);
ret = dwc3_pci_quirks(pci);
if (ret)
goto err3;
goto err;
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
dwc3->dev.dma_mask = dev->dma_mask;
dwc3->dev.dma_parms = dev->dma_parms;
dwc3->dev.parent = dev;
glue->dwc3 = dwc3;
ret = platform_device_add(dwc3);
if (ret) {
dev_err(dev, "failed to register dwc3 device\n");
goto err3;
goto err;
}
return 0;
err3:
err:
platform_device_put(dwc3);
return ret;
}
static void dwc3_pci_remove(struct pci_dev *pci)
{
struct dwc3_pci *glue = pci_get_drvdata(pci);
platform_device_unregister(glue->dwc3);
platform_device_unregister(glue->usb2_phy);
platform_device_unregister(glue->usb3_phy);
platform_device_unregister(pci_get_drvdata(pci));
}
static const struct pci_device_id dwc3_pci_id_table[] = {
@ -228,45 +148,11 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
#ifdef CONFIG_PM_SLEEP
static int dwc3_pci_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
pci_disable_device(pci);
return 0;
}
static int dwc3_pci_resume(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
int ret;
ret = pci_enable_device(pci);
if (ret) {
dev_err(dev, "can't re-enable device --> %d\n", ret);
return ret;
}
pci_set_master(pci);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
};
static struct pci_driver dwc3_pci_driver = {
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = dwc3_pci_remove,
.driver = {
.pm = &dwc3_pci_dev_pm_ops,
},
};
MODULE_AUTHOR("Felipe Balbi <[email protected]>");

View file

@ -344,7 +344,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
/*
* LTM will be set once we know how to set this in HW.
*/
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
usb_status |= dwc->gadget.is_selfpowered;
if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);

View file

@ -139,7 +139,8 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
udelay(5);
}
dev_vdbg(dwc->dev, "link state change request timed out\n");
dwc3_trace(trace_dwc3_gadget,
"link state change request timed out");
return -ETIMEDOUT;
}
@ -219,7 +220,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
fifo_size |= (last_fifo_depth << 16);
dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
dep->name, last_fifo_depth, fifo_size & 0xffff);
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
@ -287,7 +288,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
do {
reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
if (!(reg & DWC3_DGCMD_CMDACT)) {
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
dwc3_trace(trace_dwc3_gadget,
"Command Complete --> %d",
DWC3_DGCMD_STATUS(reg));
return 0;
}
@ -297,8 +299,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
* interrupt context.
*/
timeout--;
if (!timeout)
if (!timeout) {
dwc3_trace(trace_dwc3_gadget,
"Command Timed Out");
return -ETIMEDOUT;
}
udelay(1);
} while (1);
}
@ -320,7 +325,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
do {
reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
if (!(reg & DWC3_DEPCMD_CMDACT)) {
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
dwc3_trace(trace_dwc3_gadget,
"Command Complete --> %d",
DWC3_DEPCMD_STATUS(reg));
return 0;
}
@ -330,8 +336,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
* interrupt context.
*/
timeout--;
if (!timeout)
if (!timeout) {
dwc3_trace(trace_dwc3_gadget,
"Command Timed Out");
return -ETIMEDOUT;
}
udelay(1);
} while (1);
@ -352,9 +361,6 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
if (dep->trb_pool)
return 0;
if (dep->number == 0 || dep->number == 1)
return 0;
dep->trb_pool = dma_alloc_coherent(dwc->dev,
sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
&dep->trb_pool_dma, GFP_KERNEL);
@ -492,7 +498,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
u32 reg;
int ret;
dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
if (!(dep->flags & DWC3_EP_ENABLED)) {
ret = dwc3_gadget_start_config(dwc, dep);
@ -729,10 +735,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
struct dwc3_request *req, dma_addr_t dma,
unsigned length, unsigned last, unsigned chain, unsigned node)
{
struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb;
dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s",
dep->name, req, (unsigned long long) dma,
length, last ? " last" : "",
chain ? " chain" : "");
@ -934,7 +939,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
u32 cmd;
if (start_new && (dep->flags & DWC3_EP_BUSY)) {
dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
return -EBUSY;
}
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
@ -1005,8 +1010,9 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
u32 uf;
if (list_empty(&dep->request_list)) {
dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
dep->name);
dwc3_trace(trace_dwc3_gadget,
"ISOC ep %s run out for requests",
dep->name);
dep->flags |= DWC3_EP_PENDING_REQUEST;
return;
}
@ -1113,15 +1119,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* handled.
*/
if (dep->stream_capable) {
int ret;
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
if (ret && ret != -EBUSY) {
struct dwc3 *dwc = dep->dwc;
if (ret && ret != -EBUSY)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
}
}
return 0;
@ -1152,8 +1153,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
goto out;
}
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
request, ep->name, request->length);
trace_dwc3_ep_queue(req);
ret = __dwc3_gadget_ep_queue(dep, req);
@ -1416,7 +1415,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dwc->is_selfpowered = !!is_selfpowered;
g->is_selfpowered = !!is_selfpowered;
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
@ -1468,7 +1467,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
udelay(1);
} while (1);
dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
dwc->gadget_driver
? dwc->gadget_driver->function : "no-function",
is_on ? "connect" : "disconnect");
@ -1688,7 +1687,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
dep->endpoint.name = dep->name;
dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name);
if (epnum == 0 || epnum == 1) {
usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
@ -1725,13 +1724,15 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
if (ret < 0) {
dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
dwc3_trace(trace_dwc3_gadget,
"failed to allocate OUT endpoints");
return ret;
}
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
if (ret < 0) {
dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
dwc3_trace(trace_dwc3_gadget,
"failed to allocate IN endpoints");
return ret;
}
@ -1977,7 +1978,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
} else {
int ret;
dev_vdbg(dwc->dev, "%s: reason %s\n",
dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
dep->name, event->status &
DEPEVT_STATUS_TRANSFER_ACTIVE
? "Transfer Active"
@ -2001,7 +2002,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
switch (event->status) {
case DEPEVT_STREAMEVT_FOUND:
dev_vdbg(dwc->dev, "Stream %d found and started\n",
dwc3_trace(trace_dwc3_gadget,
"Stream %d found and started",
event->parameters);
break;
@ -2015,7 +2017,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
break;
case DWC3_DEPEVT_EPCMDCMPLT:
dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
break;
}
}
@ -2043,6 +2045,7 @@ static void dwc3_resume_gadget(struct dwc3 *dwc)
if (dwc->gadget_driver && dwc->gadget_driver->resume) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->resume(&dwc->gadget);
spin_lock(&dwc->lock);
}
}
@ -2079,7 +2082,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
* We have discussed this with the IP Provider and it was
* suggested to giveback all requests here, but give HW some
* extra time to synchronize with the interconnect. We're using
* an arbitraty 100us delay for that.
* an arbitrary 100us delay for that.
*
* Note also that a similar handling was tested by Synopsys
* (thanks a lot Paul) and nothing bad has come out of it.
@ -2389,7 +2392,8 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
(next == DWC3_LINK_STATE_RESUME)) {
dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
dwc3_trace(trace_dwc3_gadget,
"ignoring transition U3 -> Resume");
return;
}
}
@ -2511,22 +2515,22 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_EOPF:
dev_vdbg(dwc->dev, "End of Periodic Frame\n");
dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
break;
case DWC3_DEVICE_EVENT_SOF:
dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame");
break;
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
dev_vdbg(dwc->dev, "Erratic Error\n");
dwc3_trace(trace_dwc3_gadget, "Erratic Error");
break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
dev_vdbg(dwc->dev, "Command Complete\n");
dwc3_trace(trace_dwc3_gadget, "Command Complete");
break;
case DWC3_DEVICE_EVENT_OVERFLOW:
dev_vdbg(dwc->dev, "Overflow\n");
dwc3_trace(trace_dwc3_gadget, "Overflow");
break;
default:
dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
}
}

View file

@ -47,6 +47,16 @@ DEFINE_EVENT(dwc3_log_msg, dwc3_writel,
TP_ARGS(vaf)
);
DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(dwc3_log_msg, dwc3_core,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)

View file

@ -423,6 +423,17 @@ config USB_CONFIGFS_F_HID
For more information, see Documentation/usb/gadget_hid.txt.
config USB_CONFIGFS_F_UVC
bool "USB Webcam function"
depends on USB_CONFIGFS
depends on VIDEO_DEV
select VIDEOBUF2_VMALLOC
select USB_F_UVC
help
The Webcam function acts as a composite USB Audio and Video Class
device. It provides a userspace API to process UVC control requests
and stream video data to the host.
source "drivers/usb/gadget/legacy/Kconfig"
endchoice

View file

@ -1655,7 +1655,7 @@ unknown:
* OS descriptors handling
*/
if (cdev->use_os_string && cdev->os_desc_config &&
(ctrl->bRequest & USB_TYPE_VENDOR) &&
(ctrl->bRequestType & USB_TYPE_VENDOR) &&
ctrl->bRequest == cdev->b_vendor_code) {
struct usb_request *req;
struct usb_configuration *os_desc_cfg;

View file

@ -36,7 +36,7 @@ usb_f_uac1-y := f_uac1.o u_uac1.o
obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o
usb_f_uac2-y := f_uac2.o
obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o
usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o
obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o
usb_f_midi-y := f_midi.o
obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o

View file

@ -31,6 +31,7 @@
#include <linux/aio.h>
#include <linux/mmu_context.h>
#include <linux/poll.h>
#include <linux/eventfd.h>
#include "u_fs.h"
#include "u_f.h"
@ -153,6 +154,8 @@ struct ffs_io_data {
struct usb_ep *ep;
struct usb_request *req;
struct ffs_data *ffs;
};
struct ffs_desc_helper {
@ -390,17 +393,20 @@ done_spin:
return ret;
}
/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
{
/*
* We are holding ffs->ev.waitq.lock and ffs->mutex and we need
* to release them.
* n cannot be bigger than ffs->ev.count, which cannot be bigger than
* size of ffs->ev.types array (which is four) so that's how much space
* we reserve.
*/
struct usb_functionfs_event events[n];
struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
const size_t size = n * sizeof *events;
unsigned i = 0;
memset(events, 0, sizeof events);
memset(events, 0, size);
do {
events[i].type = ffs->ev.types[i];
@ -410,19 +416,15 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
}
} while (++i < n);
if (n < ffs->ev.count) {
ffs->ev.count -= n;
ffs->ev.count -= n;
if (ffs->ev.count)
memmove(ffs->ev.types, ffs->ev.types + n,
ffs->ev.count * sizeof *ffs->ev.types);
} else {
ffs->ev.count = 0;
}
spin_unlock_irq(&ffs->ev.waitq.lock);
mutex_unlock(&ffs->mutex);
return unlikely(__copy_to_user(buf, events, sizeof events))
? -EFAULT : sizeof events;
return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size;
}
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
@ -606,6 +608,8 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait)
}
case FFS_CLOSING:
break;
case FFS_DEACTIVATED:
break;
}
mutex_unlock(&ffs->mutex);
@ -673,6 +677,9 @@ static void ffs_user_copy_worker(struct work_struct *work)
aio_complete(io_data->kiocb, ret, ret);
if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd)
eventfd_signal(io_data->ffs->ffs_eventfd, 1);
usb_ep_free_request(io_data->ep, io_data->req);
io_data->kiocb->private = NULL;
@ -826,6 +833,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
io_data->buf = data;
io_data->ep = ep->ep;
io_data->req = req;
io_data->ffs = epfile->ffs;
req->context = io_data;
req->complete = ffs_epfile_async_io_complete;
@ -1180,6 +1188,7 @@ struct ffs_sb_fill_data {
struct ffs_file_perms perms;
umode_t root_mode;
const char *dev_name;
bool no_disconnect;
struct ffs_data *ffs_data;
};
@ -1250,6 +1259,12 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
/* Interpret option */
switch (eq - opts) {
case 13:
if (!memcmp(opts, "no_disconnect", 13))
data->no_disconnect = !!value;
else
goto invalid;
break;
case 5:
if (!memcmp(opts, "rmode", 5))
data->root_mode = (value & 0555) | S_IFDIR;
@ -1314,6 +1329,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
.gid = GLOBAL_ROOT_GID,
},
.root_mode = S_IFDIR | 0500,
.no_disconnect = false,
};
struct dentry *rv;
int ret;
@ -1330,6 +1346,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
if (unlikely(!ffs))
return ERR_PTR(-ENOMEM);
ffs->file_perms = data.perms;
ffs->no_disconnect = data.no_disconnect;
ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
if (unlikely(!ffs->dev_name)) {
@ -1361,6 +1378,7 @@ ffs_fs_kill_sb(struct super_block *sb)
kill_litter_super(sb);
if (sb->s_fs_info) {
ffs_release_dev(sb->s_fs_info);
ffs_data_closed(sb->s_fs_info);
ffs_data_put(sb->s_fs_info);
}
}
@ -1417,7 +1435,11 @@ static void ffs_data_opened(struct ffs_data *ffs)
ENTER();
atomic_inc(&ffs->ref);
atomic_inc(&ffs->opened);
if (atomic_add_return(1, &ffs->opened) == 1 &&
ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
}
static void ffs_data_put(struct ffs_data *ffs)
@ -1439,6 +1461,21 @@ static void ffs_data_closed(struct ffs_data *ffs)
ENTER();
if (atomic_dec_and_test(&ffs->opened)) {
if (ffs->no_disconnect) {
ffs->state = FFS_DEACTIVATED;
if (ffs->epfiles) {
ffs_epfiles_destroy(ffs->epfiles,
ffs->eps_count);
ffs->epfiles = NULL;
}
if (ffs->setup_state == FFS_SETUP_PENDING)
__ffs_ep0_stall(ffs);
} else {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
}
if (atomic_read(&ffs->opened) < 0) {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
@ -1480,6 +1517,9 @@ static void ffs_data_clear(struct ffs_data *ffs)
if (ffs->epfiles)
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
if (ffs->ffs_eventfd)
eventfd_ctx_put(ffs->ffs_eventfd);
kfree(ffs->raw_descs_data);
kfree(ffs->raw_strings);
kfree(ffs->stringtabs);
@ -1581,10 +1621,10 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
mutex_init(&epfile->mutex);
init_waitqueue_head(&epfile->wait);
if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
sprintf(epfiles->name, "ep%02x", ffs->eps_addrmap[i]);
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
else
sprintf(epfiles->name, "ep%u", i);
epfile->dentry = ffs_sb_create_file(ffs->sb, epfiles->name,
sprintf(epfile->name, "ep%u", i);
epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
epfile,
&ffs_epfile_operations);
if (unlikely(!epfile->dentry)) {
@ -1616,7 +1656,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
kfree(epfiles);
}
static void ffs_func_eps_disable(struct ffs_function *func)
{
struct ffs_ep *ep = func->eps;
@ -1629,10 +1668,12 @@ static void ffs_func_eps_disable(struct ffs_function *func)
/* pending requests get nuked */
if (likely(ep->ep))
usb_ep_disable(ep->ep);
epfile->ep = NULL;
++ep;
++epfile;
if (epfile) {
epfile->ep = NULL;
++epfile;
}
} while (--count);
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
}
@ -2138,7 +2179,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
FUNCTIONFS_HAS_HS_DESC |
FUNCTIONFS_HAS_SS_DESC |
FUNCTIONFS_HAS_MS_OS_DESC |
FUNCTIONFS_VIRTUAL_ADDR)) {
FUNCTIONFS_VIRTUAL_ADDR |
FUNCTIONFS_EVENTFD)) {
ret = -ENOSYS;
goto error;
}
@ -2149,6 +2191,20 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
goto error;
}
if (flags & FUNCTIONFS_EVENTFD) {
if (len < 4)
goto error;
ffs->ffs_eventfd =
eventfd_ctx_fdget((int)get_unaligned_le32(data));
if (IS_ERR(ffs->ffs_eventfd)) {
ret = PTR_ERR(ffs->ffs_eventfd);
ffs->ffs_eventfd = NULL;
goto error;
}
data += 4;
len -= 4;
}
/* Read fs_count, hs_count and ss_count (if present) */
for (i = 0; i < 3; ++i) {
if (!(flags & (1 << i))) {
@ -2377,6 +2433,13 @@ static void __ffs_event_add(struct ffs_data *ffs,
if (ffs->setup_state == FFS_SETUP_PENDING)
ffs->setup_state = FFS_SETUP_CANCELLED;
/*
* Logic of this function guarantees that there are at most four pending
* evens on ffs->ev.types queue. This is important because the queue
* has space for four elements only and __ffs_ep0_read_events function
* depends on that limit as well. If more event types are added, those
* limits have to be revisited or guaranteed to still hold.
*/
switch (type) {
case FUNCTIONFS_RESUME:
rem_type2 = FUNCTIONFS_SUSPEND;
@ -2416,6 +2479,8 @@ static void __ffs_event_add(struct ffs_data *ffs,
pr_vdebug("adding event %d\n", type);
ffs->ev.types[ffs->ev.count++] = type;
wake_up_locked(&ffs->ev.waitq);
if (ffs->ffs_eventfd)
eventfd_signal(ffs->ffs_eventfd, 1);
}
static void ffs_event_add(struct ffs_data *ffs,
@ -2888,6 +2953,13 @@ static int ffs_func_bind(struct usb_configuration *c,
/* Other USB function hooks *************************************************/
static void ffs_reset_work(struct work_struct *work)
{
struct ffs_data *ffs = container_of(work,
struct ffs_data, reset_work);
ffs_data_reset(ffs);
}
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
@ -2904,6 +2976,13 @@ static int ffs_func_set_alt(struct usb_function *f,
if (ffs->func)
ffs_func_eps_disable(ffs->func);
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return -ENODEV;
}
if (ffs->state != FFS_ACTIVE)
return -ENODEV;

View file

@ -759,7 +759,7 @@ static struct f_hid_opts_attribute f_hid_opts_##name = \
F_HID_OPT(subclass, 8, 255);
F_HID_OPT(protocol, 8, 255);
F_HID_OPT(report_length, 16, 65536);
F_HID_OPT(report_length, 16, 65535);
static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
{

View file

@ -1214,7 +1214,7 @@ static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->pattern);
result = sprintf(page, "%u", opts->pattern);
mutex_unlock(&opts->lock);
return result;
@ -1258,7 +1258,7 @@ static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->isoc_interval);
result = sprintf(page, "%u", opts->isoc_interval);
mutex_unlock(&opts->lock);
return result;
@ -1302,7 +1302,7 @@ static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->isoc_maxpacket);
result = sprintf(page, "%u", opts->isoc_maxpacket);
mutex_unlock(&opts->lock);
return result;
@ -1346,7 +1346,7 @@ static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->isoc_mult);
result = sprintf(page, "%u", opts->isoc_mult);
mutex_unlock(&opts->lock);
return result;
@ -1390,7 +1390,7 @@ static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->isoc_maxburst);
result = sprintf(page, "%u", opts->isoc_maxburst);
mutex_unlock(&opts->lock);
return result;
@ -1434,7 +1434,7 @@ static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->bulk_buflen);
result = sprintf(page, "%u", opts->bulk_buflen);
mutex_unlock(&opts->lock);
return result;
@ -1473,7 +1473,7 @@ static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->int_interval);
result = sprintf(page, "%u", opts->int_interval);
mutex_unlock(&opts->lock);
return result;
@ -1517,7 +1517,7 @@ static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->int_maxpacket);
result = sprintf(page, "%u", opts->int_maxpacket);
mutex_unlock(&opts->lock);
return result;
@ -1561,7 +1561,7 @@ static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->int_mult);
result = sprintf(page, "%u", opts->int_mult);
mutex_unlock(&opts->lock);
return result;
@ -1605,7 +1605,7 @@ static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->int_maxburst);
result = sprintf(page, "%u", opts->int_maxburst);
mutex_unlock(&opts->lock);
return result;

View file

@ -31,7 +31,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
*/
#define F_AUDIO_AC_INTERFACE 0
#define F_AUDIO_AS_INTERFACE 1
#define F_AUDIO_NUM_INTERFACES 2
#define F_AUDIO_NUM_INTERFACES 1
/* B.3.1 Standard AC Interface Descriptor */
static struct usb_interface_descriptor ac_interface_desc = {
@ -42,14 +42,18 @@ static struct usb_interface_descriptor ac_interface_desc = {
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
};
DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
/*
* The number of AudioStreaming and MIDIStreaming interfaces
* in the Audio Interface Collection
*/
DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
/* 1 input terminal, 1 output terminal and 1 feature unit */
#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
/* B.3.2 Class-Specific AC Interface Descriptor */
static struct uac1_ac_header_descriptor_2 ac_header_desc = {
static struct uac1_ac_header_descriptor_1 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_HEADER,
@ -57,8 +61,8 @@ static struct uac1_ac_header_descriptor_2 ac_header_desc = {
.wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
.bInCollection = F_AUDIO_NUM_INTERFACES,
.baInterfaceNr = {
[0] = F_AUDIO_AC_INTERFACE,
[1] = F_AUDIO_AS_INTERFACE,
/* Interface number of the first AudioStream interface */
[0] = 1,
}
};
@ -584,6 +588,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (intf == 1) {
if (alt == 1) {
config_ep_by_speed(cdev->gadget, f, out_ep);
usb_ep_enable(out_ep);
out_ep->driver_data = audio;
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
@ -669,7 +674,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
audio->card.gadget = c->cdev->gadget;
audio_opts->card = &audio->card;
/* set up ASLA audio devices */
if (!audio_opts->bound) {
status = gaudio_setup(&audio->card);

View file

@ -27,10 +27,11 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-event.h>
#include "u_uvc.h"
#include "uvc.h"
#include "uvc_configfs.h"
#include "uvc_v4l2.h"
#include "uvc_video.h"
#include "u_uvc.h"
unsigned int uvc_gadget_trace_param;
@ -509,6 +510,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
break;
}
if (!uvc_control_desc || !uvc_streaming_cls)
return ERR_PTR(-ENODEV);
/* Descriptors layout
*
* uvc_iad
@ -605,7 +609,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
INFO(cdev, "uvc_function_bind\n");
opts = to_f_uvc_opts(f->fi);
opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters.
*/
opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
@ -700,10 +704,27 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
/* Copy descriptors */
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
if (gadget_is_dualspeed(cdev->gadget))
if (IS_ERR(f->fs_descriptors)) {
ret = PTR_ERR(f->fs_descriptors);
f->fs_descriptors = NULL;
goto error;
}
if (gadget_is_dualspeed(cdev->gadget)) {
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
if (gadget_is_superspeed(c->cdev->gadget))
if (IS_ERR(f->hs_descriptors)) {
ret = PTR_ERR(f->hs_descriptors);
f->hs_descriptors = NULL;
goto error;
}
}
if (gadget_is_superspeed(c->cdev->gadget)) {
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
if (IS_ERR(f->ss_descriptors)) {
ret = PTR_ERR(f->ss_descriptors);
f->ss_descriptors = NULL;
goto error;
}
}
/* Preallocate control endpoint request. */
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
@ -766,27 +787,106 @@ error:
static void uvc_free_inst(struct usb_function_instance *f)
{
struct f_uvc_opts *opts = to_f_uvc_opts(f);
struct f_uvc_opts *opts = fi_to_f_uvc_opts(f);
mutex_destroy(&opts->lock);
kfree(opts);
}
static struct usb_function_instance *uvc_alloc_inst(void)
{
struct f_uvc_opts *opts;
struct uvc_camera_terminal_descriptor *cd;
struct uvc_processing_unit_descriptor *pd;
struct uvc_output_terminal_descriptor *od;
struct uvc_color_matching_descriptor *md;
struct uvc_descriptor_header **ctl_cls;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = uvc_free_inst;
mutex_init(&opts->lock);
cd = &opts->uvc_camera_terminal;
cd->bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3);
cd->bDescriptorType = USB_DT_CS_INTERFACE;
cd->bDescriptorSubType = UVC_VC_INPUT_TERMINAL;
cd->bTerminalID = 1;
cd->wTerminalType = cpu_to_le16(0x0201);
cd->bAssocTerminal = 0;
cd->iTerminal = 0;
cd->wObjectiveFocalLengthMin = cpu_to_le16(0);
cd->wObjectiveFocalLengthMax = cpu_to_le16(0);
cd->wOcularFocalLength = cpu_to_le16(0);
cd->bControlSize = 3;
cd->bmControls[0] = 2;
cd->bmControls[1] = 0;
cd->bmControls[2] = 0;
pd = &opts->uvc_processing;
pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2);
pd->bDescriptorType = USB_DT_CS_INTERFACE;
pd->bDescriptorSubType = UVC_VC_PROCESSING_UNIT;
pd->bUnitID = 2;
pd->bSourceID = 1;
pd->wMaxMultiplier = cpu_to_le16(16*1024);
pd->bControlSize = 2;
pd->bmControls[0] = 1;
pd->bmControls[1] = 0;
pd->iProcessing = 0;
od = &opts->uvc_output_terminal;
od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE;
od->bDescriptorType = USB_DT_CS_INTERFACE;
od->bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL;
od->bTerminalID = 3;
od->wTerminalType = cpu_to_le16(0x0101);
od->bAssocTerminal = 0;
od->bSourceID = 2;
od->iTerminal = 0;
md = &opts->uvc_color_matching;
md->bLength = UVC_DT_COLOR_MATCHING_SIZE;
md->bDescriptorType = USB_DT_CS_INTERFACE;
md->bDescriptorSubType = UVC_VS_COLORFORMAT;
md->bColorPrimaries = 1;
md->bTransferCharacteristics = 1;
md->bMatrixCoefficients = 4;
/* Prepare fs control class descriptors for configfs-based gadgets */
ctl_cls = opts->uvc_fs_control_cls;
ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
ctl_cls[1] = (struct uvc_descriptor_header *)cd;
ctl_cls[2] = (struct uvc_descriptor_header *)pd;
ctl_cls[3] = (struct uvc_descriptor_header *)od;
ctl_cls[4] = NULL; /* NULL-terminate */
opts->fs_control =
(const struct uvc_descriptor_header * const *)ctl_cls;
/* Prepare hs control class descriptors for configfs-based gadgets */
ctl_cls = opts->uvc_ss_control_cls;
ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
ctl_cls[1] = (struct uvc_descriptor_header *)cd;
ctl_cls[2] = (struct uvc_descriptor_header *)pd;
ctl_cls[3] = (struct uvc_descriptor_header *)od;
ctl_cls[4] = NULL; /* NULL-terminate */
opts->ss_control =
(const struct uvc_descriptor_header * const *)ctl_cls;
opts->streaming_interval = 1;
opts->streaming_maxpacket = 1024;
uvcg_attach_configfs(opts);
return &opts->func_inst;
}
static void uvc_free(struct usb_function *f)
{
struct uvc_device *uvc = to_uvc(f);
struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
func_inst);
--opts->refcnt;
kfree(uvc);
}
@ -812,19 +912,39 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
{
struct uvc_device *uvc;
struct f_uvc_opts *opts;
struct uvc_descriptor_header **strm_cls;
uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
if (uvc == NULL)
return ERR_PTR(-ENOMEM);
uvc->state = UVC_STATE_DISCONNECTED;
opts = to_f_uvc_opts(fi);
opts = fi_to_f_uvc_opts(fi);
mutex_lock(&opts->lock);
if (opts->uvc_fs_streaming_cls) {
strm_cls = opts->uvc_fs_streaming_cls;
opts->fs_streaming =
(const struct uvc_descriptor_header * const *)strm_cls;
}
if (opts->uvc_hs_streaming_cls) {
strm_cls = opts->uvc_hs_streaming_cls;
opts->hs_streaming =
(const struct uvc_descriptor_header * const *)strm_cls;
}
if (opts->uvc_ss_streaming_cls) {
strm_cls = opts->uvc_ss_streaming_cls;
opts->ss_streaming =
(const struct uvc_descriptor_header * const *)strm_cls;
}
uvc->desc.fs_control = opts->fs_control;
uvc->desc.ss_control = opts->ss_control;
uvc->desc.fs_streaming = opts->fs_streaming;
uvc->desc.hs_streaming = opts->hs_streaming;
uvc->desc.ss_streaming = opts->ss_streaming;
++opts->refcnt;
mutex_unlock(&opts->lock);
/* Register the function. */
uvc->func.name = "uvc";

View file

@ -729,9 +729,7 @@ static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
if (len < 18)
return -EINVAL;
snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
dev_addr[0], dev_addr[1], dev_addr[2],
dev_addr[3], dev_addr[4], dev_addr[5]);
snprintf(str, len, "%pM", dev_addr);
return 18;
}

View file

@ -19,6 +19,7 @@
#include <linux/usb/composite.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#ifdef VERBOSE_DEBUG
#ifndef pr_vdebug
@ -92,6 +93,26 @@ enum ffs_state {
*/
FFS_ACTIVE,
/*
* Function is visible to host, but it's not functional. All
* setup requests are stalled and transfers on another endpoints
* are refused. All epfiles, except ep0, are deleted so there
* is no way to perform any operations on them.
*
* This state is set after closing all functionfs files, when
* mount parameter "no_disconnect=1" has been set. Function will
* remain in deactivated state until filesystem is umounted or
* ep0 is opened again. In the second case functionfs state will
* be reset, and it will be ready for descriptors and strings
* writing.
*
* This is useful only when functionfs is composed to gadget
* with another function which can perform some critical
* operations, and it's strongly desired to have this operations
* completed, even after functionfs files closure.
*/
FFS_DEACTIVATED,
/*
* All endpoints have been closed. This state is also set if
* we encounter an unrecoverable error. The only
@ -251,6 +272,10 @@ struct ffs_data {
kgid_t gid;
} file_perms;
struct eventfd_ctx *ffs_eventfd;
bool no_disconnect;
struct work_struct reset_work;
/*
* The endpoint files, filled by ffs_epfiles_create(),
* destroyed by ffs_epfiles_destroy().

View file

@ -308,8 +308,7 @@ int gaudio_setup(struct gaudio *card)
*/
void gaudio_cleanup(struct gaudio *the_card)
{
if (the_card) {
if (the_card)
gaudio_close_snd_dev(the_card);
}
}

View file

@ -70,7 +70,6 @@ struct f_uac1_opts {
unsigned fn_play_alloc:1;
unsigned fn_cap_alloc:1;
unsigned fn_cntl_alloc:1;
struct gaudio *card;
struct mutex lock;
int refcnt;
};

View file

@ -17,8 +17,9 @@
#define U_UVC_H
#include <linux/usb/composite.h>
#include <linux/usb/video.h>
#define to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst)
#define fi_to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst)
struct f_uvc_opts {
struct usb_function_instance func_inst;
@ -26,11 +27,60 @@ struct f_uvc_opts {
unsigned int streaming_interval;
unsigned int streaming_maxpacket;
unsigned int streaming_maxburst;
/*
* Control descriptors array pointers for full-/high-speed and
* super-speed. They point by default to the uvc_fs_control_cls and
* uvc_ss_control_cls arrays respectively. Legacy gadgets must
* override them in their gadget bind callback.
*/
const struct uvc_descriptor_header * const *fs_control;
const struct uvc_descriptor_header * const *ss_control;
/*
* Streaming descriptors array pointers for full-speed, high-speed and
* super-speed. They will point to the uvc_[fhs]s_streaming_cls arrays
* for configfs-based gadgets. Legacy gadgets must initialize them in
* their gadget bind callback.
*/
const struct uvc_descriptor_header * const *fs_streaming;
const struct uvc_descriptor_header * const *hs_streaming;
const struct uvc_descriptor_header * const *ss_streaming;
/* Default control descriptors for configfs-based gadgets. */
struct uvc_camera_terminal_descriptor uvc_camera_terminal;
struct uvc_processing_unit_descriptor uvc_processing;
struct uvc_output_terminal_descriptor uvc_output_terminal;
struct uvc_color_matching_descriptor uvc_color_matching;
/*
* Control descriptors pointers arrays for full-/high-speed and
* super-speed. The first element is a configurable control header
* descriptor, the other elements point to the fixed default control
* descriptors. Used by configfs only, must not be touched by legacy
* gadgets.
*/
struct uvc_descriptor_header *uvc_fs_control_cls[5];
struct uvc_descriptor_header *uvc_ss_control_cls[5];
/*
* Streaming descriptors for full-speed, high-speed and super-speed.
* Used by configfs only, must not be touched by legacy gadgets. The
* arrays are allocated at runtime as the number of descriptors isn't
* known in advance.
*/
struct uvc_descriptor_header **uvc_fs_streaming_cls;
struct uvc_descriptor_header **uvc_hs_streaming_cls;
struct uvc_descriptor_header **uvc_ss_streaming_cls;
/*
* Read/write access to configfs attributes is handled by configfs.
*
* This lock protects the descriptors from concurrent access by
* read/write and symlink creation/removal.
*/
struct mutex lock;
int refcnt;
};
void uvc_set_trace_param(unsigned int trace);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,22 @@
/*
* uvc_configfs.h
*
* Configfs support for the uvc function.
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef UVC_CONFIGFS_H
#define UVC_CONFIGFS_H
struct f_uvc_opts;
int uvcg_attach_configfs(struct f_uvc_opts *opts);
#endif /* UVC_CONFIGFS_H */

View file

@ -176,7 +176,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
udc->enabled
? (udc->vbus ? "active" : "enabled")
: "disabled",
udc->selfpowered ? "self" : "VBUS",
udc->gadget.is_selfpowered ? "self" : "VBUS",
udc->suspended ? ", suspended" : "",
udc->driver ? udc->driver->driver.name : "(none)");
@ -1000,7 +1000,7 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
unsigned long flags;
spin_lock_irqsave(&udc->lock, flags);
udc->selfpowered = (is_on != 0);
gadget->is_selfpowered = (is_on != 0);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
@ -1149,7 +1149,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
*/
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_GET_STATUS:
tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
tmp = (udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED);
if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
PACKET("get device status\n");
@ -1653,7 +1653,7 @@ static int at91_start(struct usb_gadget *gadget,
udc->driver = driver;
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
udc->enabled = 1;
udc->selfpowered = 1;
udc->gadget.is_selfpowered = 1;
return 0;
}

View file

@ -122,7 +122,6 @@ struct at91_udc {
unsigned req_pending:1;
unsigned wait_for_addr_ack:1;
unsigned wait_for_config_ack:1;
unsigned selfpowered:1;
unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;

View file

@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/clk/at91_pmc.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@ -315,6 +316,17 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
}
#endif
static inline u32 usba_int_enb_get(struct usba_udc *udc)
{
return udc->int_enb_cache;
}
static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
{
usba_writel(udc, INT_ENB, val);
udc->int_enb_cache = val;
}
static int vbus_is_present(struct usba_udc *udc)
{
if (gpio_is_valid(udc->vbus_pin))
@ -324,27 +336,22 @@ static int vbus_is_present(struct usba_udc *udc)
return 1;
}
#if defined(CONFIG_ARCH_AT91SAM9RL)
#include <linux/clk/at91_pmc.h>
static void toggle_bias(int is_on)
static void toggle_bias(struct usba_udc *udc, int is_on)
{
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
if (is_on)
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
else
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
if (udc->errata && udc->errata->toggle_bias)
udc->errata->toggle_bias(udc, is_on);
}
#else
static void toggle_bias(int is_on)
static void generate_bias_pulse(struct usba_udc *udc)
{
}
if (!udc->bias_pulse_needed)
return;
#endif /* CONFIG_ARCH_AT91SAM9RL */
if (udc->errata && udc->errata->pulse_bias)
udc->errata->pulse_bias(udc);
udc->bias_pulse_needed = false;
}
static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
{
@ -601,16 +608,14 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
if (ep->can_dma) {
u32 ctrl;
usba_writel(udc, INT_ENB,
(usba_readl(udc, INT_ENB)
| USBA_BF(EPT_INT, 1 << ep->index)
| USBA_BF(DMA_INT, 1 << ep->index)));
usba_int_enb_set(udc, usba_int_enb_get(udc) |
USBA_BF(EPT_INT, 1 << ep->index) |
USBA_BF(DMA_INT, 1 << ep->index));
ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
usba_ep_writel(ep, CTL_ENB, ctrl);
} else {
usba_writel(udc, INT_ENB,
(usba_readl(udc, INT_ENB)
| USBA_BF(EPT_INT, 1 << ep->index)));
usba_int_enb_set(udc, usba_int_enb_get(udc) |
USBA_BF(EPT_INT, 1 << ep->index));
}
spin_unlock_irqrestore(&udc->lock, flags);
@ -618,7 +623,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
(unsigned long)usba_ep_readl(ep, CFG));
DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
(unsigned long)usba_readl(udc, INT_ENB));
(unsigned long)usba_int_enb_get(udc));
return 0;
}
@ -654,9 +659,8 @@ static int usba_ep_disable(struct usb_ep *_ep)
usba_dma_readl(ep, STATUS);
}
usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
usba_writel(udc, INT_ENB,
usba_readl(udc, INT_ENB)
& ~USBA_BF(EPT_INT, 1 << ep->index));
usba_int_enb_set(udc, usba_int_enb_get(udc) &
~USBA_BF(EPT_INT, 1 << ep->index));
request_complete_list(ep, &req_list, -ESHUTDOWN);
@ -985,6 +989,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
struct usba_udc *udc = to_usba_udc(gadget);
unsigned long flags;
gadget->is_selfpowered = (is_selfpowered != 0);
spin_lock_irqsave(&udc->lock, flags);
if (is_selfpowered)
udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
@ -1619,18 +1624,21 @@ static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
static irqreturn_t usba_udc_irq(int irq, void *devid)
{
struct usba_udc *udc = devid;
u32 status;
u32 status, int_enb;
u32 dma_status;
u32 ep_status;
spin_lock(&udc->lock);
status = usba_readl(udc, INT_STA);
int_enb = usba_int_enb_get(udc);
status = usba_readl(udc, INT_STA) & int_enb;
DBG(DBG_INT, "irq, status=%#08x\n", status);
if (status & USBA_DET_SUSPEND) {
toggle_bias(0);
toggle_bias(udc, 0);
usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
usba_int_enb_set(udc, int_enb | USBA_WAKE_UP);
udc->bias_pulse_needed = true;
DBG(DBG_BUS, "Suspend detected\n");
if (udc->gadget.speed != USB_SPEED_UNKNOWN
&& udc->driver && udc->driver->suspend) {
@ -1641,13 +1649,15 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
}
if (status & USBA_WAKE_UP) {
toggle_bias(1);
toggle_bias(udc, 1);
usba_writel(udc, INT_CLR, USBA_WAKE_UP);
usba_int_enb_set(udc, int_enb & ~USBA_WAKE_UP);
DBG(DBG_BUS, "Wake Up CPU detected\n");
}
if (status & USBA_END_OF_RESUME) {
usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
generate_bias_pulse(udc);
DBG(DBG_BUS, "Resume detected\n");
if (udc->gadget.speed != USB_SPEED_UNKNOWN
&& udc->driver && udc->driver->resume) {
@ -1683,6 +1693,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
struct usba_ep *ep0;
usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
generate_bias_pulse(udc);
reset_all_endpoints(udc);
if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {
@ -1708,11 +1719,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
usba_ep_writel(ep0, CTL_ENB,
USBA_EPT_ENABLE | USBA_RX_SETUP);
usba_writel(udc, INT_ENB,
(usba_readl(udc, INT_ENB)
| USBA_BF(EPT_INT, 1)
| USBA_DET_SUSPEND
| USBA_END_OF_RESUME));
usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) |
USBA_DET_SUSPEND | USBA_END_OF_RESUME);
/*
* Unclear why we hit this irregularly, e.g. in usbtest,
@ -1745,13 +1753,13 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
vbus = vbus_is_present(udc);
if (vbus != udc->vbus_prev) {
if (vbus) {
toggle_bias(1);
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
usba_int_enb_set(udc, USBA_END_OF_RESET);
} else {
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
toggle_bias(0);
toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
if (udc->driver->disconnect) {
spin_unlock(&udc->lock);
@ -1797,9 +1805,9 @@ static int atmel_usba_start(struct usb_gadget *gadget,
/* If Vbus is present, enable the controller and wait for reset */
spin_lock_irqsave(&udc->lock, flags);
if (vbus_is_present(udc) && udc->vbus_prev == 0) {
toggle_bias(1);
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
usba_int_enb_set(udc, USBA_END_OF_RESET);
}
spin_unlock_irqrestore(&udc->lock, flags);
@ -1820,7 +1828,7 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
spin_unlock_irqrestore(&udc->lock, flags);
/* This will also disable the DP pullup */
toggle_bias(0);
toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
clk_disable_unprepare(udc->hclk);
@ -1832,6 +1840,41 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
}
#ifdef CONFIG_OF
static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
{
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
if (is_on)
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
else
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
}
static void at91sam9g45_pulse_bias(struct usba_udc *udc)
{
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
}
static const struct usba_udc_errata at91sam9rl_errata = {
.toggle_bias = at91sam9rl_toggle_bias,
};
static const struct usba_udc_errata at91sam9g45_errata = {
.pulse_bias = at91sam9g45_pulse_bias,
};
static const struct of_device_id atmel_udc_dt_ids[] = {
{ .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata },
{ .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata },
{ .compatible = "atmel,sama5d3-udc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
struct usba_udc *udc)
{
@ -1839,10 +1882,17 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
const char *name;
enum of_gpio_flags flags;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct device_node *pp;
int i, ret;
struct usba_ep *eps, *ep;
match = of_match_node(atmel_udc_dt_ids, np);
if (!match)
return ERR_PTR(-EINVAL);
udc->errata = match->data;
udc->num_ep = 0;
udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
@ -2033,7 +2083,7 @@ static int usba_udc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
return ret;
}
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
clk_disable_unprepare(pclk);
@ -2042,6 +2092,8 @@ static int usba_udc_probe(struct platform_device *pdev)
else
udc->usba_ep = usba_udc_pdata(pdev, udc);
toggle_bias(udc, 0);
if (IS_ERR(udc->usba_ep))
return PTR_ERR(udc->usba_ep);
@ -2101,15 +2153,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
return 0;
}
#if defined(CONFIG_OF)
static const struct of_device_id atmel_udc_dt_ids[] = {
{ .compatible = "atmel,at91sam9rl-udc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
#endif
static struct platform_driver udc_driver = {
.remove = __exit_p(usba_udc_remove),
.driver = {

View file

@ -304,6 +304,11 @@ struct usba_request {
unsigned int mapped:1;
};
struct usba_udc_errata {
void (*toggle_bias)(struct usba_udc *udc, int is_on);
void (*pulse_bias)(struct usba_udc *udc);
};
struct usba_udc {
/* Protect hw registers from concurrent modifications */
spinlock_t lock;
@ -314,6 +319,7 @@ struct usba_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct platform_device *pdev;
const struct usba_udc_errata *errata;
int irq;
int vbus_pin;
int vbus_pin_inverted;
@ -321,12 +327,15 @@ struct usba_udc {
struct clk *pclk;
struct clk *hclk;
struct usba_ep *usba_ep;
bool bias_pulse_needed;
u16 devstatus;
u16 test_mode;
int vbus_prev;
u32 int_enb_cache;
#ifdef CONFIG_USB_GADGET_DEBUG_FS
struct dentry *debugfs_root;
struct dentry *debugfs_regs;

View file

@ -718,7 +718,7 @@ static int ep_queue(struct bdc_ep *ep, struct bdc_req *req)
struct bdc *bdc;
int ret = 0;
if (!req || !ep || !ep->usb_ep.desc)
if (!req || !ep->usb_ep.desc)
return -EINVAL;
bdc = ep->bdc;
@ -882,8 +882,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
ret = bdc_ep_set_stall(bdc, ep->ep_num);
if (ret)
dev_err(bdc->dev, "failed to %s STALL on %s\n",
value ? "set" : "clear", ep->name);
dev_err(bdc->dev, "failed to set STALL on %s\n",
ep->name);
else
ep->flags |= BDC_EP_STALL;
} else {
@ -891,8 +891,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
dev_dbg(bdc->dev, "Before Clear\n");
ret = bdc_ep_clear_stall(bdc, ep->ep_num);
if (ret)
dev_err(bdc->dev, "failed to %s STALL on %s\n",
value ? "set" : "clear", ep->name);
dev_err(bdc->dev, "failed to clear STALL on %s\n",
ep->name);
else
ep->flags &= ~BDC_EP_STALL;
dev_dbg(bdc->dev, "After Clear\n");

View file

@ -454,6 +454,7 @@ static int bdc_udc_set_selfpowered(struct usb_gadget *gadget,
unsigned long flags;
dev_dbg(bdc->dev, "%s()\n", __func__);
gadget->is_selfpowered = (is_self != 0);
spin_lock_irqsave(&bdc->lock, flags);
if (!is_self)
bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;

View file

@ -802,6 +802,7 @@ static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
{
struct dummy *dum;
_gadget->is_selfpowered = (value != 0);
dum = gadget_to_dummy_hcd(_gadget)->dum;
if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);

View file

@ -2630,7 +2630,7 @@ static int qe_udc_remove(struct platform_device *ofdev)
struct qe_udc *udc = platform_get_drvdata(ofdev);
struct qe_ep *ep;
unsigned int size;
DECLARE_COMPLETION(done);
DECLARE_COMPLETION_ONSTACK(done);
usb_del_gadget_udc(&udc->gadget);

View file

@ -1337,7 +1337,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
/* Get device status */
tmp = 1 << USB_DEVICE_SELF_POWERED;
tmp = udc->gadget.is_selfpowered;
tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
/* Get interface status */
@ -1948,6 +1948,7 @@ static int fsl_udc_start(struct usb_gadget *g,
/* hook up the driver */
udc_controller->driver = driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
g->is_selfpowered = 1;
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
/* Suspend the controller until OTG enable it */
@ -2529,7 +2530,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
DECLARE_COMPLETION(done);
DECLARE_COMPLETION_ONSTACK(done);
if (!udc_controller)
return -ENODEV;

View file

@ -191,7 +191,6 @@ struct lpc32xx_udc {
bool enabled;
bool clocked;
bool suspended;
bool selfpowered;
int ep0state;
atomic_t enabled_ep_cnt;
wait_queue_head_t ep_disable_wait_queue;
@ -547,7 +546,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
udc->vbus ? "present" : "off",
udc->enabled ? (udc->vbus ? "active" : "enabled") :
"disabled",
udc->selfpowered ? "self" : "VBUS",
udc->gadget.is_selfpowered ? "self" : "VBUS",
udc->suspended ? ", suspended" : "",
udc->driver ? udc->driver->driver.name : "(none)");
@ -2212,7 +2211,7 @@ static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
break; /* Not supported */
case USB_RECIP_DEVICE:
ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
ep0buff = udc->gadget.is_selfpowered;
if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
break;
@ -2498,10 +2497,7 @@ static int lpc32xx_wakeup(struct usb_gadget *gadget)
static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
{
struct lpc32xx_udc *udc = to_udc(gadget);
/* Always self-powered */
udc->selfpowered = (is_on != 0);
gadget->is_selfpowered = (is_on != 0);
return 0;
}
@ -2946,7 +2942,7 @@ static int lpc32xx_start(struct usb_gadget *gadget,
udc->driver = driver;
udc->gadget.dev.of_node = udc->dev->of_node;
udc->enabled = 1;
udc->selfpowered = 1;
udc->gadget.is_selfpowered = 1;
udc->vbus = 0;
/* Force VBUS process once to check for cable insertion */

View file

@ -1378,9 +1378,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
}
}
/* pullup is always on */
mv_udc_pullup(&udc->gadget, 1);
/* When boot with cable attached, there will be no vbus irq occurred */
if (udc->qwork)
queue_work(udc->qwork, &udc->vbus_work);

View file

@ -1132,13 +1132,10 @@ net2272_wakeup(struct usb_gadget *_gadget)
static int
net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
{
struct net2272 *dev;
if (!_gadget)
return -ENODEV;
dev = container_of(_gadget, struct net2272, gadget);
dev->is_selfpowered = value;
_gadget->is_selfpowered = (value != 0);
return 0;
}
@ -1844,7 +1841,7 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
case USB_RECIP_DEVICE:
if (u.r.wLength > 2)
goto do_stall;
if (dev->is_selfpowered)
if (dev->gadget.is_selfpowered)
status = (1 << USB_DEVICE_SELF_POWERED);
/* don't bother with a request object! */

View file

@ -458,7 +458,6 @@ struct net2272 {
struct usb_gadget_driver *driver;
unsigned protocol_stall:1,
softconnect:1,
is_selfpowered:1,
wakeup:1,
dma_eot_polarity:1,
dma_dack_polarity:1,

View file

@ -12,11 +12,7 @@
* the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers
* as well as Gadget Zero and Gadgetfs.
*
* DMA is enabled by default. Drivers using transfer queues might use
* DMA chaining to remove IRQ latencies between transfers. (Except when
* short OUT transfers happen.) Drivers can use the req->no_interrupt
* hint to completely eliminate some IRQs, if a later IRQ is guaranteed
* and DMA chaining is enabled.
* DMA is enabled by default.
*
* MSI is enabled by default. The legacy IRQ is used if MSI couldn't
* be enabled.
@ -84,23 +80,6 @@ static const char *const ep_name[] = {
"ep-e", "ep-f", "ep-g", "ep-h",
};
/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
* use_dma_chaining -- dma descriptor queueing gives even more irq reduction
*
* The net2280 DMA engines are not tightly integrated with their FIFOs;
* not all cases are (yet) handled well in this driver or the silicon.
* Some gadget drivers work better with the dma support here than others.
* These two parameters let you use PIO or more aggressive DMA.
*/
static bool use_dma = true;
static bool use_dma_chaining;
static bool use_msi = true;
/* "modprobe net2280 use_dma=n" etc */
module_param(use_dma, bool, 0444);
module_param(use_dma_chaining, bool, 0444);
module_param(use_msi, bool, 0444);
/* mode 0 == ep-{a,b,c,d} 1K fifo each
* mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
* mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
@ -120,11 +99,6 @@ static bool enable_suspend;
/* "modprobe net2280 enable_suspend=1" etc */
module_param(enable_suspend, bool, 0444);
/* force full-speed operation */
static bool full_speed;
module_param(full_speed, bool, 0444);
MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!");
#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
static char *type_string(u8 bmAttributes)
@ -202,15 +176,6 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
/* set speed-dependent max packet; may kick in high bandwidth */
set_max_speed(ep, max);
/* FIFO lines can't go to different packets. PIO is ok, so
* use it instead of troublesome (non-bulk) multi-packet DMA.
*/
if (ep->dma && (max % 4) != 0 && use_dma_chaining) {
ep_dbg(ep->dev, "%s, no dma for maxpacket %d\n",
ep->ep.name, ep->ep.maxpacket);
ep->dma = NULL;
}
/* set type, direction, address; reset fifo counters */
writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
@ -478,7 +443,7 @@ static int net2280_disable(struct usb_ep *_ep)
/* synch memory views with the device */
(void)readl(&ep->cfg->ep_cfg);
if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
if (!ep->dma && ep->num >= 1 && ep->num <= 4)
ep->dma = &ep->dev->dma[ep->num - 1];
spin_unlock_irqrestore(&ep->dev->lock, flags);
@ -610,9 +575,15 @@ static void out_flush(struct net2280_ep *ep)
u32 __iomem *statp;
u32 tmp;
ASSERT_OUT_NAKING(ep);
statp = &ep->regs->ep_stat;
tmp = readl(statp);
if (tmp & BIT(NAK_OUT_PACKETS)) {
ep_dbg(ep->dev, "%s %s %08x !NAK\n",
ep->ep.name, __func__, tmp);
writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
}
writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
BIT(DATA_PACKET_RECEIVED_INTERRUPT),
statp);
@ -747,8 +718,7 @@ static void fill_dma_desc(struct net2280_ep *ep,
req->valid = valid;
if (valid)
dmacount |= BIT(VALID_BIT);
if (likely(!req->req.no_interrupt || !use_dma_chaining))
dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
/* td->dmadesc = previously set by caller */
td->dmaaddr = cpu_to_le32 (req->req.dma);
@ -862,27 +832,11 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req)
req->td->dmadesc = cpu_to_le32 (ep->td_dma);
fill_dma_desc(ep, req, 1);
if (!use_dma_chaining)
req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
start_queue(ep, tmp, req->td_dma);
}
static inline void resume_dma(struct net2280_ep *ep)
{
writel(readl(&ep->dma->dmactl) | BIT(DMA_ENABLE), &ep->dma->dmactl);
ep->dma_started = true;
}
static inline void ep_stop_dma(struct net2280_ep *ep)
{
writel(readl(&ep->dma->dmactl) & ~BIT(DMA_ENABLE), &ep->dma->dmactl);
spin_stop_dma(ep->dma);
ep->dma_started = false;
}
static inline void
queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid)
{
@ -973,10 +927,8 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return ret;
}
#if 0
ep_vdbg(dev, "%s queue req %p, len %d buf %p\n",
_ep->name, _req, _req->length, _req->buf);
#endif
spin_lock_irqsave(&dev->lock, flags);
@ -984,24 +936,12 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
_req->actual = 0;
/* kickstart this i/o queue? */
if (list_empty(&ep->queue) && !ep->stopped) {
/* DMA request while EP halted */
if (ep->dma &&
(readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) &&
(dev->quirks & PLX_SUPERSPEED)) {
int valid = 1;
if (ep->is_in) {
int expect;
expect = likely(req->req.zero ||
((req->req.length %
ep->ep.maxpacket) != 0));
if (expect != ep->in_fifo_validate)
valid = 0;
}
queue_dma(ep, req, valid);
}
if (list_empty(&ep->queue) && !ep->stopped &&
!((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
(readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
/* use DMA if the endpoint supports it, else pio */
else if (ep->dma)
if (ep->dma)
start_dma(ep, req);
else {
/* maybe there's no control data, just status ack */
@ -1084,8 +1024,6 @@ dma_done(struct net2280_ep *ep, struct net2280_request *req, u32 dmacount,
done(ep, req, status);
}
static void restart_dma(struct net2280_ep *ep);
static void scan_dma_completions(struct net2280_ep *ep)
{
/* only look at descriptors that were "naturally" retired,
@ -1117,9 +1055,8 @@ static void scan_dma_completions(struct net2280_ep *ep)
dma_done(ep, req, tmp, 0);
break;
} else if (!ep->is_in &&
(req->req.length % ep->ep.maxpacket) != 0) {
if (ep->dev->quirks & PLX_SUPERSPEED)
return dma_done(ep, req, tmp, 0);
(req->req.length % ep->ep.maxpacket) &&
!(ep->dev->quirks & PLX_SUPERSPEED)) {
tmp = readl(&ep->regs->ep_stat);
/* AVOID TROUBLE HERE by not issuing short reads from
@ -1150,67 +1087,15 @@ static void scan_dma_completions(struct net2280_ep *ep)
static void restart_dma(struct net2280_ep *ep)
{
struct net2280_request *req;
u32 dmactl = dmactl_default;
if (ep->stopped)
return;
req = list_entry(ep->queue.next, struct net2280_request, queue);
if (!use_dma_chaining) {
start_dma(ep, req);
return;
}
/* the 2280 will be processing the queue unless queue hiccups after
* the previous transfer:
* IN: wanted automagic zlp, head doesn't (or vice versa)
* DMA_FIFO_VALIDATE doesn't init from dma descriptors.
* OUT: was "usb-short", we must restart.
*/
if (ep->is_in && !req->valid) {
struct net2280_request *entry, *prev = NULL;
int reqmode, done = 0;
ep_dbg(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
ep->in_fifo_validate = likely(req->req.zero ||
(req->req.length % ep->ep.maxpacket) != 0);
if (ep->in_fifo_validate)
dmactl |= BIT(DMA_FIFO_VALIDATE);
list_for_each_entry(entry, &ep->queue, queue) {
__le32 dmacount;
if (entry == req)
continue;
dmacount = entry->td->dmacount;
if (!done) {
reqmode = likely(entry->req.zero ||
(entry->req.length % ep->ep.maxpacket));
if (reqmode == ep->in_fifo_validate) {
entry->valid = 1;
dmacount |= valid_bit;
entry->td->dmacount = dmacount;
prev = entry;
continue;
} else {
/* force a hiccup */
prev->td->dmacount |= dma_done_ie;
done = 1;
}
}
/* walk the rest of the queue so unlinks behave */
entry->valid = 0;
dmacount &= ~valid_bit;
entry->td->dmacount = dmacount;
prev = entry;
}
}
writel(0, &ep->dma->dmactl);
start_queue(ep, dmactl, req->td_dma);
start_dma(ep, req);
}
static void abort_dma_228x(struct net2280_ep *ep)
static void abort_dma(struct net2280_ep *ep)
{
/* abort the current transfer */
if (likely(!list_empty(&ep->queue))) {
@ -1222,19 +1107,6 @@ static void abort_dma_228x(struct net2280_ep *ep)
scan_dma_completions(ep);
}
static void abort_dma_338x(struct net2280_ep *ep)
{
writel(BIT(DMA_ABORT), &ep->dma->dmastat);
spin_stop_dma(ep->dma);
}
static void abort_dma(struct net2280_ep *ep)
{
if (ep->dev->quirks & PLX_LEGACY)
return abort_dma_228x(ep);
return abort_dma_338x(ep);
}
/* dequeue ALL requests */
static void nuke(struct net2280_ep *ep)
{
@ -1306,25 +1178,6 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req)
done(ep, req, -ECONNRESET);
}
req = NULL;
/* patch up hardware chaining data */
} else if (ep->dma && use_dma_chaining) {
if (req->queue.prev == ep->queue.next) {
writel(le32_to_cpu(req->td->dmadesc),
&ep->dma->dmadesc);
if (req->td->dmacount & dma_done_ie)
writel(readl(&ep->dma->dmacount) |
le32_to_cpu(dma_done_ie),
&ep->dma->dmacount);
} else {
struct net2280_request *prev;
prev = list_entry(req->queue.prev,
struct net2280_request, queue);
prev->td->dmadesc = req->td->dmadesc;
if (req->td->dmacount & dma_done_ie)
prev->td->dmacount |= dma_done_ie;
}
}
if (req)
@ -1512,10 +1365,10 @@ static int net2280_set_selfpowered(struct usb_gadget *_gadget, int value)
tmp = readl(&dev->usb->usbctl);
if (value) {
tmp |= BIT(SELF_POWERED_STATUS);
dev->selfpowered = 1;
_gadget->is_selfpowered = 1;
} else {
tmp &= ~BIT(SELF_POWERED_STATUS);
dev->selfpowered = 0;
_gadget->is_selfpowered = 0;
}
writel(tmp, &dev->usb->usbctl);
spin_unlock_irqrestore(&dev->lock, flags);
@ -1604,14 +1457,11 @@ static ssize_t registers_show(struct device *_dev,
/* Main Control Registers */
t = scnprintf(next, size, "%s version " DRIVER_VERSION
", chiprev %04x, dma %s\n\n"
", chiprev %04x\n\n"
"devinit %03x fifoctl %08x gadget '%s'\n"
"pci irqenb0 %02x irqenb1 %08x "
"irqstat0 %04x irqstat1 %08x\n",
driver_name, dev->chiprev,
use_dma
? (use_dma_chaining ? "chaining" : "enabled")
: "disabled",
readl(&dev->regs->devinit),
readl(&dev->regs->fifoctl),
s,
@ -1913,76 +1763,73 @@ static void defect7374_disable_data_eps(struct net2280 *dev)
static void defect7374_enable_data_eps_zero(struct net2280 *dev)
{
u32 tmp = 0, tmp_reg;
u32 fsmvalue, scratch;
u32 scratch;
int i;
unsigned char ep_sel;
scratch = get_idx_reg(dev->regs, SCRATCH);
fsmvalue = scratch & (0xf << DEFECT7374_FSM_FIELD);
WARN_ON((scratch & (0xf << DEFECT7374_FSM_FIELD))
== DEFECT7374_FSM_SS_CONTROL_READ);
scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
/*See if firmware needs to set up for workaround*/
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
ep_warn(dev, "Operate Defect 7374 workaround soft this time");
ep_warn(dev, "It will operate on cold-reboot and SS connect");
ep_warn(dev, "Operate Defect 7374 workaround soft this time");
ep_warn(dev, "It will operate on cold-reboot and SS connect");
/*GPEPs:*/
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
(2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
((dev->enhanced_mode) ?
BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
BIT(IN_ENDPOINT_ENABLE));
/*GPEPs:*/
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
(2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
((dev->enhanced_mode) ?
BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
BIT(IN_ENDPOINT_ENABLE));
for (i = 1; i < 5; i++)
writel(tmp, &dev->ep[i].cfg->ep_cfg);
for (i = 1; i < 5; i++)
writel(tmp, &dev->ep[i].cfg->ep_cfg);
/* CSRIN, PCIIN, STATIN, RCIN*/
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
writel(tmp, &dev->dep[1].dep_cfg);
writel(tmp, &dev->dep[3].dep_cfg);
writel(tmp, &dev->dep[4].dep_cfg);
writel(tmp, &dev->dep[5].dep_cfg);
/* CSRIN, PCIIN, STATIN, RCIN*/
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
writel(tmp, &dev->dep[1].dep_cfg);
writel(tmp, &dev->dep[3].dep_cfg);
writel(tmp, &dev->dep[4].dep_cfg);
writel(tmp, &dev->dep[5].dep_cfg);
/*Implemented for development and debug.
* Can be refined/tuned later.*/
for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
/* Select an endpoint for subsequent operations: */
tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
writel(((tmp_reg & ~0x1f) | ep_sel),
&dev->plregs->pl_ep_ctrl);
/*Implemented for development and debug.
* Can be refined/tuned later.*/
for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
/* Select an endpoint for subsequent operations: */
tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
writel(((tmp_reg & ~0x1f) | ep_sel),
&dev->plregs->pl_ep_ctrl);
if (ep_sel == 1) {
tmp =
(readl(&dev->plregs->pl_ep_ctrl) |
BIT(CLEAR_ACK_ERROR_CODE) | 0);
writel(tmp, &dev->plregs->pl_ep_ctrl);
continue;
}
if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
ep_sel == 18 || ep_sel == 20)
continue;
tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
writel(tmp, &dev->plregs->pl_ep_cfg_4);
tmp = readl(&dev->plregs->pl_ep_ctrl) &
~BIT(EP_INITIALIZED);
if (ep_sel == 1) {
tmp =
(readl(&dev->plregs->pl_ep_ctrl) |
BIT(CLEAR_ACK_ERROR_CODE) | 0);
writel(tmp, &dev->plregs->pl_ep_ctrl);
continue;
}
/* Set FSM to focus on the first Control Read:
* - Tip: Connection speed is known upon the first
* setup request.*/
scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
set_idx_reg(dev->regs, SCRATCH, scratch);
if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
ep_sel == 18 || ep_sel == 20)
continue;
tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
writel(tmp, &dev->plregs->pl_ep_cfg_4);
tmp = readl(&dev->plregs->pl_ep_ctrl) &
~BIT(EP_INITIALIZED);
writel(tmp, &dev->plregs->pl_ep_ctrl);
} else{
ep_warn(dev, "Defect 7374 workaround soft will NOT operate");
ep_warn(dev, "It will operate on cold-reboot and SS connect");
}
/* Set FSM to focus on the first Control Read:
* - Tip: Connection speed is known upon the first
* setup request.*/
scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
set_idx_reg(dev->regs, SCRATCH, scratch);
}
/* keeping it simple:
@ -2033,21 +1880,13 @@ static void usb_reset_228x(struct net2280 *dev)
static void usb_reset_338x(struct net2280 *dev)
{
u32 tmp;
u32 fsmvalue;
dev->gadget.speed = USB_SPEED_UNKNOWN;
(void)readl(&dev->usb->usbctl);
net2280_led_init(dev);
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
/* See if firmware needs to set up for workaround: */
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
ep_info(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__,
fsmvalue);
} else {
if (dev->bug7734_patched) {
/* disable automatic responses, and irqs */
writel(0, &dev->usb->stdrsp);
writel(0, &dev->regs->pciirqenb0);
@ -2064,7 +1903,7 @@ static void usb_reset_338x(struct net2280 *dev)
writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1);
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
if (dev->bug7734_patched) {
/* reset, and enable pci */
tmp = readl(&dev->regs->devinit) |
BIT(PCI_ENABLE) |
@ -2093,10 +1932,6 @@ static void usb_reset(struct net2280 *dev)
static void usb_reinit_228x(struct net2280 *dev)
{
u32 tmp;
int init_dma;
/* use_dma changes are ignored till next device re-init */
init_dma = use_dma;
/* basic endpoint init */
for (tmp = 0; tmp < 7; tmp++) {
@ -2108,8 +1943,7 @@ static void usb_reinit_228x(struct net2280 *dev)
if (tmp > 0 && tmp <= 4) {
ep->fifo_size = 1024;
if (init_dma)
ep->dma = &dev->dma[tmp - 1];
ep->dma = &dev->dma[tmp - 1];
} else
ep->fifo_size = 64;
ep->regs = &dev->epregs[tmp];
@ -2133,17 +1967,12 @@ static void usb_reinit_228x(struct net2280 *dev)
static void usb_reinit_338x(struct net2280 *dev)
{
int init_dma;
int i;
u32 tmp, val;
u32 fsmvalue;
static const u32 ne[9] = { 0, 1, 2, 3, 4, 1, 2, 3, 4 };
static const u32 ep_reg_addr[9] = { 0x00, 0xC0, 0x00, 0xC0, 0x00,
0x00, 0xC0, 0x00, 0xC0 };
/* use_dma changes are ignored till next device re-init */
init_dma = use_dma;
/* basic endpoint init */
for (i = 0; i < dev->n_ep; i++) {
struct net2280_ep *ep = &dev->ep[i];
@ -2152,7 +1981,7 @@ static void usb_reinit_338x(struct net2280 *dev)
ep->dev = dev;
ep->num = i;
if (i > 0 && i <= 4 && init_dma)
if (i > 0 && i <= 4)
ep->dma = &dev->dma[i - 1];
if (dev->enhanced_mode) {
@ -2177,14 +2006,7 @@ static void usb_reinit_338x(struct net2280 *dev)
dev->ep[0].stopped = 0;
/* Link layer set up */
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
/* See if driver needs to set up for workaround: */
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
ep_info(dev, "%s: Defect 7374 FsmValue %08x\n",
__func__, fsmvalue);
else {
if (dev->bug7734_patched) {
tmp = readl(&dev->usb_ext->usbctl2) &
~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE));
writel(tmp, &dev->usb_ext->usbctl2);
@ -2291,15 +2113,8 @@ static void ep0_start_228x(struct net2280 *dev)
static void ep0_start_338x(struct net2280 *dev)
{
u32 fsmvalue;
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
ep_info(dev, "%s: Defect 7374 FsmValue %08x\n", __func__,
fsmvalue);
else
if (dev->bug7734_patched)
writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) |
BIT(SET_EP_HIDE_STATUS_PHASE),
&dev->epregs[0].ep_rsp);
@ -2382,16 +2197,12 @@ static int net2280_start(struct usb_gadget *_gadget,
if (retval)
goto err_func;
/* Enable force-full-speed testing mode, if desired */
if (full_speed && (dev->quirks & PLX_LEGACY))
writel(BIT(FORCE_FULL_SPEED_MODE), &dev->usb->xcvrdiag);
/* ... then enable host detection and ep0; and we're ready
/* enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
*/
net2280_led_active(dev, 1);
if (dev->quirks & PLX_SUPERSPEED)
if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
defect7374_enable_data_eps_zero(dev);
ep0_start(dev);
@ -2444,10 +2255,6 @@ static int net2280_stop(struct usb_gadget *_gadget)
net2280_led_active(dev, 0);
/* Disable full-speed test mode */
if (dev->quirks & PLX_LEGACY)
writel(0, &dev->usb->xcvrdiag);
device_remove_file(&dev->pdev->dev, &dev_attr_function);
device_remove_file(&dev->pdev->dev, &dev_attr_queues);
@ -2478,10 +2285,10 @@ static void handle_ep_small(struct net2280_ep *ep)
/* ack all, and handle what we care about */
t = readl(&ep->regs->ep_stat);
ep->irqs++;
#if 0
ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n",
ep->ep.name, t, req ? &req->req : 0);
#endif
ep->ep.name, t, req ? &req->req : NULL);
if (!ep->is_in || (ep->dev->quirks & PLX_2280))
writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat);
else
@ -2717,6 +2524,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
* run after the next USB connection.
*/
scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
dev->bug7734_patched = 1;
goto restore_data_eps;
}
@ -2730,6 +2538,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
if ((state >= (ACK_GOOD_NORMAL << STATE)) &&
(state <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE))) {
scratch |= DEFECT7374_FSM_SS_CONTROL_READ;
dev->bug7734_patched = 1;
break;
}
@ -2766,80 +2575,19 @@ restore_data_eps:
return;
}
static void ep_stall(struct net2280_ep *ep, int stall)
static void ep_clear_seqnum(struct net2280_ep *ep)
{
struct net2280 *dev = ep->dev;
u32 val;
static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 };
if (stall) {
writel(BIT(SET_ENDPOINT_HALT) |
/* BIT(SET_NAK_PACKETS) | */
BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE),
&ep->regs->ep_rsp);
ep->is_halt = 1;
} else {
if (dev->gadget.speed == USB_SPEED_SUPER) {
/*
* Workaround for SS SeqNum not cleared via
* Endpoint Halt (Clear) bit. select endpoint
*/
val = readl(&dev->plregs->pl_ep_ctrl);
val = (val & ~0x1f) | ep_pl[ep->num];
writel(val, &dev->plregs->pl_ep_ctrl);
val = readl(&dev->plregs->pl_ep_ctrl) & ~0x1f;
val |= ep_pl[ep->num];
writel(val, &dev->plregs->pl_ep_ctrl);
val |= BIT(SEQUENCE_NUMBER_RESET);
writel(val, &dev->plregs->pl_ep_ctrl);
val |= BIT(SEQUENCE_NUMBER_RESET);
writel(val, &dev->plregs->pl_ep_ctrl);
}
val = readl(&ep->regs->ep_rsp);
val |= BIT(CLEAR_ENDPOINT_HALT) |
BIT(CLEAR_ENDPOINT_TOGGLE);
writel(val,
/* | BIT(CLEAR_NAK_PACKETS),*/
&ep->regs->ep_rsp);
ep->is_halt = 0;
val = readl(&ep->regs->ep_rsp);
}
}
static void ep_stdrsp(struct net2280_ep *ep, int value, int wedged)
{
/* set/clear, then synch memory views with the device */
if (value) {
ep->stopped = 1;
if (ep->num == 0)
ep->dev->protocol_stall = 1;
else {
if (ep->dma)
ep_stop_dma(ep);
ep_stall(ep, true);
}
if (wedged)
ep->wedged = 1;
} else {
ep->stopped = 0;
ep->wedged = 0;
ep_stall(ep, false);
/* Flush the queue */
if (!list_empty(&ep->queue)) {
struct net2280_request *req =
list_entry(ep->queue.next, struct net2280_request,
queue);
if (ep->dma)
resume_dma(ep);
else {
if (ep->is_in)
write_fifo(ep, &req->req);
else {
if (read_fifo(ep, req))
done(ep, req, 0);
}
}
}
}
return;
}
static void handle_stat0_irqs_superspeed(struct net2280 *dev,
@ -2863,7 +2611,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
switch (r.bRequestType) {
case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
status = dev->wakeup_enable ? 0x02 : 0x00;
if (dev->selfpowered)
if (dev->gadget.is_selfpowered)
status |= BIT(0);
status |= (dev->u1_enable << 2 | dev->u2_enable << 3 |
dev->ltm_enable << 4);
@ -2940,7 +2688,12 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
if (w_value != USB_ENDPOINT_HALT)
goto do_stall3;
ep_vdbg(dev, "%s clear halt\n", e->ep.name);
ep_stall(e, false);
/*
* Workaround for SS SeqNum not cleared via
* Endpoint Halt (Clear) bit. select endpoint
*/
ep_clear_seqnum(e);
clear_halt(e);
if (!list_empty(&e->queue) && e->td_dma)
restart_dma(e);
allow_status(ep);
@ -2998,7 +2751,14 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
e = get_ep_by_addr(dev, w_index);
if (!e || (w_value != USB_ENDPOINT_HALT))
goto do_stall3;
ep_stdrsp(e, true, false);
ep->stopped = 1;
if (ep->num == 0)
ep->dev->protocol_stall = 1;
else {
if (ep->dma)
abort_dma(ep);
set_halt(ep);
}
allow_status_338x(ep);
break;
@ -3026,7 +2786,7 @@ do_stall3:
r.bRequestType, r.bRequest, tmp);
dev->protocol_stall = 1;
/* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */
ep_stall(ep, true);
set_halt(ep);
}
next_endpoints3:
@ -3091,9 +2851,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
}
ep->stopped = 0;
dev->protocol_stall = 0;
if (dev->quirks & PLX_SUPERSPEED)
ep->is_halt = 0;
else{
if (!(dev->quirks & PLX_SUPERSPEED)) {
if (ep->dev->quirks & PLX_2280)
tmp = BIT(FIFO_OVERFLOW) |
BIT(FIFO_UNDERFLOW);
@ -3120,7 +2878,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
cpu_to_le32s(&u.raw[0]);
cpu_to_le32s(&u.raw[1]);
if (dev->quirks & PLX_SUPERSPEED)
if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
defect7374_workaround(dev, u.r);
tmp = 0;
@ -3423,17 +3181,12 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
continue;
}
/* chaining should stop on abort, short OUT from fifo,
* or (stat0 codepath) short OUT transfer.
*/
if (!use_dma_chaining) {
if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
ep_dbg(ep->dev, "%s no xact done? %08x\n",
ep->ep.name, tmp);
continue;
}
stop_dma(ep->dma);
if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
ep_dbg(ep->dev, "%s no xact done? %08x\n",
ep->ep.name, tmp);
continue;
}
stop_dma(ep->dma);
/* OUT transfers terminate when the data from the
* host is in our memory. Process whatever's done.
@ -3448,30 +3201,9 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
scan_dma_completions(ep);
/* disable dma on inactive queues; else maybe restart */
if (list_empty(&ep->queue)) {
if (use_dma_chaining)
stop_dma(ep->dma);
} else {
if (!list_empty(&ep->queue)) {
tmp = readl(&dma->dmactl);
if (!use_dma_chaining || (tmp & BIT(DMA_ENABLE)) == 0)
restart_dma(ep);
else if (ep->is_in && use_dma_chaining) {
struct net2280_request *req;
__le32 dmacount;
/* the descriptor at the head of the chain
* may still have VALID_BIT clear; that's
* used to trigger changing DMA_FIFO_VALIDATE
* (affects automagic zlp writes).
*/
req = list_entry(ep->queue.next,
struct net2280_request, queue);
dmacount = req->td->dmacount;
dmacount &= cpu_to_le32(BIT(VALID_BIT) |
DMA_BYTE_COUNT_MASK);
if (dmacount && (dmacount & valid_bit) == 0)
restart_dma(ep);
}
restart_dma(ep);
}
ep->irqs++;
}
@ -3556,7 +3288,7 @@ static void net2280_remove(struct pci_dev *pdev)
}
if (dev->got_irq)
free_irq(pdev->irq, dev);
if (use_msi && dev->quirks & PLX_SUPERSPEED)
if (dev->quirks & PLX_SUPERSPEED)
pci_disable_msi(pdev);
if (dev->regs)
iounmap(dev->regs);
@ -3581,9 +3313,6 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
void __iomem *base = NULL;
int retval, i;
if (!use_dma)
use_dma_chaining = 0;
/* alloc, and start init */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
@ -3663,9 +3392,12 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
/* See if firmware needs to set up for workaround: */
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ)
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
dev->bug7734_patched = 1;
writel(0, &dev->usb->usbctl);
} else{
} else
dev->bug7734_patched = 0;
} else {
dev->enhanced_mode = 0;
dev->n_ep = 7;
/* put into initial config, link up all endpoints */
@ -3682,7 +3414,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto done;
}
if (use_msi && (dev->quirks & PLX_SUPERSPEED))
if (dev->quirks & PLX_SUPERSPEED)
if (pci_enable_msi(pdev))
ep_err(dev, "Failed to enable MSI mode\n");
@ -3741,9 +3473,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ep_info(dev, "%s\n", driver_desc);
ep_info(dev, "irq %d, pci mem %p, chip rev %04x\n",
pdev->irq, base, dev->chiprev);
ep_info(dev, "version: " DRIVER_VERSION "; dma %s %s\n",
use_dma ? (use_dma_chaining ? "chaining" : "enabled")
: "disabled",
ep_info(dev, "version: " DRIVER_VERSION "; %s\n",
dev->enhanced_mode ? "enhanced mode" : "legacy mode");
retval = device_create_file(&pdev->dev, &dev_attr_registers);
if (retval)
@ -3776,9 +3506,6 @@ static void net2280_shutdown(struct pci_dev *pdev)
/* disable the pullup so the host will think we're gone */
writel(0, &dev->usb->usbctl);
/* Disable full-speed test mode */
if (dev->quirks & PLX_LEGACY)
writel(0, &dev->usb->xcvrdiag);
}

View file

@ -100,7 +100,6 @@ struct net2280_ep {
dma_addr_t td_dma; /* of dummy */
struct net2280 *dev;
unsigned long irqs;
unsigned is_halt:1, dma_started:1;
/* analogous to a host-side qh */
struct list_head queue;
@ -126,7 +125,7 @@ static inline void allow_status(struct net2280_ep *ep)
ep->stopped = 1;
}
static void allow_status_338x(struct net2280_ep *ep)
static inline void allow_status_338x(struct net2280_ep *ep)
{
/*
* Control Status Phase Handshake was set by the chip when the setup
@ -165,8 +164,8 @@ struct net2280 {
u2_enable:1,
ltm_enable:1,
wakeup_enable:1,
selfpowered:1,
addressed_state:1;
addressed_state:1,
bug7734_patched:1;
u16 chiprev;
int enhanced_mode;
int n_ep;
@ -356,23 +355,6 @@ static inline void start_out_naking(struct net2280_ep *ep)
readl(&ep->regs->ep_rsp);
}
#ifdef DEBUG
static inline void assert_out_naking(struct net2280_ep *ep, const char *where)
{
u32 tmp = readl(&ep->regs->ep_stat);
if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) {
ep_dbg(ep->dev, "%s %s %08x !NAK\n",
ep->ep.name, where, tmp);
writel(BIT(SET_NAK_OUT_PACKETS),
&ep->regs->ep_rsp);
}
}
#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
#else
#define ASSERT_OUT_NAKING(ep) do {} while (0)
#endif
static inline void stop_out_naking(struct net2280_ep *ep)
{
u32 tmp;

View file

@ -1171,6 +1171,7 @@ omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
unsigned long flags;
u16 syscon1;
gadget->is_selfpowered = (is_selfpowered != 0);
udc = container_of(gadget, struct omap_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
syscon1 = omap_readw(UDC_SYSCON1);

View file

@ -1161,6 +1161,7 @@ static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value)
if (!gadget)
return -EINVAL;
gadget->is_selfpowered = (value != 0);
dev = container_of(gadget, struct pch_udc_dev, gadget);
if (value)
pch_udc_set_selfpowered(dev);

View file

@ -1272,7 +1272,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
goto bind_fail;
}
pullup(dev);
dump_state(dev);
return 0;
bind_fail:
@ -1339,7 +1338,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g)
local_irq_disable();
dev->pullup = 0;
pullup(dev);
stop_activity(dev, NULL);
local_irq_enable();

View file

@ -1809,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */
udc->driver = driver;
dplus_pullup(udc, 1);
if (!IS_ERR_OR_NULL(udc->transceiver)) {
retval = otg_set_peripheral(udc->transceiver->otg,
@ -1862,7 +1861,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g)
stop_activity(udc, NULL);
udc_disable(udc);
dplus_pullup(udc, 0);
udc->driver = NULL;

View file

@ -1803,6 +1803,7 @@ static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
{
struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
gadget->is_selfpowered = (is_self != 0);
if (is_self)
r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
else

View file

@ -238,14 +238,6 @@ static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
S3C2410_UDC_EP0_CSR_REG);
}
static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
{
udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
| S3C2410_UDC_EP0_CSR_SSE),
S3C2410_UDC_EP0_CSR_REG);
}
static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
{
udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
@ -291,18 +283,6 @@ static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
}
}
static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
{
unsigned i;
/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
* fifos, and pending transactions mustn't be continued in any case.
*/
for (i = 1; i < S3C2410_ENDPOINTS; i++)
s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
}
static inline int s3c2410_udc_fifo_count_out(void)
{
int tmp;
@ -1454,6 +1434,7 @@ static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value)
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
gadget->is_selfpowered = (value != 0);
if (value)
udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else

View file

@ -564,6 +564,7 @@ static USB_UDC_ATTR(is_a_peripheral);
static USB_UDC_ATTR(b_hnp_enable);
static USB_UDC_ATTR(a_hnp_support);
static USB_UDC_ATTR(a_alt_hnp_support);
static USB_UDC_ATTR(is_selfpowered);
static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr,
@ -577,6 +578,7 @@ static struct attribute *usb_udc_attrs[] = {
&dev_attr_b_hnp_enable.attr,
&dev_attr_a_hnp_support.attr,
&dev_attr_a_alt_hnp_support.attr,
&dev_attr_is_selfpowered.attr,
NULL,
};

View file

@ -331,20 +331,6 @@ config USB_ISP116X_HCD
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
config USB_ISP1760_HCD
tristate "ISP 1760 HCD support"
---help---
The ISP1760 chip is a USB 2.0 host controller.
This driver does not support isochronous transfers or OTG.
This USB controller is usually attached to a non-DMA-Master
capable bus. NXP's eval kit brings this chip on PCI card
where the chip itself is behind a PLB to simulate such
a bus.
To compile this driver as a module, choose M here: the
module will be called isp1760.
config USB_ISP1362_HCD
tristate "ISP1362 HCD support"
---help---

View file

@ -5,8 +5,6 @@
# tell define_trace.h where to find the xhci trace header
CFLAGS_xhci-trace.o := -I$(src)
isp1760-y := isp1760-hcd.o isp1760-if.o
fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
@ -69,7 +67,6 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o

View file

@ -1,208 +0,0 @@
#ifndef _ISP1760_HCD_H_
#define _ISP1760_HCD_H_
/* exports for if */
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
int irq, unsigned long irqflags,
int rst_gpio,
struct device *dev, const char *busname,
unsigned int devflags);
int init_kmem_once(void);
void deinit_kmem_cache(void);
/* EHCI capability registers */
#define HC_CAPLENGTH 0x00
#define HC_HCSPARAMS 0x04
#define HC_HCCPARAMS 0x08
/* EHCI operational registers */
#define HC_USBCMD 0x20
#define HC_USBSTS 0x24
#define HC_FRINDEX 0x2c
#define HC_CONFIGFLAG 0x60
#define HC_PORTSC1 0x64
#define HC_ISO_PTD_DONEMAP_REG 0x130
#define HC_ISO_PTD_SKIPMAP_REG 0x134
#define HC_ISO_PTD_LASTPTD_REG 0x138
#define HC_INT_PTD_DONEMAP_REG 0x140
#define HC_INT_PTD_SKIPMAP_REG 0x144
#define HC_INT_PTD_LASTPTD_REG 0x148
#define HC_ATL_PTD_DONEMAP_REG 0x150
#define HC_ATL_PTD_SKIPMAP_REG 0x154
#define HC_ATL_PTD_LASTPTD_REG 0x158
/* Configuration Register */
#define HC_HW_MODE_CTRL 0x300
#define ALL_ATX_RESET (1 << 31)
#define HW_ANA_DIGI_OC (1 << 15)
#define HW_DATA_BUS_32BIT (1 << 8)
#define HW_DACK_POL_HIGH (1 << 6)
#define HW_DREQ_POL_HIGH (1 << 5)
#define HW_INTR_HIGH_ACT (1 << 2)
#define HW_INTR_EDGE_TRIG (1 << 1)
#define HW_GLOBAL_INTR_EN (1 << 0)
#define HC_CHIP_ID_REG 0x304
#define HC_SCRATCH_REG 0x308
#define HC_RESET_REG 0x30c
#define SW_RESET_RESET_HC (1 << 1)
#define SW_RESET_RESET_ALL (1 << 0)
#define HC_BUFFER_STATUS_REG 0x334
#define ISO_BUF_FILL (1 << 2)
#define INT_BUF_FILL (1 << 1)
#define ATL_BUF_FILL (1 << 0)
#define HC_MEMORY_REG 0x33c
#define ISP_BANK(x) ((x) << 16)
#define HC_PORT1_CTRL 0x374
#define PORT1_POWER (3 << 3)
#define PORT1_INIT1 (1 << 7)
#define PORT1_INIT2 (1 << 23)
#define HW_OTG_CTRL_SET 0x374
#define HW_OTG_CTRL_CLR 0x376
/* Interrupt Register */
#define HC_INTERRUPT_REG 0x310
#define HC_INTERRUPT_ENABLE 0x314
#define HC_ISO_INT (1 << 9)
#define HC_ATL_INT (1 << 8)
#define HC_INTL_INT (1 << 7)
#define HC_EOT_INT (1 << 3)
#define HC_SOT_INT (1 << 1)
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
#define HC_ISO_IRQ_MASK_OR_REG 0x318
#define HC_INT_IRQ_MASK_OR_REG 0x31C
#define HC_ATL_IRQ_MASK_OR_REG 0x320
#define HC_ISO_IRQ_MASK_AND_REG 0x324
#define HC_INT_IRQ_MASK_AND_REG 0x328
#define HC_ATL_IRQ_MASK_AND_REG 0x32C
/* urb state*/
#define DELETE_URB (0x0008)
#define NO_TRANSFER_ACTIVE (0xffffffff)
/* Philips Proprietary Transfer Descriptor (PTD) */
typedef __u32 __bitwise __dw;
struct ptd {
__dw dw0;
__dw dw1;
__dw dw2;
__dw dw3;
__dw dw4;
__dw dw5;
__dw dw6;
__dw dw7;
};
#define PTD_OFFSET 0x0400
#define ISO_PTD_OFFSET 0x0400
#define INT_PTD_OFFSET 0x0800
#define ATL_PTD_OFFSET 0x0c00
#define PAYLOAD_OFFSET 0x1000
struct slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
unsigned long timestamp;
};
typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct isp1760_qtd *qtd);
/*
* Device flags that can vary from board to board. All of these
* indicate the most "atypical" case, so that a devflags of 0 is
* a sane default configuration.
*/
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */
/* chip memory management */
struct memory_chunk {
unsigned int start;
unsigned int size;
unsigned int free;
};
/*
* 60kb divided in:
* - 32 blocks @ 256 bytes
* - 20 blocks @ 1024 bytes
* - 4 blocks @ 8192 bytes
*/
#define BLOCK_1_NUM 32
#define BLOCK_2_NUM 20
#define BLOCK_3_NUM 4
#define BLOCK_1_SIZE 256
#define BLOCK_2_SIZE 1024
#define BLOCK_3_SIZE 8192
#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
#define PAYLOAD_AREA_SIZE 0xf000
/* ATL */
/* DW0 */
#define DW0_VALID_BIT 1
#define FROM_DW0_VALID(x) ((x) & 0x01)
#define TO_DW0_LENGTH(x) (((u32) x) << 3)
#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
#define TO_DW0_MULTI(x) (((u32) x) << 29)
#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
/* DW1 */
#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
#define DW1_TRANS_BULK ((u32) 2 << 12)
#define DW1_TRANS_INT ((u32) 3 << 12)
#define DW1_TRANS_SPLIT ((u32) 1 << 14)
#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
/* DW2 */
#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
#define TO_DW2_RL(x) ((x) << 25)
#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
/* DW3 */
#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
#define TO_DW3_NAKCOUNT(x) ((x) << 19)
#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
#define TO_DW3_CERR(x) ((x) << 23)
#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
#define TO_DW3_PING(x) ((x) << 26)
#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
#define DW3_ERROR_BIT (1 << 28)
#define DW3_BABBLE_BIT (1 << 29)
#define DW3_HALT_BIT (1 << 30)
#define DW3_ACTIVE_BIT (1 << 31)
#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
#define INT_EXACT (1 << 0)
#define SETUP_PID (2)
#define IN_PID (1)
#define OUT_PID (0)
/* Errata 1 */
#define RL_COUNTER (0)
#define NAK_COUNTER (0)
#define ERR_COUNTER (2)
#endif /* _ISP1760_HCD_H_ */

View file

@ -1,477 +0,0 @@
/*
* Glue code for the ISP1760 driver and bus
* Currently there is support for
* - OpenFirmware
* - PCI
* - PDEV (generic platform device centralized driver model)
*
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
*
*/
#include <linux/usb.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/usb/isp1760.h>
#include <linux/usb/hcd.h>
#include "isp1760-hcd.h"
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#endif
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
struct isp1760 {
struct usb_hcd *hcd;
int rst_gpio;
};
static int of_isp1760_probe(struct platform_device *dev)
{
struct isp1760 *drvdata;
struct device_node *dp = dev->dev.of_node;
struct resource *res;
struct resource memory;
int virq;
resource_size_t res_len;
int ret;
unsigned int devflags = 0;
enum of_gpio_flags gpio_flags;
u32 bus_width = 0;
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
ret = of_address_to_resource(dp, 0, &memory);
if (ret) {
ret = -ENXIO;
goto free_data;
}
res_len = resource_size(&memory);
res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
if (!res) {
ret = -EBUSY;
goto free_data;
}
virq = irq_of_parse_and_map(dp, 0);
if (!virq) {
ret = -ENODEV;
goto release_reg;
}
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
devflags |= ISP1760_FLAG_ISP1761;
/* Some systems wire up only 16 of the 32 data lines */
of_property_read_u32(dp, "bus-width", &bus_width);
if (bus_width == 16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (of_get_property(dp, "port1-otg", NULL) != NULL)
devflags |= ISP1760_FLAG_OTG_EN;
if (of_get_property(dp, "analog-oc", NULL) != NULL)
devflags |= ISP1760_FLAG_ANALOG_OC;
if (of_get_property(dp, "dack-polarity", NULL) != NULL)
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
if (gpio_is_valid(drvdata->rst_gpio)) {
ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
if (!ret) {
if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
gpio_direction_output(drvdata->rst_gpio, 0);
} else {
gpio_direction_output(drvdata->rst_gpio, 1);
}
} else {
drvdata->rst_gpio = ret;
}
}
drvdata->hcd = isp1760_register(memory.start, res_len, virq,
IRQF_SHARED, drvdata->rst_gpio,
&dev->dev, dev_name(&dev->dev),
devflags);
if (IS_ERR(drvdata->hcd)) {
ret = PTR_ERR(drvdata->hcd);
goto free_gpio;
}
platform_set_drvdata(dev, drvdata);
return ret;
free_gpio:
if (gpio_is_valid(drvdata->rst_gpio))
gpio_free(drvdata->rst_gpio);
release_reg:
release_mem_region(memory.start, res_len);
free_data:
kfree(drvdata);
return ret;
}
static int of_isp1760_remove(struct platform_device *dev)
{
struct isp1760 *drvdata = platform_get_drvdata(dev);
usb_remove_hcd(drvdata->hcd);
iounmap(drvdata->hcd->regs);
release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
usb_put_hcd(drvdata->hcd);
if (gpio_is_valid(drvdata->rst_gpio))
gpio_free(drvdata->rst_gpio);
kfree(drvdata);
return 0;
}
static const struct of_device_id of_isp1760_match[] = {
{
.compatible = "nxp,usb-isp1760",
},
{
.compatible = "nxp,usb-isp1761",
},
{ },
};
MODULE_DEVICE_TABLE(of, of_isp1760_match);
static struct platform_driver isp1760_of_driver = {
.driver = {
.name = "nxp-isp1760",
.of_match_table = of_isp1760_match,
},
.probe = of_isp1760_probe,
.remove = of_isp1760_remove,
};
#endif
#ifdef CONFIG_PCI
static int isp1761_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u8 latency, limit;
__u32 reg_data;
int retry_count;
struct usb_hcd *hcd;
unsigned int devflags = 0;
int ret_status = 0;
resource_size_t pci_mem_phy0;
resource_size_t memlength;
u8 __iomem *chip_addr;
u8 __iomem *iobase;
resource_size_t nxp_pci_io_base;
resource_size_t iolength;
if (usb_disabled())
return -ENODEV;
if (pci_enable_device(dev) < 0)
return -ENODEV;
if (!dev->irq)
return -ENODEV;
/* Grab the PLX PCI mem maped port start address we need */
nxp_pci_io_base = pci_resource_start(dev, 0);
iolength = pci_resource_len(dev, 0);
if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
printk(KERN_ERR "request region #1\n");
return -EBUSY;
}
iobase = ioremap_nocache(nxp_pci_io_base, iolength);
if (!iobase) {
printk(KERN_ERR "ioremap #1\n");
ret_status = -ENOMEM;
goto cleanup1;
}
/* Grab the PLX PCI shared memory of the ISP 1761 we need */
pci_mem_phy0 = pci_resource_start(dev, 3);
memlength = pci_resource_len(dev, 3);
if (memlength < 0xffff) {
printk(KERN_ERR "memory length for this resource is wrong\n");
ret_status = -ENOMEM;
goto cleanup2;
}
if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
printk(KERN_ERR "host controller already in use\n");
ret_status = -EBUSY;
goto cleanup2;
}
/* map available memory */
chip_addr = ioremap_nocache(pci_mem_phy0,memlength);
if (!chip_addr) {
printk(KERN_ERR "Error ioremap failed\n");
ret_status = -ENOMEM;
goto cleanup3;
}
/* bad pci latencies can contribute to overruns */
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
if (latency) {
pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
if (limit && limit < latency)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
}
/* Try to check whether we can access Scratch Register of
* Host Controller or not. The initial PCI access is retried until
* local init for the PCI bridge is completed
*/
retry_count = 20;
reg_data = 0;
while ((reg_data != 0xFACE) && retry_count) {
/*by default host is in 16bit mode, so
* io operations at this stage must be 16 bit
* */
writel(0xface, chip_addr + HC_SCRATCH_REG);
udelay(100);
reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
retry_count--;
}
iounmap(chip_addr);
/* Host Controller presence is detected by writing to scratch register
* and reading back and checking the contents are same or not
*/
if (reg_data != 0xFACE) {
dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
ret_status = -ENOMEM;
goto cleanup3;
}
pci_set_master(dev);
/* configure PLX PCI chip to pass interrupts */
#define PLX_INT_CSR_REG 0x68
reg_data = readl(iobase + PLX_INT_CSR_REG);
reg_data |= 0x900;
writel(reg_data, iobase + PLX_INT_CSR_REG);
dev->dev.dma_mask = NULL;
hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
devflags);
if (IS_ERR(hcd)) {
ret_status = -ENODEV;
goto cleanup3;
}
/* done with PLX IO access */
iounmap(iobase);
release_mem_region(nxp_pci_io_base, iolength);
pci_set_drvdata(dev, hcd);
return 0;
cleanup3:
release_mem_region(pci_mem_phy0, memlength);
cleanup2:
iounmap(iobase);
cleanup1:
release_mem_region(nxp_pci_io_base, iolength);
return ret_status;
}
static void isp1761_pci_remove(struct pci_dev *dev)
{
struct usb_hcd *hcd;
hcd = pci_get_drvdata(dev);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
pci_disable_device(dev);
}
static void isp1761_pci_shutdown(struct pci_dev *dev)
{
printk(KERN_ERR "ips1761_pci_shutdown\n");
}
static const struct pci_device_id isp1760_plx [] = {
{
.class = PCI_CLASS_BRIDGE_OTHER << 8,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x5406,
.subvendor = PCI_VENDOR_ID_PLX,
.subdevice = 0x9054,
},
{ }
};
MODULE_DEVICE_TABLE(pci, isp1760_plx);
static struct pci_driver isp1761_pci_driver = {
.name = "isp1760",
.id_table = isp1760_plx,
.probe = isp1761_pci_probe,
.remove = isp1761_pci_remove,
.shutdown = isp1761_pci_shutdown,
};
#endif
static int isp1760_plat_probe(struct platform_device *pdev)
{
int ret = 0;
struct usb_hcd *hcd;
struct resource *mem_res;
struct resource *irq_res;
resource_size_t mem_size;
struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev);
unsigned int devflags = 0;
unsigned long irqflags = IRQF_SHARED;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
pr_warning("isp1760: Memory resource not available\n");
ret = -ENODEV;
goto out;
}
mem_size = resource_size(mem_res);
if (!request_mem_region(mem_res->start, mem_size, "isp1760")) {
pr_warning("isp1760: Cannot reserve the memory resource\n");
ret = -EBUSY;
goto out;
}
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
pr_warning("isp1760: IRQ resource not available\n");
ret = -ENODEV;
goto cleanup;
}
irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
if (priv) {
if (priv->is_isp1761)
devflags |= ISP1760_FLAG_ISP1761;
if (priv->bus_width_16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (priv->port1_otg)
devflags |= ISP1760_FLAG_OTG_EN;
if (priv->analog_oc)
devflags |= ISP1760_FLAG_ANALOG_OC;
if (priv->dack_polarity_high)
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (priv->dreq_polarity_high)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
}
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
irqflags, -ENOENT,
&pdev->dev, dev_name(&pdev->dev), devflags);
platform_set_drvdata(pdev, hcd);
if (IS_ERR(hcd)) {
pr_warning("isp1760: Failed to register the HCD device\n");
ret = -ENODEV;
goto cleanup;
}
pr_info("ISP1760 USB device initialised\n");
return ret;
cleanup:
release_mem_region(mem_res->start, mem_size);
out:
return ret;
}
static int isp1760_plat_remove(struct platform_device *pdev)
{
struct resource *mem_res;
resource_size_t mem_size;
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_remove_hcd(hcd);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mem_size = resource_size(mem_res);
release_mem_region(mem_res->start, mem_size);
usb_put_hcd(hcd);
return 0;
}
static struct platform_driver isp1760_plat_driver = {
.probe = isp1760_plat_probe,
.remove = isp1760_plat_remove,
.driver = {
.name = "isp1760",
},
};
static int __init isp1760_init(void)
{
int ret, any_ret = -ENODEV;
init_kmem_once();
ret = platform_driver_register(&isp1760_plat_driver);
if (!ret)
any_ret = 0;
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
ret = platform_driver_register(&isp1760_of_driver);
if (!ret)
any_ret = 0;
#endif
#ifdef CONFIG_PCI
ret = pci_register_driver(&isp1761_pci_driver);
if (!ret)
any_ret = 0;
#endif
if (any_ret)
deinit_kmem_cache();
return any_ret;
}
module_init(isp1760_init);
static void __exit isp1760_exit(void)
{
platform_driver_unregister(&isp1760_plat_driver);
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
platform_driver_unregister(&isp1760_of_driver);
#endif
#ifdef CONFIG_PCI
pci_unregister_driver(&isp1761_pci_driver);
#endif
deinit_kmem_cache();
}
module_exit(isp1760_exit);

View file

@ -0,0 +1,59 @@
config USB_ISP1760
tristate "NXP ISP 1760/1761 support"
depends on USB || USB_GADGET
help
Say Y or M here if your system as an ISP1760 USB host controller
or an ISP1761 USB dual-role controller.
This driver does not support isochronous transfers or OTG.
This USB controller is usually attached to a non-DMA-Master
capable bus. NXP's eval kit brings this chip on PCI card
where the chip itself is behind a PLB to simulate such
a bus.
To compile this driver as a module, choose M here: the
module will be called isp1760.
config USB_ISP1760_HCD
bool
config USB_ISP1761_UDC
bool
if USB_ISP1760
choice
bool "ISP1760 Mode Selection"
default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET)
default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET)
default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET)
config USB_ISP1760_HOST_ROLE
bool "Host only mode"
depends on USB=y || USB=USB_ISP1760
select USB_ISP1760_HCD
help
Select this if you want to use the ISP1760 in host mode only. The
gadget function will be disabled.
config USB_ISP1760_GADGET_ROLE
bool "Gadget only mode"
depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
select USB_ISP1761_UDC
help
Select this if you want to use the ISP1760 in peripheral mode only.
The host function will be disabled.
config USB_ISP1760_DUAL_ROLE
bool "Dual Role mode"
depends on USB=y || USB=USB_ISP1760
depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
select USB_ISP1760_HCD
select USB_ISP1761_UDC
help
Select this if you want to use the ISP1760 in both host and
peripheral modes.
endchoice
endif

View file

@ -0,0 +1,5 @@
isp1760-y := isp1760-core.o isp1760-if.o
isp1760-$(CONFIG_USB_ISP1760_HCD) += isp1760-hcd.o
isp1760-$(CONFIG_USB_ISP1761_UDC) += isp1760-udc.o
obj-$(CONFIG_USB_ISP1760) += isp1760.o

View file

@ -0,0 +1,177 @@
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include "isp1760-core.h"
#include "isp1760-hcd.h"
#include "isp1760-regs.h"
#include "isp1760-udc.h"
static void isp1760_init_core(struct isp1760_device *isp)
{
u32 otgctrl;
u32 hwmode;
/* Low-level chip reset */
if (isp->rst_gpio) {
gpiod_set_value_cansleep(isp->rst_gpio, 1);
mdelay(50);
gpiod_set_value_cansleep(isp->rst_gpio, 0);
}
/*
* Reset the host controller, including the CPU interface
* configuration.
*/
isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
msleep(100);
/* Setup HW Mode Control: This assumes a level active-low interrupt */
hwmode = HW_DATA_BUS_32BIT;
if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
hwmode &= ~HW_DATA_BUS_32BIT;
if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
hwmode |= HW_ANA_DIGI_OC;
if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
hwmode |= HW_DACK_POL_HIGH;
if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
hwmode |= HW_DREQ_POL_HIGH;
if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
hwmode |= HW_INTR_HIGH_ACT;
if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
hwmode |= HW_INTR_EDGE_TRIG;
/*
* The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
* IRQ line for both the host and device controllers. Hardcode IRQ
* sharing for now and disable the DC interrupts globally to avoid
* spurious interrupts during HCD registration.
*/
if (isp->devflags & ISP1760_FLAG_ISP1761) {
isp1760_write32(isp->regs, DC_MODE, 0);
hwmode |= HW_COMN_IRQ;
}
/*
* We have to set this first in case we're in 16-bit mode.
* Write it twice to ensure correct upper bits if switching
* to 16-bit mode.
*/
isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
/*
* PORT 1 Control register of the ISP1760 is the OTG control register
* on ISP1761.
*
* TODO: Really support OTG. For now we configure port 1 in device mode
* when OTG is requested.
*/
if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
(isp->devflags & ISP1760_FLAG_OTG_EN))
otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
| HW_OTG_DISABLE;
else
otgctrl = (HW_SW_SEL_HC_DC << 16)
| (HW_VBUS_DRV | HW_SEL_CP_EXT);
isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
dev_info(isp->dev, "bus width: %u, oc: %s\n",
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
}
void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
{
isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
}
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
struct device *dev, unsigned int devflags)
{
struct isp1760_device *isp;
bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
int ret;
/*
* If neither the HCD not the UDC is enabled return an error, as no
* device would be registered.
*/
if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) &&
(!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || udc_disabled))
return -ENODEV;
/* prevent usb-core allocating DMA pages */
dev->dma_mask = NULL;
isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
if (!isp)
return -ENOMEM;
isp->dev = dev;
isp->devflags = devflags;
isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
if (IS_ERR(isp->rst_gpio))
return PTR_ERR(isp->rst_gpio);
isp->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(isp->regs))
return PTR_ERR(isp->regs);
isp1760_init_core(isp);
if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
irqflags | IRQF_SHARED, dev);
if (ret < 0)
return ret;
}
if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
IRQF_DISABLED);
if (ret < 0) {
isp1760_hcd_unregister(&isp->hcd);
return ret;
}
}
dev_set_drvdata(dev, isp);
return 0;
}
void isp1760_unregister(struct device *dev)
{
struct isp1760_device *isp = dev_get_drvdata(dev);
isp1760_udc_unregister(isp);
isp1760_hcd_unregister(&isp->hcd);
}
MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
MODULE_AUTHOR("Sebastian Siewior <[email protected]>");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,68 @@
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#ifndef _ISP1760_CORE_H_
#define _ISP1760_CORE_H_
#include <linux/ioport.h>
#include "isp1760-hcd.h"
#include "isp1760-udc.h"
struct device;
struct gpio_desc;
/*
* Device flags that can vary from board to board. All of these
* indicate the most "atypical" case, so that a devflags of 0 is
* a sane default configuration.
*/
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
struct isp1760_device {
struct device *dev;
void __iomem *regs;
unsigned int devflags;
struct gpio_desc *rst_gpio;
struct isp1760_hcd hcd;
struct isp1760_udc udc;
};
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
struct device *dev, unsigned int devflags);
void isp1760_unregister(struct device *dev);
void isp1760_set_pullup(struct isp1760_device *isp, bool enable);
static inline u32 isp1760_read32(void __iomem *base, u32 reg)
{
return readl(base + reg);
}
static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val)
{
writel(val, base + reg);
}
#endif

View file

@ -11,6 +11,7 @@
* (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
*
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@ -24,73 +25,96 @@
#include <linux/timer.h>
#include <asm/unaligned.h>
#include <asm/cacheflush.h>
#include <linux/gpio.h>
#include "isp1760-core.h"
#include "isp1760-hcd.h"
#include "isp1760-regs.h"
static struct kmem_cache *qtd_cachep;
static struct kmem_cache *qh_cachep;
static struct kmem_cache *urb_listitem_cachep;
enum queue_head_types {
QH_CONTROL,
QH_BULK,
QH_INTERRUPT,
QH_END
};
struct isp1760_hcd {
u32 hcs_params;
spinlock_t lock;
struct slotinfo atl_slots[32];
int atl_done_map;
struct slotinfo int_slots[32];
int int_done_map;
struct memory_chunk memory_pool[BLOCKS];
struct list_head qh_list[QH_END];
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024
unsigned periodic_size;
unsigned i_thresh;
unsigned long reset_done;
unsigned long next_statechange;
unsigned int devflags;
int rst_gpio;
};
typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct isp1760_qtd *qtd);
static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
{
return (struct isp1760_hcd *) (hcd->hcd_priv);
return *(struct isp1760_hcd **)hcd->hcd_priv;
}
/* Section 2.2 Host Controller Capability Registers */
#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
/* urb state*/
#define DELETE_URB (0x0008)
#define NO_TRANSFER_ACTIVE (0xffffffff)
/* Section 2.3 Host Controller Operational Registers */
#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
#define CMD_RESET (1<<1) /* reset HC not bus */
#define CMD_RUN (1<<0) /* start/stop HC */
#define STS_PCD (1<<2) /* port change detect */
#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
/* Philips Proprietary Transfer Descriptor (PTD) */
typedef __u32 __bitwise __dw;
struct ptd {
__dw dw0;
__dw dw1;
__dw dw2;
__dw dw3;
__dw dw4;
__dw dw5;
__dw dw6;
__dw dw7;
};
#define PTD_OFFSET 0x0400
#define ISO_PTD_OFFSET 0x0400
#define INT_PTD_OFFSET 0x0800
#define ATL_PTD_OFFSET 0x0c00
#define PAYLOAD_OFFSET 0x1000
#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
#define PORT_POWER (1<<12) /* true: has power (see PPC) */
#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
#define PORT_RESET (1<<8) /* reset port */
#define PORT_SUSPEND (1<<7) /* suspend port */
#define PORT_RESUME (1<<6) /* resume it */
#define PORT_PE (1<<2) /* port enable */
#define PORT_CSC (1<<1) /* connect status change */
#define PORT_CONNECT (1<<0) /* device connected */
#define PORT_RWC_BITS (PORT_CSC)
/* ATL */
/* DW0 */
#define DW0_VALID_BIT 1
#define FROM_DW0_VALID(x) ((x) & 0x01)
#define TO_DW0_LENGTH(x) (((u32) x) << 3)
#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
#define TO_DW0_MULTI(x) (((u32) x) << 29)
#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
/* DW1 */
#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
#define DW1_TRANS_BULK ((u32) 2 << 12)
#define DW1_TRANS_INT ((u32) 3 << 12)
#define DW1_TRANS_SPLIT ((u32) 1 << 14)
#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
/* DW2 */
#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
#define TO_DW2_RL(x) ((x) << 25)
#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
/* DW3 */
#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
#define TO_DW3_NAKCOUNT(x) ((x) << 19)
#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
#define TO_DW3_CERR(x) ((x) << 23)
#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
#define TO_DW3_PING(x) ((x) << 26)
#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
#define DW3_ERROR_BIT (1 << 28)
#define DW3_BABBLE_BIT (1 << 29)
#define DW3_HALT_BIT (1 << 30)
#define DW3_ACTIVE_BIT (1 << 31)
#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
#define INT_EXACT (1 << 0)
#define SETUP_PID (2)
#define IN_PID (1)
#define OUT_PID (0)
/* Errata 1 */
#define RL_COUNTER (0)
#define NAK_COUNTER (0)
#define ERR_COUNTER (2)
struct isp1760_qtd {
u8 packet_type;
@ -137,12 +161,12 @@ struct urb_listitem {
*/
static u32 reg_read32(void __iomem *base, u32 reg)
{
return readl(base + reg);
return isp1760_read32(base, reg);
}
static void reg_write32(void __iomem *base, u32 reg, u32 val)
{
writel(val, base + reg);
isp1760_write32(base, reg, val);
}
/*
@ -443,42 +467,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
int result;
u32 scratch, hwmode;
/* low-level chip reset */
if (gpio_is_valid(priv->rst_gpio)) {
unsigned int rst_lvl;
rst_lvl = (priv->devflags &
ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
gpio_set_value(priv->rst_gpio, rst_lvl);
mdelay(50);
gpio_set_value(priv->rst_gpio, !rst_lvl);
}
/* Setup HW Mode Control: This assumes a level active-low interrupt */
hwmode = HW_DATA_BUS_32BIT;
if (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16)
hwmode &= ~HW_DATA_BUS_32BIT;
if (priv->devflags & ISP1760_FLAG_ANALOG_OC)
hwmode |= HW_ANA_DIGI_OC;
if (priv->devflags & ISP1760_FLAG_DACK_POL_HIGH)
hwmode |= HW_DACK_POL_HIGH;
if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
hwmode |= HW_DREQ_POL_HIGH;
if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH)
hwmode |= HW_INTR_HIGH_ACT;
if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
hwmode |= HW_INTR_EDGE_TRIG;
/*
* We have to set this first in case we're in 16-bit mode.
* Write it twice to ensure correct upper bits if switching
* to 16-bit mode.
*/
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
/* Change bus pattern */
scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
@ -488,46 +476,33 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
return -ENODEV;
}
/* pre reset */
/*
* The RESET_HC bit in the SW_RESET register is supposed to reset the
* host controller without touching the CPU interface registers, but at
* least on the ISP1761 it seems to behave as the RESET_ALL bit and
* reset the whole device. We thus can't use it here, so let's reset
* the host controller through the EHCI USB Command register. The device
* has been reset in core code anyway, so this shouldn't matter.
*/
reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
/* reset */
reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
mdelay(100);
reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_HC);
mdelay(100);
result = ehci_reset(hcd);
if (result)
return result;
/* Step 11 passed */
dev_info(hcd->self.controller, "bus width: %d, oc: %s\n",
(priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ?
16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
"analog" : "digital");
/* ATL reset */
hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET;
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
mdelay(10);
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
/*
* PORT 1 Control register of the ISP1760 is the OTG control
* register on ISP1761. Since there is no OTG or device controller
* support in this driver, we use port 1 as a "normal" USB host port on
* both chips.
*/
reg_write32(hcd->regs, HC_PORT1_CTRL, PORT1_POWER | PORT1_INIT2);
mdelay(10);
priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
return priv_init(hcd);
@ -743,8 +718,9 @@ static void qtd_free(struct isp1760_qtd *qtd)
}
static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
struct slotinfo *slots, struct isp1760_qtd *qtd,
struct isp1760_qh *qh, struct ptd *ptd)
struct isp1760_slotinfo *slots,
struct isp1760_qtd *qtd, struct isp1760_qh *qh,
struct ptd *ptd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
int skip_map;
@ -857,7 +833,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
int ptd_offset;
struct slotinfo *slots;
struct isp1760_slotinfo *slots;
int curr_slot, free_slot;
int n;
struct ptd ptd;
@ -1097,7 +1073,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
struct isp1760_qh *qh;
int slot;
int state;
struct slotinfo *slots;
struct isp1760_slotinfo *slots;
u32 ptd_offset;
struct isp1760_qtd *qtd;
int modified;
@ -2161,7 +2137,7 @@ static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
static const struct hc_driver isp1760_hc_driver = {
.description = "isp1760-hcd",
.product_desc = "NXP ISP1760 USB Host Controller",
.hcd_priv_size = sizeof(struct isp1760_hcd),
.hcd_priv_size = sizeof(struct isp1760_hcd *),
.irq = isp1760_irq,
.flags = HCD_MEMORY | HCD_USB2,
.reset = isp1760_hc_setup,
@ -2177,7 +2153,7 @@ static const struct hc_driver isp1760_hc_driver = {
.clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete,
};
int __init init_kmem_once(void)
int __init isp1760_init_kmem_once(void)
{
urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
@ -2204,66 +2180,56 @@ int __init init_kmem_once(void)
return 0;
}
void deinit_kmem_cache(void)
void isp1760_deinit_kmem_cache(void)
{
kmem_cache_destroy(qtd_cachep);
kmem_cache_destroy(qh_cachep);
kmem_cache_destroy(urb_listitem_cachep);
}
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
int irq, unsigned long irqflags,
int rst_gpio,
struct device *dev, const char *busname,
unsigned int devflags)
int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
struct resource *mem, int irq, unsigned long irqflags,
struct device *dev)
{
struct usb_hcd *hcd;
struct isp1760_hcd *priv;
int ret;
if (usb_disabled())
return ERR_PTR(-ENODEV);
/* prevent usb-core allocating DMA pages */
dev->dma_mask = NULL;
hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev));
if (!hcd)
return ERR_PTR(-ENOMEM);
return -ENOMEM;
*(struct isp1760_hcd **)hcd->hcd_priv = priv;
priv->hcd = hcd;
priv = hcd_to_priv(hcd);
priv->devflags = devflags;
priv->rst_gpio = rst_gpio;
init_memory(priv);
hcd->regs = ioremap(res_start, res_len);
if (!hcd->regs) {
ret = -EIO;
goto err_put;
}
hcd->irq = irq;
hcd->rsrc_start = res_start;
hcd->rsrc_len = res_len;
hcd->regs = regs;
hcd->rsrc_start = mem->start;
hcd->rsrc_len = resource_size(mem);
/* This driver doesn't support wakeup requests */
hcd->cant_recv_wakeups = 1;
ret = usb_add_hcd(hcd, irq, irqflags);
if (ret)
goto err_unmap;
goto error;
device_wakeup_enable(hcd->self.controller);
return hcd;
return 0;
err_unmap:
iounmap(hcd->regs);
err_put:
usb_put_hcd(hcd);
return ERR_PTR(ret);
error:
usb_put_hcd(hcd);
return ret;
}
MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
MODULE_AUTHOR("Sebastian Siewior <[email protected]>");
MODULE_LICENSE("GPL v2");
void isp1760_hcd_unregister(struct isp1760_hcd *priv)
{
if (!priv->hcd)
return;
usb_remove_hcd(priv->hcd);
usb_put_hcd(priv->hcd);
}

View file

@ -0,0 +1,102 @@
#ifndef _ISP1760_HCD_H_
#define _ISP1760_HCD_H_
#include <linux/spinlock.h>
struct isp1760_qh;
struct isp1760_qtd;
struct resource;
struct usb_hcd;
/*
* 60kb divided in:
* - 32 blocks @ 256 bytes
* - 20 blocks @ 1024 bytes
* - 4 blocks @ 8192 bytes
*/
#define BLOCK_1_NUM 32
#define BLOCK_2_NUM 20
#define BLOCK_3_NUM 4
#define BLOCK_1_SIZE 256
#define BLOCK_2_SIZE 1024
#define BLOCK_3_SIZE 8192
#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
#define PAYLOAD_AREA_SIZE 0xf000
struct isp1760_slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
unsigned long timestamp;
};
/* chip memory management */
struct isp1760_memory_chunk {
unsigned int start;
unsigned int size;
unsigned int free;
};
enum isp1760_queue_head_types {
QH_CONTROL,
QH_BULK,
QH_INTERRUPT,
QH_END
};
struct isp1760_hcd {
#ifdef CONFIG_USB_ISP1760_HCD
struct usb_hcd *hcd;
u32 hcs_params;
spinlock_t lock;
struct isp1760_slotinfo atl_slots[32];
int atl_done_map;
struct isp1760_slotinfo int_slots[32];
int int_done_map;
struct isp1760_memory_chunk memory_pool[BLOCKS];
struct list_head qh_list[QH_END];
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024
unsigned periodic_size;
unsigned i_thresh;
unsigned long reset_done;
unsigned long next_statechange;
#endif
};
#ifdef CONFIG_USB_ISP1760_HCD
int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
struct resource *mem, int irq, unsigned long irqflags,
struct device *dev);
void isp1760_hcd_unregister(struct isp1760_hcd *priv);
int isp1760_init_kmem_once(void);
void isp1760_deinit_kmem_cache(void);
#else
static inline int isp1760_hcd_register(struct isp1760_hcd *priv,
void __iomem *regs, struct resource *mem,
int irq, unsigned long irqflags,
struct device *dev)
{
return 0;
}
static inline void isp1760_hcd_unregister(struct isp1760_hcd *priv)
{
}
static inline int isp1760_init_kmem_once(void)
{
return 0;
}
static inline void isp1760_deinit_kmem_cache(void)
{
}
#endif
#endif /* _ISP1760_HCD_H_ */

View file

@ -0,0 +1,309 @@
/*
* Glue code for the ISP1760 driver and bus
* Currently there is support for
* - OpenFirmware
* - PCI
* - PDEV (generic platform device centralized driver model)
*
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
*
*/
#include <linux/usb.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb/isp1760.h>
#include <linux/usb/hcd.h>
#include "isp1760-core.h"
#include "isp1760-regs.h"
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
#ifdef CONFIG_PCI
static int isp1761_pci_init(struct pci_dev *dev)
{
resource_size_t mem_start;
resource_size_t mem_length;
u8 __iomem *iobase;
u8 latency, limit;
int retry_count;
u32 reg_data;
/* Grab the PLX PCI shared memory of the ISP 1761 we need */
mem_start = pci_resource_start(dev, 3);
mem_length = pci_resource_len(dev, 3);
if (mem_length < 0xffff) {
printk(KERN_ERR "memory length for this resource is wrong\n");
return -ENOMEM;
}
if (!request_mem_region(mem_start, mem_length, "ISP-PCI")) {
printk(KERN_ERR "host controller already in use\n");
return -EBUSY;
}
/* map available memory */
iobase = ioremap_nocache(mem_start, mem_length);
if (!iobase) {
printk(KERN_ERR "Error ioremap failed\n");
release_mem_region(mem_start, mem_length);
return -ENOMEM;
}
/* bad pci latencies can contribute to overruns */
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
if (latency) {
pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
if (limit && limit < latency)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
}
/* Try to check whether we can access Scratch Register of
* Host Controller or not. The initial PCI access is retried until
* local init for the PCI bridge is completed
*/
retry_count = 20;
reg_data = 0;
while ((reg_data != 0xFACE) && retry_count) {
/*by default host is in 16bit mode, so
* io operations at this stage must be 16 bit
* */
writel(0xface, iobase + HC_SCRATCH_REG);
udelay(100);
reg_data = readl(iobase + HC_SCRATCH_REG) & 0x0000ffff;
retry_count--;
}
iounmap(iobase);
release_mem_region(mem_start, mem_length);
/* Host Controller presence is detected by writing to scratch register
* and reading back and checking the contents are same or not
*/
if (reg_data != 0xFACE) {
dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
return -ENOMEM;
}
/* Grab the PLX PCI mem maped port start address we need */
mem_start = pci_resource_start(dev, 0);
mem_length = pci_resource_len(dev, 0);
if (!request_mem_region(mem_start, mem_length, "ISP1761 IO MEM")) {
printk(KERN_ERR "request region #1\n");
return -EBUSY;
}
iobase = ioremap_nocache(mem_start, mem_length);
if (!iobase) {
printk(KERN_ERR "ioremap #1\n");
release_mem_region(mem_start, mem_length);
return -ENOMEM;
}
/* configure PLX PCI chip to pass interrupts */
#define PLX_INT_CSR_REG 0x68
reg_data = readl(iobase + PLX_INT_CSR_REG);
reg_data |= 0x900;
writel(reg_data, iobase + PLX_INT_CSR_REG);
/* done with PLX IO access */
iounmap(iobase);
release_mem_region(mem_start, mem_length);
return 0;
}
static int isp1761_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
unsigned int devflags = 0;
int ret;
if (!dev->irq)
return -ENODEV;
if (pci_enable_device(dev) < 0)
return -ENODEV;
ret = isp1761_pci_init(dev);
if (ret < 0)
goto error;
pci_set_master(dev);
dev->dev.dma_mask = NULL;
ret = isp1760_register(&dev->resource[3], dev->irq, 0, &dev->dev,
devflags);
if (ret < 0)
goto error;
return 0;
error:
pci_disable_device(dev);
return ret;
}
static void isp1761_pci_remove(struct pci_dev *dev)
{
isp1760_unregister(&dev->dev);
pci_disable_device(dev);
}
static void isp1761_pci_shutdown(struct pci_dev *dev)
{
printk(KERN_ERR "ips1761_pci_shutdown\n");
}
static const struct pci_device_id isp1760_plx [] = {
{
.class = PCI_CLASS_BRIDGE_OTHER << 8,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x5406,
.subvendor = PCI_VENDOR_ID_PLX,
.subdevice = 0x9054,
},
{ }
};
MODULE_DEVICE_TABLE(pci, isp1760_plx);
static struct pci_driver isp1761_pci_driver = {
.name = "isp1760",
.id_table = isp1760_plx,
.probe = isp1761_pci_probe,
.remove = isp1761_pci_remove,
.shutdown = isp1761_pci_shutdown,
};
#endif
static int isp1760_plat_probe(struct platform_device *pdev)
{
unsigned long irqflags;
unsigned int devflags = 0;
struct resource *mem_res;
struct resource *irq_res;
int ret;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
pr_warning("isp1760: IRQ resource not available\n");
return -ENODEV;
}
irqflags = irq_res->flags & IRQF_TRIGGER_MASK;
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
struct device_node *dp = pdev->dev.of_node;
u32 bus_width = 0;
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
devflags |= ISP1760_FLAG_ISP1761;
/* Some systems wire up only 16 of the 32 data lines */
of_property_read_u32(dp, "bus-width", &bus_width);
if (bus_width == 16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (of_property_read_bool(dp, "port1-otg"))
devflags |= ISP1760_FLAG_OTG_EN;
if (of_property_read_bool(dp, "analog-oc"))
devflags |= ISP1760_FLAG_ANALOG_OC;
if (of_property_read_bool(dp, "dack-polarity"))
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (of_property_read_bool(dp, "dreq-polarity"))
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
} else if (dev_get_platdata(&pdev->dev)) {
struct isp1760_platform_data *pdata =
dev_get_platdata(&pdev->dev);
if (pdata->is_isp1761)
devflags |= ISP1760_FLAG_ISP1761;
if (pdata->bus_width_16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (pdata->port1_otg)
devflags |= ISP1760_FLAG_OTG_EN;
if (pdata->analog_oc)
devflags |= ISP1760_FLAG_ANALOG_OC;
if (pdata->dack_polarity_high)
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (pdata->dreq_polarity_high)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
}
ret = isp1760_register(mem_res, irq_res->start, irqflags, &pdev->dev,
devflags);
if (ret < 0)
return ret;
pr_info("ISP1760 USB device initialised\n");
return 0;
}
static int isp1760_plat_remove(struct platform_device *pdev)
{
isp1760_unregister(&pdev->dev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id isp1760_of_match[] = {
{ .compatible = "nxp,usb-isp1760", },
{ .compatible = "nxp,usb-isp1761", },
{ },
};
MODULE_DEVICE_TABLE(of, isp1760_of_match);
#endif
static struct platform_driver isp1760_plat_driver = {
.probe = isp1760_plat_probe,
.remove = isp1760_plat_remove,
.driver = {
.name = "isp1760",
.of_match_table = of_match_ptr(isp1760_of_match),
},
};
static int __init isp1760_init(void)
{
int ret, any_ret = -ENODEV;
isp1760_init_kmem_once();
ret = platform_driver_register(&isp1760_plat_driver);
if (!ret)
any_ret = 0;
#ifdef CONFIG_PCI
ret = pci_register_driver(&isp1761_pci_driver);
if (!ret)
any_ret = 0;
#endif
if (any_ret)
isp1760_deinit_kmem_cache();
return any_ret;
}
module_init(isp1760_init);
static void __exit isp1760_exit(void)
{
platform_driver_unregister(&isp1760_plat_driver);
#ifdef CONFIG_PCI
pci_unregister_driver(&isp1761_pci_driver);
#endif
isp1760_deinit_kmem_cache();
}
module_exit(isp1760_exit);

View file

@ -0,0 +1,230 @@
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#ifndef _ISP1760_REGS_H_
#define _ISP1760_REGS_H_
/* -----------------------------------------------------------------------------
* Host Controller
*/
/* EHCI capability registers */
#define HC_CAPLENGTH 0x000
#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
#define HC_VERSION(p) (((p) >> 16) & 0xffff) /* bits 31:16 */
#define HC_HCSPARAMS 0x004
#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* true: has port indicators */
#define HCS_PPC(p) ((p) & (1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) /* bits 3:0, ports on HC */
#define HC_HCCPARAMS 0x008
#define HCC_ISOC_CACHE(p) ((p) & (1 << 7)) /* true: can cache isoc frame */
#define HCC_ISOC_THRES(p) (((p) >> 4) & 0x7) /* bits 6:4, uframes cached */
/* EHCI operational registers */
#define HC_USBCMD 0x020
#define CMD_LRESET (1 << 7) /* partial reset (no ports, etc) */
#define CMD_RESET (1 << 1) /* reset HC not bus */
#define CMD_RUN (1 << 0) /* start/stop HC */
#define HC_USBSTS 0x024
#define STS_PCD (1 << 2) /* port change detect */
#define HC_FRINDEX 0x02c
#define HC_CONFIGFLAG 0x060
#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
#define HC_PORTSC1 0x064
#define PORT_OWNER (1 << 13) /* true: companion hc owns this port */
#define PORT_POWER (1 << 12) /* true: has power (see PPC) */
#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
#define PORT_RESET (1 << 8) /* reset port */
#define PORT_SUSPEND (1 << 7) /* suspend port */
#define PORT_RESUME (1 << 6) /* resume it */
#define PORT_PE (1 << 2) /* port enable */
#define PORT_CSC (1 << 1) /* connect status change */
#define PORT_CONNECT (1 << 0) /* device connected */
#define PORT_RWC_BITS (PORT_CSC)
#define HC_ISO_PTD_DONEMAP_REG 0x130
#define HC_ISO_PTD_SKIPMAP_REG 0x134
#define HC_ISO_PTD_LASTPTD_REG 0x138
#define HC_INT_PTD_DONEMAP_REG 0x140
#define HC_INT_PTD_SKIPMAP_REG 0x144
#define HC_INT_PTD_LASTPTD_REG 0x148
#define HC_ATL_PTD_DONEMAP_REG 0x150
#define HC_ATL_PTD_SKIPMAP_REG 0x154
#define HC_ATL_PTD_LASTPTD_REG 0x158
/* Configuration Register */
#define HC_HW_MODE_CTRL 0x300
#define ALL_ATX_RESET (1 << 31)
#define HW_ANA_DIGI_OC (1 << 15)
#define HW_DEV_DMA (1 << 11)
#define HW_COMN_IRQ (1 << 10)
#define HW_COMN_DMA (1 << 9)
#define HW_DATA_BUS_32BIT (1 << 8)
#define HW_DACK_POL_HIGH (1 << 6)
#define HW_DREQ_POL_HIGH (1 << 5)
#define HW_INTR_HIGH_ACT (1 << 2)
#define HW_INTR_EDGE_TRIG (1 << 1)
#define HW_GLOBAL_INTR_EN (1 << 0)
#define HC_CHIP_ID_REG 0x304
#define HC_SCRATCH_REG 0x308
#define HC_RESET_REG 0x30c
#define SW_RESET_RESET_HC (1 << 1)
#define SW_RESET_RESET_ALL (1 << 0)
#define HC_BUFFER_STATUS_REG 0x334
#define ISO_BUF_FILL (1 << 2)
#define INT_BUF_FILL (1 << 1)
#define ATL_BUF_FILL (1 << 0)
#define HC_MEMORY_REG 0x33c
#define ISP_BANK(x) ((x) << 16)
#define HC_PORT1_CTRL 0x374
#define PORT1_POWER (3 << 3)
#define PORT1_INIT1 (1 << 7)
#define PORT1_INIT2 (1 << 23)
#define HW_OTG_CTRL_SET 0x374
#define HW_OTG_CTRL_CLR 0x376
#define HW_OTG_DISABLE (1 << 10)
#define HW_OTG_SE0_EN (1 << 9)
#define HW_BDIS_ACON_EN (1 << 8)
#define HW_SW_SEL_HC_DC (1 << 7)
#define HW_VBUS_CHRG (1 << 6)
#define HW_VBUS_DISCHRG (1 << 5)
#define HW_VBUS_DRV (1 << 4)
#define HW_SEL_CP_EXT (1 << 3)
#define HW_DM_PULLDOWN (1 << 2)
#define HW_DP_PULLDOWN (1 << 1)
#define HW_DP_PULLUP (1 << 0)
/* Interrupt Register */
#define HC_INTERRUPT_REG 0x310
#define HC_INTERRUPT_ENABLE 0x314
#define HC_ISO_INT (1 << 9)
#define HC_ATL_INT (1 << 8)
#define HC_INTL_INT (1 << 7)
#define HC_EOT_INT (1 << 3)
#define HC_SOT_INT (1 << 1)
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
#define HC_ISO_IRQ_MASK_OR_REG 0x318
#define HC_INT_IRQ_MASK_OR_REG 0x31c
#define HC_ATL_IRQ_MASK_OR_REG 0x320
#define HC_ISO_IRQ_MASK_AND_REG 0x324
#define HC_INT_IRQ_MASK_AND_REG 0x328
#define HC_ATL_IRQ_MASK_AND_REG 0x32c
/* -----------------------------------------------------------------------------
* Peripheral Controller
*/
/* Initialization Registers */
#define DC_ADDRESS 0x0200
#define DC_DEVEN (1 << 7)
#define DC_MODE 0x020c
#define DC_DMACLKON (1 << 9)
#define DC_VBUSSTAT (1 << 8)
#define DC_CLKAON (1 << 7)
#define DC_SNDRSU (1 << 6)
#define DC_GOSUSP (1 << 5)
#define DC_SFRESET (1 << 4)
#define DC_GLINTENA (1 << 3)
#define DC_WKUPCS (1 << 2)
#define DC_INTCONF 0x0210
#define DC_CDBGMOD_ACK_NAK (0 << 6)
#define DC_CDBGMOD_ACK (1 << 6)
#define DC_CDBGMOD_ACK_1NAK (2 << 6)
#define DC_DDBGMODIN_ACK_NAK (0 << 4)
#define DC_DDBGMODIN_ACK (1 << 4)
#define DC_DDBGMODIN_ACK_1NAK (2 << 4)
#define DC_DDBGMODOUT_ACK_NYET_NAK (0 << 2)
#define DC_DDBGMODOUT_ACK_NYET (1 << 2)
#define DC_DDBGMODOUT_ACK_NYET_1NAK (2 << 2)
#define DC_INTLVL (1 << 1)
#define DC_INTPOL (1 << 0)
#define DC_DEBUG 0x0212
#define DC_INTENABLE 0x0214
#define DC_IEPTX(n) (1 << (11 + 2 * (n)))
#define DC_IEPRX(n) (1 << (10 + 2 * (n)))
#define DC_IEPRXTX(n) (3 << (10 + 2 * (n)))
#define DC_IEP0SETUP (1 << 8)
#define DC_IEVBUS (1 << 7)
#define DC_IEDMA (1 << 6)
#define DC_IEHS_STA (1 << 5)
#define DC_IERESM (1 << 4)
#define DC_IESUSP (1 << 3)
#define DC_IEPSOF (1 << 2)
#define DC_IESOF (1 << 1)
#define DC_IEBRST (1 << 0)
/* Data Flow Registers */
#define DC_EPINDEX 0x022c
#define DC_EP0SETUP (1 << 5)
#define DC_ENDPIDX(n) ((n) << 1)
#define DC_EPDIR (1 << 0)
#define DC_CTRLFUNC 0x0228
#define DC_CLBUF (1 << 4)
#define DC_VENDP (1 << 3)
#define DC_DSEN (1 << 2)
#define DC_STATUS (1 << 1)
#define DC_STALL (1 << 0)
#define DC_DATAPORT 0x0220
#define DC_BUFLEN 0x021c
#define DC_DATACOUNT_MASK 0xffff
#define DC_BUFSTAT 0x021e
#define DC_EPMAXPKTSZ 0x0204
#define DC_EPTYPE 0x0208
#define DC_NOEMPKT (1 << 4)
#define DC_EPENABLE (1 << 3)
#define DC_DBLBUF (1 << 2)
#define DC_ENDPTYP_ISOC (1 << 0)
#define DC_ENDPTYP_BULK (2 << 0)
#define DC_ENDPTYP_INTERRUPT (3 << 0)
/* DMA Registers */
#define DC_DMACMD 0x0230
#define DC_DMATXCOUNT 0x0234
#define DC_DMACONF 0x0238
#define DC_DMAHW 0x023c
#define DC_DMAINTREASON 0x0250
#define DC_DMAINTEN 0x0254
#define DC_DMAEP 0x0258
#define DC_DMABURSTCOUNT 0x0264
/* General Registers */
#define DC_INTERRUPT 0x0218
#define DC_CHIPID 0x0270
#define DC_FRAMENUM 0x0274
#define DC_SCRATCH 0x0278
#define DC_UNLOCKDEV 0x027c
#define DC_INTPULSEWIDTH 0x0280
#define DC_TESTMODE 0x0284
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
/*
* Driver for the NXP ISP1761 device controller
*
* Copyright 2014 Ideas on Board Oy
*
* Contacts:
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#ifndef _ISP1760_UDC_H_
#define _ISP1760_UDC_H_
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/usb/gadget.h>
struct isp1760_device;
struct isp1760_udc;
enum isp1760_ctrl_state {
ISP1760_CTRL_SETUP, /* Waiting for a SETUP transaction */
ISP1760_CTRL_DATA_IN, /* Setup received, data IN stage */
ISP1760_CTRL_DATA_OUT, /* Setup received, data OUT stage */
ISP1760_CTRL_STATUS, /* 0-length request in status stage */
};
struct isp1760_ep {
struct isp1760_udc *udc;
struct usb_ep ep;
struct list_head queue;
unsigned int addr;
unsigned int maxpacket;
char name[7];
const struct usb_endpoint_descriptor *desc;
bool rx_pending;
bool halted;
bool wedged;
};
/**
* struct isp1760_udc - UDC state information
* irq: IRQ number
* irqname: IRQ name (as passed to request_irq)
* regs: Base address of the UDC registers
* driver: Gadget driver
* gadget: Gadget device
* lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register
* ep: Array of endpoints
* ep0_state: Control request state for endpoint 0
* ep0_dir: Direction of the current control request
* ep0_length: Length of the current control request
* connected: Tracks gadget driver bus connection state
*/
struct isp1760_udc {
#ifdef CONFIG_USB_ISP1761_UDC
struct isp1760_device *isp;
int irq;
char *irqname;
void __iomem *regs;
struct usb_gadget_driver *driver;
struct usb_gadget gadget;
spinlock_t lock;
struct timer_list vbus_timer;
struct isp1760_ep ep[15];
enum isp1760_ctrl_state ep0_state;
u8 ep0_dir;
u16 ep0_length;
bool connected;
unsigned int devstatus;
#endif
};
#ifdef CONFIG_USB_ISP1761_UDC
int isp1760_udc_register(struct isp1760_device *isp, int irq,
unsigned long irqflags);
void isp1760_udc_unregister(struct isp1760_device *isp);
#else
static inline int isp1760_udc_register(struct isp1760_device *isp, int irq,
unsigned long irqflags)
{
return 0;
}
static inline void isp1760_udc_unregister(struct isp1760_device *isp)
{
}
#endif
#endif

View file

@ -63,11 +63,13 @@ comment "Platform Glue Layer"
config USB_MUSB_DAVINCI
tristate "DaVinci"
depends on ARCH_DAVINCI_DMx
depends on NOP_USB_XCEIV
depends on BROKEN
config USB_MUSB_DA8XX
tristate "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX
depends on NOP_USB_XCEIV
depends on BROKEN
config USB_MUSB_TUSB6010
@ -77,12 +79,13 @@ config USB_MUSB_TUSB6010
config USB_MUSB_OMAP2PLUS
tristate "OMAP2430 and onwards"
depends on ARCH_OMAP2PLUS && USB
depends on ARCH_OMAP2PLUS && USB && OMAP_CONTROL_PHY
select GENERIC_PHY
config USB_MUSB_AM35X
tristate "AM35x"
depends on ARCH_OMAP
depends on NOP_USB_XCEIV
config USB_MUSB_DSPS
tristate "TI DSPS platforms"
@ -93,6 +96,7 @@ config USB_MUSB_DSPS
config USB_MUSB_BLACKFIN
tristate "Blackfin"
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
depends on NOP_USB_XCEIV
config USB_MUSB_UX500
tristate "Ux500 platforms"
@ -100,6 +104,7 @@ config USB_MUSB_UX500
config USB_MUSB_JZ4740
tristate "JZ4740"
depends on NOP_USB_XCEIV
depends on MACH_JZ4740 || COMPILE_TEST
depends on USB_MUSB_GADGET
depends on USB_OTG_BLACKLIST_HUB

View file

@ -608,7 +608,7 @@ static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume);
static struct platform_driver bfin_driver = {
.probe = bfin_probe,
.remove = __exit_p(bfin_remove),
.remove = bfin_remove,
.driver = {
.name = "musb-blackfin",
.pm = &bfin_pm_ops,

View file

@ -567,6 +567,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->xceiv->otg->state = OTG_STATE_A_HOST;
musb->is_active = 1;
musb_host_resume_root_hub(musb);
break;
case OTG_STATE_B_WAIT_ACON:
musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
@ -2500,6 +2501,12 @@ static int musb_runtime_resume(struct device *dev)
musb_restore_context(musb);
first = 0;
if (musb->need_finish_resume) {
musb->need_finish_resume = 0;
schedule_delayed_work(&musb->finish_resume_work,
msecs_to_jiffies(20));
}
return 0;
}

View file

@ -9,9 +9,9 @@
#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
#define EP_MODE_AUTOREG_NONE 0
#define EP_MODE_AUTOREG_ALL_NEOP 1
#define EP_MODE_AUTOREG_ALWAYS 3
#define EP_MODE_AUTOREQ_NONE 0
#define EP_MODE_AUTOREQ_ALL_NEOP 1
#define EP_MODE_AUTOREQ_ALWAYS 3
#define EP_MODE_DMA_TRANSPARENT 0
#define EP_MODE_DMA_RNDIS 1
@ -404,19 +404,19 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
/* auto req */
cppi41_set_autoreq_mode(cppi41_channel,
EP_MODE_AUTOREG_ALL_NEOP);
EP_MODE_AUTOREQ_ALL_NEOP);
} else {
musb_writel(musb->ctrl_base,
RNDIS_REG(cppi41_channel->port_num), 0);
cppi41_set_dma_mode(cppi41_channel,
EP_MODE_DMA_TRANSPARENT);
cppi41_set_autoreq_mode(cppi41_channel,
EP_MODE_AUTOREG_NONE);
EP_MODE_AUTOREQ_NONE);
}
} else {
/* fallback mode */
cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
len = min_t(u32, packet_sz, len);
}
cppi41_channel->prog_len = len;
@ -549,10 +549,15 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
csr &= ~MUSB_TXCSR_DMAENAB;
musb_writew(epio, MUSB_TXCSR, csr);
} else {
cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
csr = musb_readw(epio, MUSB_RXCSR);
csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
musb_writew(epio, MUSB_RXCSR, csr);
/* wait to drain cppi dma pipe line */
udelay(50);
csr = musb_readw(epio, MUSB_RXCSR);
if (csr & MUSB_RXCSR_RXPKTRDY) {
csr |= MUSB_RXCSR_FLUSHFIFO;
@ -566,13 +571,14 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
tdbit <<= 16;
do {
musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
if (is_tx)
musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
ret = dmaengine_terminate_all(cppi41_channel->dc);
} while (ret == -EAGAIN);
musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
if (is_tx) {
musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
csr = musb_readw(epio, MUSB_TXCSR);
if (csr & MUSB_TXCSR_TXPKTRDY) {
csr |= MUSB_TXCSR_FLUSHFIFO;

View file

@ -196,7 +196,7 @@ static ssize_t musb_test_mode_write(struct file *file,
memset(buf, 0x00, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (strstarts(buf, "force host"))

View file

@ -1612,9 +1612,7 @@ done:
static int
musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered)
{
struct musb *musb = gadget_to_musb(gadget);
musb->is_self_powered = !!is_selfpowered;
gadget->is_selfpowered = !!is_selfpowered;
return 0;
}

View file

@ -85,7 +85,7 @@ static int service_tx_status_request(
switch (recip) {
case USB_RECIP_DEVICE:
result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;
result[0] = musb->g.is_selfpowered << USB_DEVICE_SELF_POWERED;
result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
if (musb->g.is_otg) {
result[0] |= musb->g.b_hnp_enable

View file

@ -72,7 +72,6 @@ void musb_host_finish_resume(struct work_struct *work)
musb->xceiv->otg->state = OTG_STATE_A_HOST;
spin_unlock_irqrestore(&musb->lock, flags);
musb_host_resume_root_hub(musb);
}
void musb_port_suspend(struct musb *musb, bool do_suspend)
@ -349,8 +348,7 @@ int musb_hub_control(
desc->bDescriptorType = 0x29;
desc->bNbrPorts = 1;
desc->wHubCharacteristics = cpu_to_le16(
HUB_CHAR_INDV_PORT_LPSM /* per-port power switching */
HUB_CHAR_INDV_PORT_LPSM /* per-port power switching */
| HUB_CHAR_NO_OCPM /* no overcurrent reporting */
);
desc->bPwrOn2PwrGood = 5; /* msec/2 */

View file

@ -107,19 +107,6 @@ static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
#define fsl_writel(val, addr) writel(val, addr)
#endif /* CONFIG_PPC32 */
/* Routines to access transceiver ULPI registers */
u8 view_ulpi(u8 addr)
{
u32 temp;
temp = 0x40000000 | (addr << 16);
fsl_writel(temp, &usb_dr_regs->ulpiview);
udelay(1000);
while (temp & 0x40)
temp = fsl_readl(&usb_dr_regs->ulpiview);
return (le32_to_cpu(temp) & 0x0000ff00) >> 8;
}
int write_ulpi(u8 addr, u8 data)
{
u32 temp;
@ -460,28 +447,6 @@ static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
fsl_otg_del_timer(fsm, timer);
}
/*
* Reduce timer count by 1, and find timeout conditions.
* Called by fsl_otg 1ms timer interrupt
*/
int fsl_otg_tick_timer(void)
{
struct fsl_otg_timer *tmp_timer, *del_tmp;
int expired = 0;
list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
tmp_timer->count--;
/* check if timer expires */
if (!tmp_timer->count) {
list_del(&tmp_timer->list);
tmp_timer->function(tmp_timer->data);
expired = 1;
}
}
return expired;
}
/* Reset controller, not reset the bus */
void otg_reset_controller(void)
{

View file

@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/usb_phy_generic.h>
#include <linux/slab.h>
@ -39,6 +40,10 @@
#include "phy-generic.h"
#define VBUS_IRQ_FLAGS \
(IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | \
IRQF_ONESHOT)
struct platform_device *usb_phy_generic_register(void)
{
return platform_device_register_simple("usb_phy_generic",
@ -59,19 +64,79 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
static void nop_reset_set(struct usb_phy_generic *nop, int asserted)
{
int value;
if (!gpio_is_valid(nop->gpio_reset))
if (!nop->gpiod_reset)
return;
value = asserted;
if (nop->reset_active_low)
value = !value;
gpiod_direction_output(nop->gpiod_reset, !asserted);
usleep_range(10000, 20000);
gpiod_set_value(nop->gpiod_reset, asserted);
}
gpio_set_value_cansleep(nop->gpio_reset, value);
/* interface to regulator framework */
static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
{
struct regulator *vbus_draw = nop->vbus_draw;
int enabled;
int ret;
if (!asserted)
usleep_range(10000, 20000);
if (!vbus_draw)
return;
enabled = nop->vbus_draw_enabled;
if (mA) {
regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
if (!enabled) {
ret = regulator_enable(vbus_draw);
if (ret < 0)
return;
nop->vbus_draw_enabled = 1;
}
} else {
if (enabled) {
ret = regulator_disable(vbus_draw);
if (ret < 0)
return;
nop->vbus_draw_enabled = 0;
}
}
nop->mA = mA;
}
static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
{
struct usb_phy_generic *nop = data;
struct usb_otg *otg = nop->phy.otg;
int vbus, status;
vbus = gpiod_get_value(nop->gpiod_vbus);
if ((vbus ^ nop->vbus) == 0)
return IRQ_HANDLED;
nop->vbus = vbus;
if (vbus) {
status = USB_EVENT_VBUS;
otg->state = OTG_STATE_B_PERIPHERAL;
nop->phy.last_event = status;
usb_gadget_vbus_connect(otg->gadget);
/* drawing a "unit load" is *always* OK, except for OTG */
nop_set_vbus_draw(nop, 100);
atomic_notifier_call_chain(&nop->phy.notifier, status,
otg->gadget);
} else {
nop_set_vbus_draw(nop, 0);
usb_gadget_vbus_disconnect(otg->gadget);
status = USB_EVENT_NONE;
otg->state = OTG_STATE_B_IDLE;
nop->phy.last_event = status;
atomic_notifier_call_chain(&nop->phy.notifier, status,
otg->gadget);
}
return IRQ_HANDLED;
}
int usb_gen_phy_init(struct usb_phy *phy)
@ -143,37 +208,48 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
struct usb_phy_generic_platform_data *pdata)
{
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err;
int err = 0;
u32 clk_rate = 0;
bool needs_vcc = false;
nop->reset_active_low = true; /* default behaviour */
if (dev->of_node) {
struct device_node *node = dev->of_node;
enum of_gpio_flags flags = 0;
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
needs_vcc = of_property_read_bool(node, "vcc-supply");
nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
0, &flags);
if (nop->gpio_reset == -EPROBE_DEFER)
return -EPROBE_DEFER;
nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset");
err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
if (!err) {
nop->gpiod_vbus = devm_gpiod_get_optional(dev,
"vbus-detect");
err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
}
} else if (pdata) {
type = pdata->type;
clk_rate = pdata->clk_rate;
needs_vcc = pdata->needs_vcc;
nop->gpio_reset = pdata->gpio_reset;
} else {
nop->gpio_reset = -1;
if (gpio_is_valid(pdata->gpio_reset)) {
err = devm_gpio_request_one(dev, pdata->gpio_reset, 0,
dev_name(dev));
if (!err)
nop->gpiod_reset =
gpio_to_desc(pdata->gpio_reset);
}
nop->gpiod_vbus = pdata->gpiod_vbus;
}
if (err == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (err) {
dev_err(dev, "Error requesting RESET or VBUS GPIO\n");
return err;
}
if (nop->gpiod_reset)
gpiod_direction_output(nop->gpiod_reset, 1);
nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
GFP_KERNEL);
if (!nop->phy.otg)
@ -201,24 +277,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
return -EPROBE_DEFER;
}
if (gpio_is_valid(nop->gpio_reset)) {
unsigned long gpio_flags;
/* Assert RESET */
if (nop->reset_active_low)
gpio_flags = GPIOF_OUT_INIT_LOW;
else
gpio_flags = GPIOF_OUT_INIT_HIGH;
err = devm_gpio_request_one(dev, nop->gpio_reset,
gpio_flags, dev_name(dev));
if (err) {
dev_err(dev, "Error requesting RESET GPIO %d\n",
nop->gpio_reset);
return err;
}
}
nop->dev = dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
@ -247,6 +305,18 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev));
if (err)
return err;
if (nop->gpiod_vbus) {
err = devm_request_threaded_irq(&pdev->dev,
gpiod_to_irq(nop->gpiod_vbus),
NULL, nop_gpio_vbus_thread,
VBUS_IRQ_FLAGS, "vbus_detect",
nop);
if (err) {
dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
gpiod_to_irq(nop->gpiod_vbus), err);
return err;
}
}
nop->phy.init = usb_gen_phy_init;
nop->phy.shutdown = usb_gen_phy_shutdown;

View file

@ -2,14 +2,20 @@
#define _PHY_GENERIC_H_
#include <linux/usb/usb_phy_generic.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
struct usb_phy_generic {
struct usb_phy phy;
struct device *dev;
struct clk *clk;
struct regulator *vcc;
int gpio_reset;
bool reset_active_low;
struct gpio_desc *gpiod_reset;
struct gpio_desc *gpiod_vbus;
struct regulator *vbus_draw;
bool vbus_draw_enabled;
unsigned long mA;
unsigned int vbus;
};
int usb_gen_phy_init(struct usb_phy *phy);

View file

@ -40,6 +40,7 @@
#define BM_USBPHY_CTRL_SFTRST BIT(31)
#define BM_USBPHY_CTRL_CLKGATE BIT(30)
#define BM_USBPHY_CTRL_OTG_ID_VALUE BIT(27)
#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26)
#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25)
#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23)
@ -69,6 +70,9 @@
#define ANADIG_USB2_LOOPBACK_SET 0x244
#define ANADIG_USB2_LOOPBACK_CLR 0x248
#define ANADIG_USB1_MISC 0x1f0
#define ANADIG_USB2_MISC 0x250
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12)
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
@ -80,6 +84,11 @@
#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2)
#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5)
#define BM_ANADIG_USB1_MISC_RX_VPIN_FS BIT(29)
#define BM_ANADIG_USB1_MISC_RX_VMIN_FS BIT(28)
#define BM_ANADIG_USB2_MISC_RX_VPIN_FS BIT(29)
#define BM_ANADIG_USB2_MISC_RX_VMIN_FS BIT(28)
#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
/* Do disconnection between PHY and controller without vbus */
@ -131,8 +140,7 @@ static const struct mxs_phy_data vf610_phy_data = {
};
static const struct mxs_phy_data imx6sx_phy_data = {
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_NEED_IP_FIX,
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
};
static const struct of_device_id mxs_phy_dt_ids[] = {
@ -256,6 +264,18 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
usleep_range(500, 1000);
}
static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
{
void __iomem *base = mxs_phy->phy.io_priv;
u32 phyctrl = readl(base + HW_USBPHY_CTRL);
if (IS_ENABLED(CONFIG_USB_OTG) &&
!(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
return true;
return false;
}
static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
{
bool vbus_is_on = false;
@ -270,7 +290,7 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
if (on && !vbus_is_on)
if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
__mxs_phy_disconnect_line(mxs_phy, true);
else
__mxs_phy_disconnect_line(mxs_phy, false);
@ -293,6 +313,17 @@ static int mxs_phy_init(struct usb_phy *phy)
static void mxs_phy_shutdown(struct usb_phy *phy)
{
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
BM_USBPHY_CTRL_ENIDCHG_WKUP |
BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
BM_USBPHY_CTRL_ENAUTO_PWRON_PLL;
writel(value, phy->io_priv + HW_USBPHY_CTRL_CLR);
writel(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
writel(BM_USBPHY_CTRL_CLKGATE,
phy->io_priv + HW_USBPHY_CTRL_SET);
@ -300,13 +331,56 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
clk_disable_unprepare(mxs_phy->clk);
}
static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
{
unsigned int line_state;
/* bit definition is the same for all controllers */
unsigned int dp_bit = BM_ANADIG_USB1_MISC_RX_VPIN_FS,
dm_bit = BM_ANADIG_USB1_MISC_RX_VMIN_FS;
unsigned int reg = ANADIG_USB1_MISC;
/* If the SoCs don't have anatop, quit */
if (!mxs_phy->regmap_anatop)
return false;
if (mxs_phy->port_id == 0)
reg = ANADIG_USB1_MISC;
else if (mxs_phy->port_id == 1)
reg = ANADIG_USB2_MISC;
regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
if ((line_state & (dp_bit | dm_bit)) == dm_bit)
return true;
else
return false;
}
static int mxs_phy_suspend(struct usb_phy *x, int suspend)
{
int ret;
struct mxs_phy *mxs_phy = to_mxs_phy(x);
bool low_speed_connection, vbus_is_on;
low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
if (suspend) {
writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
/*
* FIXME: Do not power down RXPWD1PT1 bit for low speed
* connect. The low speed connection will have problem at
* very rare cases during usb suspend and resume process.
*/
if (low_speed_connection & vbus_is_on) {
/*
* If value to be set as pwd value is not 0xffffffff,
* several 32Khz cycles are needed.
*/
mxs_phy_clock_switch_delay();
writel(0xffbfffff, x->io_priv + HW_USBPHY_PWD);
} else {
writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
}
writel(BM_USBPHY_CTRL_CLKGATE,
x->io_priv + HW_USBPHY_CTRL_SET);
clk_disable_unprepare(mxs_phy->clk);
@ -359,7 +433,9 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
dev_dbg(phy->dev, "%s device has disconnected\n",
(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
if (speed == USB_SPEED_HIGH)
/* Sometimes, the speed is not high speed when the error occurs */
if (readl(phy->io_priv + HW_USBPHY_CTRL) &
BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
phy->io_priv + HW_USBPHY_CTRL_CLR);

View file

@ -363,6 +363,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
int id;
int enable;
int cable;
int ret;
/*
@ -376,6 +377,16 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
id = usbhs_platform_call(priv, get_id, pdev);
if (enable && !mod) {
if (priv->edev) {
cable = extcon_get_cable_state(priv->edev, "USB-HOST");
if ((cable > 0 && id != USBHS_HOST) ||
(!cable && id != USBHS_GADGET)) {
dev_info(&pdev->dev,
"USB cable plugged in doesn't match the selected role!\n");
return;
}
}
ret = usbhs_mod_change(priv, id);
if (ret < 0)
return;
@ -514,6 +525,12 @@ static int usbhs_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
if (IS_ERR(priv->edev))
return PTR_ERR(priv->edev);
}
/*
* care platform info
*/
@ -615,7 +632,7 @@ static int usbhs_probe(struct platform_device *pdev)
*/
ret = usbhs_platform_call(priv, hardware_init, pdev);
if (ret < 0) {
dev_err(&pdev->dev, "platform prove failed.\n");
dev_err(&pdev->dev, "platform init failed.\n");
goto probe_end_mod_exit;
}
@ -632,16 +649,12 @@ static int usbhs_probe(struct platform_device *pdev)
/*
* manual call notify_hotplug for cold plug
*/
ret = usbhsc_drvcllbck_notify_hotplug(pdev);
if (ret < 0)
goto probe_end_call_remove;
usbhsc_drvcllbck_notify_hotplug(pdev);
dev_info(&pdev->dev, "probed\n");
return ret;
probe_end_call_remove:
usbhs_platform_call(priv, hardware_exit, pdev);
probe_end_mod_exit:
usbhs_mod_remove(priv);
probe_end_fifo_exit:

View file

@ -17,6 +17,7 @@
#ifndef RENESAS_USB_DRIVER_H
#define RENESAS_USB_DRIVER_H
#include <linux/extcon.h>
#include <linux/platform_device.h>
#include <linux/usb/renesas_usbhs.h>
@ -254,6 +255,8 @@ struct usbhs_priv {
struct delayed_work notify_hotplug_work;
struct platform_device *pdev;
struct extcon_dev *edev;
spinlock_t lock;
u32 flags;

View file

@ -1054,10 +1054,8 @@ static void usbhsf_dma_quit(struct usbhs_priv *priv, struct usbhs_fifo *fifo)
fifo->rx_chan = NULL;
}
static void usbhsf_dma_init(struct usbhs_priv *priv,
struct usbhs_fifo *fifo)
static void usbhsf_dma_init_pdev(struct usbhs_fifo *fifo)
{
struct device *dev = usbhs_priv_to_dev(priv);
dma_cap_mask_t mask;
dma_cap_zero(mask);
@ -1069,6 +1067,27 @@ static void usbhsf_dma_init(struct usbhs_priv *priv,
dma_cap_set(DMA_SLAVE, mask);
fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter,
&fifo->rx_slave);
}
static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo)
{
fifo->tx_chan = dma_request_slave_channel_reason(dev, "tx");
if (IS_ERR(fifo->tx_chan))
fifo->tx_chan = NULL;
fifo->rx_chan = dma_request_slave_channel_reason(dev, "rx");
if (IS_ERR(fifo->rx_chan))
fifo->rx_chan = NULL;
}
static void usbhsf_dma_init(struct usbhs_priv *priv,
struct usbhs_fifo *fifo)
{
struct device *dev = usbhs_priv_to_dev(priv);
if (dev->of_node)
usbhsf_dma_init_dt(dev, fifo);
else
usbhsf_dma_init_pdev(fifo);
if (fifo->tx_chan || fifo->rx_chan)
dev_dbg(dev, "enable DMAEngine (%s%s%s)\n",

View file

@ -926,6 +926,8 @@ static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
else
usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED);
gadget->is_selfpowered = (is_self != 0);
return 0;
}