1
0
Fork 0

usb: patches for v4.4 merge window

This pull request is large with a total of 136 non-merge
 commits. Because of its size, we will only describe the big things in
 broad terms.
 
 Many will be happy to know that dwc3 is now almost twice as fast after
 some profiling and speed improvements. Also in dwc3, John Youn from
 Synopsys added support for their new DWC USB3.1 IP Core and the HAPS
 platform which can be used to validate it.
 
 A series of patches from Robert Baldyga cleaned up uses of
 ep->driver_data as a flag for "claimed endpoint" in favor of the new
 ep->claimed flag.
 
 Sudip Mukherjee fixed a ton of really old problems on the amd5536udc
 driver. That should make a few people happy.
 
 Heikki Krogerus worked on converting dwc3 to the unified device property
 interface.
 
 Together with these, there's a ton of non-critical fixes, typos and
 stuff like that.
 
 Signed-off-by: Felipe Balbi <balbi@ti.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWJoq5AAoJEIaOsuA1yqREOlkQAJTndRGxhcZR5rLzjyRDDags
 pYoXJAqaneq5G8BwKY+2AQlPaUr87UEHUOo8pk4S31mdFHlp/d/6YIXLpdlYbEcW
 ixGhtxZnUhyvWM0HYGgyoDGQP9YJXy5/MR2lEJhmsqcH/Q0dih5VrDGyJ3BxEboZ
 2jXy7iou5fs5nHsR4fpdUH+ER//oKgHopRbbt+mmCwZbRJbuukA0KVDMHO8ix6cy
 tG/8zbnv5RY3O4a0lJAST8LNmtpxfF9yUCs83b6muhLgO9GXUGYb+I8DjPJMbwag
 klOy8Z1bG5e4ymh6383ZG7wDITf82N5cy5huoyunQHVjYg1L8vDHa9aF72e+yR/3
 blb9OYALbKPV072HMwOfH+M9cvcCVDGytbJQIgMot9mjpP6GPhgbGtxb+RWNy2j8
 Z2kEaxd3BUXvWiRbvyvn7uQuT/cAF4StrTnQrsbFSt0fKAUkQnGdK7XxYfGGql97
 p3u2x2D7YSkurywMWyXjuBsm/mXsImAfTJvoWndyOIHU2PNAzIDM4k9TWaYNNAKA
 ilZSuSC/JVnMPEH/J/QpytxMM5wbiGyJOyI4bc4MiAXgCkG3qm8vi0PMZM8x0rEu
 q778B+50alg9U7/G75dt0WQP+kqDjn+iUB7i/YUC9sq/Dhlmpp48KvJU+zaco+7I
 QsxGXmlgeA7yXX8ywy71
 =jPoY
 -----END PGP SIGNATURE-----

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

Felipe writes:

usb: patches for v4.4 merge window

This pull request is large with a total of 136 non-merge
commits. Because of its size, we will only describe the big things in
broad terms.

Many will be happy to know that dwc3 is now almost twice as fast after
some profiling and speed improvements. Also in dwc3, John Youn from
Synopsys added support for their new DWC USB3.1 IP Core and the HAPS
platform which can be used to validate it.

A series of patches from Robert Baldyga cleaned up uses of
ep->driver_data as a flag for "claimed endpoint" in favor of the new
ep->claimed flag.

Sudip Mukherjee fixed a ton of really old problems on the amd5536udc
driver. That should make a few people happy.

Heikki Krogerus worked on converting dwc3 to the unified device property
interface.

Together with these, there's a ton of non-critical fixes, typos and
stuff like that.

Signed-off-by: Felipe Balbi <balbi@ti.com>
hifive-unleashed-5.1
Greg Kroah-Hartman 2015-10-22 17:19:33 -07:00
commit a4d8e93c31
74 changed files with 2758 additions and 2266 deletions

View File

@ -35,11 +35,16 @@ Optional properties:
LTSSM during USB3 Compliance mode.
- snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy.
- snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
- snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG,
disabling the suspend signal to the PHY.
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
utmi_l1_suspend_n, false when asserts utmi_sleep_n
- snps,hird-threshold: HIRD threshold
- snps,hsphy_interface: High-Speed PHY interface selection between "utmi" for
UTMI+ and "ulpi" for ULPI when the DWC_USB3_HSPHY_INTERFACE has value 3.
- snps,quirk-frame-length-adjustment: Value for GFLADJ_30MHZ field of GFLADJ
register for post-silicon frame length adjustment when the
fladj_30mhz_sdbnd signal is invalid or incorrect.
This is usually a subnode to DWC3 glue to which it is connected.

View File

@ -809,7 +809,7 @@ static const struct gpio_led_platform_data gpio_leds_pdata = {
.num_leds = ARRAY_SIZE(gpio_leds),
};
static struct s3c_hsotg_plat crag6410_hsotg_pdata;
static struct dwc2_hsotg_plat crag6410_hsotg_pdata;
static void __init crag6410_machine_init(void)
{
@ -835,7 +835,7 @@ static void __init crag6410_machine_init(void)
s3c_i2c0_set_platdata(&i2c0_pdata);
s3c_i2c1_set_platdata(&i2c1_pdata);
s3c_fb_set_platdata(&crag6410_lcd_pdata);
s3c_hsotg_set_platdata(&crag6410_hsotg_pdata);
dwc2_hsotg_set_platdata(&crag6410_hsotg_pdata);
i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));

View File

@ -189,7 +189,7 @@ static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = {
},
};
static struct s3c_hsotg_plat smartq_hsotg_pdata;
static struct dwc2_hsotg_plat smartq_hsotg_pdata;
static int __init smartq_lcd_setup_gpio(void)
{
@ -382,7 +382,7 @@ void __init smartq_map_io(void)
void __init smartq_machine_init(void)
{
s3c_i2c0_set_platdata(NULL);
s3c_hsotg_set_platdata(&smartq_hsotg_pdata);
dwc2_hsotg_set_platdata(&smartq_hsotg_pdata);
s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);

View File

@ -628,7 +628,7 @@ static struct platform_pwm_backlight_data smdk6410_bl_data = {
.enable_gpio = -1,
};
static struct s3c_hsotg_plat smdk6410_hsotg_pdata;
static struct dwc2_hsotg_plat smdk6410_hsotg_pdata;
static void __init smdk6410_map_io(void)
{
@ -659,7 +659,7 @@ static void __init smdk6410_machine_init(void)
s3c_i2c0_set_platdata(NULL);
s3c_i2c1_set_platdata(NULL);
s3c_fb_set_platdata(&smdk6410_lcd_pdata);
s3c_hsotg_set_platdata(&smdk6410_hsotg_pdata);
dwc2_hsotg_set_platdata(&smdk6410_hsotg_pdata);
samsung_keypad_set_platdata(&smdk6410_keypad_data);

View File

@ -1042,11 +1042,11 @@ struct platform_device s3c_device_usb_hsotg = {
},
};
void __init s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd)
void __init dwc2_hsotg_set_platdata(struct dwc2_hsotg_plat *pd)
{
struct s3c_hsotg_plat *npd;
struct dwc2_hsotg_plat *npd;
npd = s3c_set_platdata(pd, sizeof(struct s3c_hsotg_plat),
npd = s3c_set_platdata(pd, sizeof(struct dwc2_hsotg_plat),
&s3c_device_usb_hsotg);
if (!npd->phy_init)

View File

@ -611,7 +611,7 @@ static int ci_get_platdata(struct device *dev,
platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
if (!platdata->dr_mode)
platdata->dr_mode = of_usb_get_dr_mode(dev->of_node);
platdata->dr_mode = usb_get_dr_mode(dev);
if (platdata->dr_mode == USB_DR_MODE_UNKNOWN)
platdata->dr_mode = USB_DR_MODE_OTG;
@ -648,7 +648,7 @@ static int ci_get_platdata(struct device *dev,
return ret;
}
if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL)
if (usb_get_maximum_speed(dev) == USB_SPEED_FULL)
platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
platdata->itc_setting = 1;

View File

@ -60,6 +60,24 @@ const char *usb_speed_string(enum usb_device_speed speed)
}
EXPORT_SYMBOL_GPL(usb_speed_string);
enum usb_device_speed usb_get_maximum_speed(struct device *dev)
{
const char *maximum_speed;
int err;
int i;
err = device_property_read_string(dev, "maximum-speed", &maximum_speed);
if (err < 0)
return USB_SPEED_UNKNOWN;
for (i = 0; i < ARRAY_SIZE(speed_names); i++)
if (strcmp(maximum_speed, speed_names[i]) == 0)
return i;
return USB_SPEED_UNKNOWN;
}
EXPORT_SYMBOL_GPL(usb_get_maximum_speed);
const char *usb_state_string(enum usb_device_state state)
{
static const char *const names[] = {
@ -81,7 +99,6 @@ const char *usb_state_string(enum usb_device_state state)
}
EXPORT_SYMBOL_GPL(usb_state_string);
#ifdef CONFIG_OF
static const char *const usb_dr_modes[] = {
[USB_DR_MODE_UNKNOWN] = "",
[USB_DR_MODE_HOST] = "host",
@ -89,19 +106,12 @@ static const char *const usb_dr_modes[] = {
[USB_DR_MODE_OTG] = "otg",
};
/**
* of_usb_get_dr_mode - Get dual role mode for given device_node
* @np: Pointer to the given device_node
*
* The function gets phy interface string from property 'dr_mode',
* and returns the correspondig enum usb_dr_mode
*/
enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
enum usb_dr_mode usb_get_dr_mode(struct device *dev)
{
const char *dr_mode;
int err, i;
err = of_property_read_string(np, "dr_mode", &dr_mode);
err = device_property_read_string(dev, "dr_mode", &dr_mode);
if (err < 0)
return USB_DR_MODE_UNKNOWN;
@ -111,34 +121,9 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
return USB_DR_MODE_UNKNOWN;
}
EXPORT_SYMBOL_GPL(of_usb_get_dr_mode);
/**
* of_usb_get_maximum_speed - Get maximum requested speed for a given USB
* controller.
* @np: Pointer to the given device_node
*
* The function gets the maximum speed string from property "maximum-speed",
* and returns the corresponding enum usb_device_speed.
*/
enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np)
{
const char *maximum_speed;
int err;
int i;
err = of_property_read_string(np, "maximum-speed", &maximum_speed);
if (err < 0)
return USB_SPEED_UNKNOWN;
for (i = 0; i < ARRAY_SIZE(speed_names); i++)
if (strcmp(maximum_speed, speed_names[i]) == 0)
return i;
return USB_SPEED_UNKNOWN;
}
EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed);
EXPORT_SYMBOL_GPL(usb_get_dr_mode);
#ifdef CONFIG_OF
/**
* of_usb_host_tpl_support - to get if Targeted Peripheral List is supported
* for given targeted hosts (non-PC hosts)

File diff suppressed because it is too large Load Diff

View File

@ -44,22 +44,38 @@
#include <linux/usb/phy.h>
#include "hw.h"
#ifdef DWC2_LOG_WRITES
static inline void do_write(u32 value, void *addr)
static inline u32 dwc2_readl(const void __iomem *addr)
{
writel(value, addr);
pr_info("INFO:: wrote %08x to %p\n", value, addr);
u32 value = __raw_readl(addr);
/* In order to preserve endianness __raw_* operation is used. Therefore
* a barrier is needed to ensure IO access is not re-ordered across
* reads or writes
*/
mb();
return value;
}
#undef writel
#define writel(v, a) do_write(v, a)
static inline void dwc2_writel(u32 value, void __iomem *addr)
{
__raw_writel(value, addr);
/*
* In order to preserve endianness __raw_* operation is used. Therefore
* a barrier is needed to ensure IO access is not re-ordered across
* reads or writes
*/
mb();
#ifdef DWC2_LOG_WRITES
pr_info("INFO:: wrote %08x to %p\n", value, addr);
#endif
}
/* Maximum number of Endpoints/HostChannels */
#define MAX_EPS_CHANNELS 16
/* s3c-hsotg declarations */
static const char * const s3c_hsotg_supply_names[] = {
/* dwc2-hsotg declarations */
static const char * const dwc2_hsotg_supply_names[] = {
"vusb_d", /* digital USB supply, 1.2V */
"vusb_a", /* analog USB supply, 1.1V */
};
@ -85,10 +101,10 @@ static const char * const s3c_hsotg_supply_names[] = {
#define EP0_MPS_LIMIT 64
struct dwc2_hsotg;
struct s3c_hsotg_req;
struct dwc2_hsotg_req;
/**
* struct s3c_hsotg_ep - driver endpoint definition.
* struct dwc2_hsotg_ep - driver endpoint definition.
* @ep: The gadget layer representation of the endpoint.
* @name: The driver generated name for the endpoint.
* @queue: Queue of requests for this endpoint.
@ -127,11 +143,11 @@ struct s3c_hsotg_req;
* as in shared-fifo mode periodic in acts like a single-frame packet
* buffer than a fifo)
*/
struct s3c_hsotg_ep {
struct dwc2_hsotg_ep {
struct usb_ep ep;
struct list_head queue;
struct dwc2_hsotg *parent;
struct s3c_hsotg_req *req;
struct dwc2_hsotg_req *req;
struct dentry *debugfs;
unsigned long total_data;
@ -150,17 +166,18 @@ struct s3c_hsotg_ep {
unsigned int periodic:1;
unsigned int isochronous:1;
unsigned int send_zlp:1;
unsigned int has_correct_parity:1;
char name[10];
};
/**
* struct s3c_hsotg_req - data transfer request
* struct dwc2_hsotg_req - data transfer request
* @req: The USB gadget request
* @queue: The list of requests for the endpoint this is queued for.
* @saved_req_buf: variable to save req.buf when bounce buffers are used.
*/
struct s3c_hsotg_req {
struct dwc2_hsotg_req {
struct usb_request req;
struct list_head queue;
void *saved_req_buf;
@ -562,6 +579,15 @@ struct dwc2_hregs_backup {
* - USB_DR_MODE_PERIPHERAL
* - USB_DR_MODE_HOST
* - USB_DR_MODE_OTG
* @hcd_enabled Host mode sub-driver initialization indicator.
* @gadget_enabled Peripheral mode sub-driver initialization indicator.
* @ll_hw_enabled Status of low-level hardware resources.
* @phy: The otg phy transceiver structure for phy control.
* @uphy: The otg phy transceiver structure for old USB phy control.
* @plat: The platform specific configuration data. This can be removed once
* all SoCs support usb transceiver.
* @supplies: Definition of USB power supplies
* @phyif: PHY interface width
* @lock: Spinlock that protects all the driver data structures
* @priv: Stores a pointer to the struct usb_hcd
* @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
@ -654,12 +680,6 @@ struct dwc2_hregs_backup {
* These are for peripheral mode:
*
* @driver: USB gadget driver
* @phy: The otg phy transceiver structure for phy control.
* @uphy: The otg phy transceiver structure for old USB phy control.
* @plat: The platform specific configuration data. This can be removed once
* all SoCs support usb transceiver.
* @supplies: Definition of USB power supplies
* @phyif: PHY interface width
* @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
* @num_of_eps: Number of available EPs (excluding EP0)
* @debug_root: Root directrory for debugfs.
@ -672,7 +692,6 @@ struct dwc2_hregs_backup {
* @ctrl_req: Request for EP0 control packets.
* @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
@ -690,13 +709,15 @@ struct dwc2_hsotg {
enum usb_dr_mode dr_mode;
unsigned int hcd_enabled:1;
unsigned int gadget_enabled:1;
unsigned int ll_hw_enabled:1;
struct phy *phy;
struct usb_phy *uphy;
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
struct dwc2_hsotg_plat *plat;
struct regulator_bulk_data supplies[ARRAY_SIZE(dwc2_hsotg_supply_names)];
u32 phyif;
spinlock_t lock;
struct mutex init_mutex;
void *priv;
int irq;
struct clk *clk;
@ -748,6 +769,7 @@ struct dwc2_hsotg {
u16 frame_usecs[8];
u16 frame_number;
u16 periodic_qh_count;
bool bus_suspended;
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
#define FRAME_NUM_ARRAY_SIZE 1000
@ -796,9 +818,6 @@ struct dwc2_hsotg {
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
/* Gadget structures */
struct usb_gadget_driver *driver;
struct s3c_hsotg_plat *plat;
u32 phyif;
int fifo_mem;
unsigned int dedicated_fifos:1;
unsigned char num_of_eps;
@ -814,9 +833,8 @@ struct dwc2_hsotg {
struct usb_gadget gadget;
unsigned int enabled:1;
unsigned int connected:1;
unsigned long last_rst;
struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
struct dwc2_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
struct dwc2_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
u32 g_using_dma;
u32 g_rx_fifo_sz;
u32 g_np_g_tx_fifo_sz;
@ -1088,7 +1106,8 @@ extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg);
extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg);
/*
* Dump core registers and SPRAM
@ -1104,30 +1123,30 @@ extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg);
/* Gadget defines */
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
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_hsotg_remove(struct dwc2_hsotg *hsotg);
extern int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2);
extern int dwc2_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 dwc2_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);
extern int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
extern void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg);
extern void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
extern int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
#define dwc2_is_device_connected(hsotg) (hsotg->connected)
#else
static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
{ return 0; }
static inline int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2)
static inline int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2)
{ return 0; }
static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
static inline int dwc2_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 dwc2_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) {}
static inline int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
static inline void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
int testmode)
{ return 0; }
#define dwc2_is_device_connected(hsotg) (0)

View File

@ -80,15 +80,15 @@ static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
*/
static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
{
u32 hprt0 = readl(hsotg->regs + HPRT0);
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
if (hprt0 & HPRT0_ENACHG) {
hprt0 &= ~HPRT0_ENA;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
}
/* Clear interrupt */
writel(GINTSTS_PRTINT, hsotg->regs + GINTSTS);
dwc2_writel(GINTSTS_PRTINT, hsotg->regs + GINTSTS);
}
/**
@ -102,7 +102,7 @@ static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
/* Clear interrupt */
writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
dwc2_writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
}
/**
@ -117,8 +117,8 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
u32 gotgctl;
u32 gintmsk;
gotgint = readl(hsotg->regs + GOTGINT);
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgint = dwc2_readl(hsotg->regs + GOTGINT);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
dwc2_op_state_str(hsotg));
@ -126,10 +126,10 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev,
" ++OTG Interrupt: Session End Detected++ (%s)\n",
dwc2_op_state_str(hsotg));
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
if (dwc2_is_device_mode(hsotg))
s3c_hsotg_disconnect(hsotg);
dwc2_hsotg_disconnect(hsotg);
if (hsotg->op_state == OTG_STATE_B_HOST) {
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
@ -152,15 +152,15 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
hsotg->lx_state = DWC2_L0;
}
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
gotgctl &= ~GOTGCTL_DEVHNPEN;
writel(gotgctl, hsotg->regs + GOTGCTL);
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
}
if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
dev_dbg(hsotg->dev,
" ++OTG Interrupt: Session Request Success Status Change++\n");
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
if (gotgctl & GOTGCTL_SESREQSCS) {
if (hsotg->core_params->phy_type ==
DWC2_PHY_TYPE_PARAM_FS
@ -168,9 +168,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
hsotg->srp_success = 1;
} else {
/* Clear Session Request */
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
gotgctl &= ~GOTGCTL_SESREQ;
writel(gotgctl, hsotg->regs + GOTGCTL);
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
}
}
}
@ -180,7 +180,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
* Print statements during the HNP interrupt handling
* can cause it to fail
*/
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
/*
* WA for 3.00a- HW is not setting cur_mode, even sometimes
* this does not help
@ -200,9 +200,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
* interrupt does not get handled and Linux
* complains loudly.
*/
gintmsk = readl(hsotg->regs + GINTMSK);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_SOF;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
/*
* Call callback function with spin lock
@ -216,9 +216,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
hsotg->op_state = OTG_STATE_B_HOST;
}
} else {
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
writel(gotgctl, hsotg->regs + GOTGCTL);
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
dev_dbg(hsotg->dev, "HNP Failed\n");
dev_err(hsotg->dev,
"Device Not Connected/Responding\n");
@ -244,9 +244,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
hsotg->op_state = OTG_STATE_A_PERIPHERAL;
} else {
/* Need to disable SOF interrupt immediately */
gintmsk = readl(hsotg->regs + GINTMSK);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_SOF;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
spin_unlock(&hsotg->lock);
dwc2_hcd_start(hsotg);
spin_lock(&hsotg->lock);
@ -261,7 +261,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
/* Clear GOTGINT */
writel(gotgint, hsotg->regs + GOTGINT);
dwc2_writel(gotgint, hsotg->regs + GOTGINT);
}
/**
@ -276,11 +276,11 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
*/
static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
{
u32 gintmsk = readl(hsotg->regs + GINTMSK);
u32 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
/* Need to disable SOF interrupt immediately */
gintmsk &= ~GINTSTS_SOF;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
@ -297,7 +297,7 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
}
/* Clear interrupt */
writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
}
/**
@ -313,16 +313,28 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
*/
static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
{
dev_dbg(hsotg->dev, "++Session Request Interrupt++\n");
int ret;
dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
hsotg->lx_state);
/* Clear interrupt */
writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
/*
* Report disconnect if there is any previous session established
*/
if (dwc2_is_device_mode(hsotg))
s3c_hsotg_disconnect(hsotg);
if (dwc2_is_device_mode(hsotg)) {
if (hsotg->lx_state == DWC2_L2) {
ret = dwc2_exit_hibernation(hsotg, true);
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev,
"exit hibernation failed\n");
}
/*
* Report disconnect if there is any previous session
* established
*/
dwc2_hsotg_disconnect(hsotg);
}
}
/*
@ -339,13 +351,14 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev, "DSTS=0x%0x\n", readl(hsotg->regs + DSTS));
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
dwc2_readl(hsotg->regs + DSTS));
if (hsotg->lx_state == DWC2_L2) {
u32 dctl = readl(hsotg->regs + DCTL);
u32 dctl = dwc2_readl(hsotg->regs + DCTL);
/* Clear Remote Wakeup Signaling */
dctl &= ~DCTL_RMTWKUPSIG;
writel(dctl, hsotg->regs + DCTL);
dwc2_writel(dctl, hsotg->regs + DCTL);
ret = dwc2_exit_hibernation(hsotg, true);
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev, "exit hibernation failed\n");
@ -355,12 +368,16 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
} else {
if (hsotg->core_params->hibernation) {
dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
return;
}
if (hsotg->lx_state != DWC2_L1) {
u32 pcgcctl = readl(hsotg->regs + PCGCTL);
u32 pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
/* Restart the Phy Clock */
pcgcctl &= ~PCGCTL_STOPPCLK;
writel(pcgcctl, hsotg->regs + PCGCTL);
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
mod_timer(&hsotg->wkp_timer,
jiffies + msecs_to_jiffies(71));
} else {
@ -370,7 +387,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
}
/* Clear interrupt */
writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
}
/*
@ -386,10 +403,7 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
if (hsotg->op_state == OTG_STATE_A_HOST)
dwc2_hcd_disconnect(hsotg);
/* Change to L3 (OFF) state */
hsotg->lx_state = DWC2_L3;
writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
}
/*
@ -412,7 +426,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
* Check the Device status register to determine if the Suspend
* state is active
*/
dsts = readl(hsotg->regs + DSTS);
dsts = dwc2_readl(hsotg->regs + DSTS);
dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
dev_dbg(hsotg->dev,
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
@ -465,7 +479,7 @@ skip_power_saving:
clear_int:
/* Clear interrupt */
writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
}
#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \
@ -483,9 +497,9 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
u32 gahbcfg;
u32 gintmsk_common = GINTMSK_COMMON;
gintsts = readl(hsotg->regs + GINTSTS);
gintmsk = readl(hsotg->regs + GINTMSK);
gahbcfg = readl(hsotg->regs + GAHBCFG);
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
/* If any common interrupts set */
if (gintsts & gintmsk_common)

View File

@ -57,7 +57,7 @@ static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
testmode = 0;
spin_lock_irqsave(&hsotg->lock, flags);
s3c_hsotg_set_test_mode(hsotg, testmode);
dwc2_hsotg_set_test_mode(hsotg, testmode);
spin_unlock_irqrestore(&hsotg->lock, flags);
return count;
}
@ -76,7 +76,7 @@ static int testmode_show(struct seq_file *s, void *unused)
int dctl;
spin_lock_irqsave(&hsotg->lock, flags);
dctl = readl(hsotg->regs + DCTL);
dctl = dwc2_readl(hsotg->regs + DCTL);
dctl &= DCTL_TSTCTL_MASK;
dctl >>= DCTL_TSTCTL_SHIFT;
spin_unlock_irqrestore(&hsotg->lock, flags);
@ -137,38 +137,38 @@ static int state_show(struct seq_file *seq, void *v)
int idx;
seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
readl(regs + DCFG),
readl(regs + DCTL),
readl(regs + DSTS));
dwc2_readl(regs + DCFG),
dwc2_readl(regs + DCTL),
dwc2_readl(regs + DSTS));
seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
readl(regs + DIEPMSK), readl(regs + DOEPMSK));
dwc2_readl(regs + DIEPMSK), dwc2_readl(regs + DOEPMSK));
seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
readl(regs + GINTMSK),
readl(regs + GINTSTS));
dwc2_readl(regs + GINTMSK),
dwc2_readl(regs + GINTSTS));
seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
readl(regs + DAINTMSK),
readl(regs + DAINT));
dwc2_readl(regs + DAINTMSK),
dwc2_readl(regs + DAINT));
seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
readl(regs + GNPTXSTS),
readl(regs + GRXSTSR));
dwc2_readl(regs + GNPTXSTS),
dwc2_readl(regs + GRXSTSR));
seq_puts(seq, "\nEndpoint status:\n");
for (idx = 0; idx < hsotg->num_of_eps; idx++) {
u32 in, out;
in = readl(regs + DIEPCTL(idx));
out = readl(regs + DOEPCTL(idx));
in = dwc2_readl(regs + DIEPCTL(idx));
out = dwc2_readl(regs + DOEPCTL(idx));
seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
idx, in, out);
in = readl(regs + DIEPTSIZ(idx));
out = readl(regs + DOEPTSIZ(idx));
in = dwc2_readl(regs + DIEPTSIZ(idx));
out = dwc2_readl(regs + DOEPTSIZ(idx));
seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
in, out);
@ -208,9 +208,9 @@ static int fifo_show(struct seq_file *seq, void *v)
int idx;
seq_puts(seq, "Non-periodic FIFOs:\n");
seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ));
seq_printf(seq, "RXFIFO: Size %d\n", dwc2_readl(regs + GRXFSIZ));
val = readl(regs + GNPTXFSIZ);
val = dwc2_readl(regs + GNPTXFSIZ);
seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
val >> FIFOSIZE_DEPTH_SHIFT,
val & FIFOSIZE_DEPTH_MASK);
@ -218,7 +218,7 @@ static int fifo_show(struct seq_file *seq, void *v)
seq_puts(seq, "\nPeriodic TXFIFOs:\n");
for (idx = 1; idx < hsotg->num_of_eps; idx++) {
val = readl(regs + DPTXFSIZN(idx));
val = dwc2_readl(regs + DPTXFSIZN(idx));
seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
val >> FIFOSIZE_DEPTH_SHIFT,
@ -256,9 +256,9 @@ static const char *decode_direction(int is_in)
*/
static int ep_show(struct seq_file *seq, void *v)
{
struct s3c_hsotg_ep *ep = seq->private;
struct dwc2_hsotg_ep *ep = seq->private;
struct dwc2_hsotg *hsotg = ep->parent;
struct s3c_hsotg_req *req;
struct dwc2_hsotg_req *req;
void __iomem *regs = hsotg->regs;
int index = ep->index;
int show_limit = 15;
@ -270,20 +270,20 @@ static int ep_show(struct seq_file *seq, void *v)
/* first show the register state */
seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
readl(regs + DIEPCTL(index)),
readl(regs + DOEPCTL(index)));
dwc2_readl(regs + DIEPCTL(index)),
dwc2_readl(regs + DOEPCTL(index)));
seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
readl(regs + DIEPDMA(index)),
readl(regs + DOEPDMA(index)));
dwc2_readl(regs + DIEPDMA(index)),
dwc2_readl(regs + DOEPDMA(index)));
seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
readl(regs + DIEPINT(index)),
readl(regs + DOEPINT(index)));
dwc2_readl(regs + DIEPINT(index)),
dwc2_readl(regs + DOEPINT(index)));
seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
readl(regs + DIEPTSIZ(index)),
readl(regs + DOEPTSIZ(index)));
dwc2_readl(regs + DIEPTSIZ(index)),
dwc2_readl(regs + DOEPTSIZ(index)));
seq_puts(seq, "\n");
seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
@ -326,7 +326,7 @@ static const struct file_operations ep_fops = {
};
/**
* s3c_hsotg_create_debug - create debugfs directory and files
* dwc2_hsotg_create_debug - create debugfs directory and files
* @hsotg: The driver state
*
* Create the debugfs files to allow the user to get information
@ -334,7 +334,7 @@ static const struct file_operations ep_fops = {
* with the same name as the device itself, in case we end up
* with multiple blocks in future systems.
*/
static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg)
{
struct dentry *root;
struct dentry *file;
@ -360,7 +360,7 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
/* Create one file for each out endpoint */
for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
struct s3c_hsotg_ep *ep;
struct dwc2_hsotg_ep *ep;
ep = hsotg->eps_out[epidx];
if (ep) {
@ -373,7 +373,7 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
}
/* Create one file for each in endpoint. EP0 is handled with out eps */
for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) {
struct s3c_hsotg_ep *ep;
struct dwc2_hsotg_ep *ep;
ep = hsotg->eps_in[epidx];
if (ep) {
@ -386,10 +386,10 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
}
}
#else
static inline void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) {}
#endif
/* s3c_hsotg_delete_debug is removed as cleanup in done in dwc2_debugfs_exit */
/* dwc2_hsotg_delete_debug is removed as cleanup in done in dwc2_debugfs_exit */
#define dump_register(nm) \
{ \
@ -737,7 +737,7 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg)
}
/* Add gadget debugfs nodes */
s3c_hsotg_create_debug(hsotg);
dwc2_hsotg_create_debug(hsotg);
hsotg->regset = devm_kzalloc(hsotg->dev, sizeof(*hsotg->regset),
GFP_KERNEL);

File diff suppressed because it is too large Load Diff

View File

@ -80,10 +80,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
if (chan == NULL)
return;
hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num));
hctsiz = readl(hsotg->regs + HCTSIZ(chan->hc_num));
hc_dma = readl(hsotg->regs + HCDMA(chan->hc_num));
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chan->hc_num));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chan->hc_num));
hc_dma = dwc2_readl(hsotg->regs + HCDMA(chan->hc_num));
dev_dbg(hsotg->dev, " Assigned to channel %p:\n", chan);
dev_dbg(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n",
@ -134,7 +134,7 @@ static void dwc2_kill_urbs_in_qh_list(struct dwc2_hsotg *hsotg,
list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
qtd_list_entry) {
dwc2_host_complete(hsotg, qtd, -ETIMEDOUT);
dwc2_host_complete(hsotg, qtd, -ECONNRESET);
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
}
}
@ -207,7 +207,7 @@ void dwc2_hcd_start(struct dwc2_hsotg *hsotg)
*/
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RST;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
}
queue_delayed_work(hsotg->wq_otg, &hsotg->start_work,
@ -228,11 +228,11 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
channel = hsotg->hc_ptr_array[i];
if (!list_empty(&channel->hc_list_entry))
continue;
hcchar = readl(hsotg->regs + HCCHAR(i));
hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
if (hcchar & HCCHAR_CHENA) {
hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR);
hcchar |= HCCHAR_CHDIS;
writel(hcchar, hsotg->regs + HCCHAR(i));
dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
}
}
}
@ -241,11 +241,11 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
channel = hsotg->hc_ptr_array[i];
if (!list_empty(&channel->hc_list_entry))
continue;
hcchar = readl(hsotg->regs + HCCHAR(i));
hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
if (hcchar & HCCHAR_CHENA) {
/* Halt the channel */
hcchar |= HCCHAR_CHDIS;
writel(hcchar, hsotg->regs + HCCHAR(i));
dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
}
dwc2_hc_cleanup(hsotg, channel);
@ -287,11 +287,11 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
* interrupt mask and status bits and disabling subsequent host
* channel interrupts.
*/
intr = readl(hsotg->regs + GINTMSK);
intr = dwc2_readl(hsotg->regs + GINTMSK);
intr &= ~(GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT);
writel(intr, hsotg->regs + GINTMSK);
dwc2_writel(intr, hsotg->regs + GINTMSK);
intr = GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT;
writel(intr, hsotg->regs + GINTSTS);
dwc2_writel(intr, hsotg->regs + GINTSTS);
/*
* Turn off the vbus power only if the core has transitioned to device
@ -301,7 +301,7 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
if (dwc2_is_device_mode(hsotg)) {
if (hsotg->op_state != OTG_STATE_A_SUSPEND) {
dev_dbg(hsotg->dev, "Disconnect: PortPower off\n");
writel(0, hsotg->regs + HPRT0);
dwc2_writel(0, hsotg->regs + HPRT0);
}
dwc2_disable_host_interrupts(hsotg);
@ -354,7 +354,7 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
/* Turn off the vbus power */
dev_dbg(hsotg->dev, "PortPower off\n");
writel(0, hsotg->regs + HPRT0);
dwc2_writel(0, hsotg->regs + HPRT0);
}
/* Caller must hold driver lock */
@ -378,7 +378,7 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
if ((dev_speed == USB_SPEED_LOW) &&
(hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) &&
(hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI)) {
u32 hprt0 = readl(hsotg->regs + HPRT0);
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
u32 prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
if (prtspd == HPRT0_SPD_FULL_SPEED)
@ -397,7 +397,7 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
return retval;
}
intr_mask = readl(hsotg->regs + GINTMSK);
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
if (!(intr_mask & GINTSTS_SOF)) {
enum dwc2_transaction_type tr_type;
@ -1070,7 +1070,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
if (dbg_perio())
dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
tx_status = readl(hsotg->regs + HPTXSTS);
tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
TXSTS_QSPCAVAIL_SHIFT;
fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
@ -1085,7 +1085,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
qh_ptr = hsotg->periodic_sched_assigned.next;
while (qh_ptr != &hsotg->periodic_sched_assigned) {
tx_status = readl(hsotg->regs + HPTXSTS);
tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
TXSTS_QSPCAVAIL_SHIFT;
if (qspcavail == 0) {
@ -1145,7 +1145,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
}
if (hsotg->core_params->dma_enable <= 0) {
tx_status = readl(hsotg->regs + HPTXSTS);
tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
TXSTS_QSPCAVAIL_SHIFT;
fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
@ -1168,9 +1168,9 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
* level to ensure that new requests are loaded as
* soon as possible.)
*/
gintmsk = readl(hsotg->regs + GINTMSK);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk |= GINTSTS_PTXFEMP;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
} else {
/*
* Disable the Tx FIFO empty interrupt since there are
@ -1179,9 +1179,9 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
* handlers to queue more transactions as transfer
* states change.
*/
gintmsk = readl(hsotg->regs + GINTMSK);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_PTXFEMP;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
}
}
}
@ -1210,7 +1210,7 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
tx_status = readl(hsotg->regs + GNPTXSTS);
tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
TXSTS_QSPCAVAIL_SHIFT;
fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
@ -1233,7 +1233,7 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
* available in the request queue or the Tx FIFO
*/
do {
tx_status = readl(hsotg->regs + GNPTXSTS);
tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
TXSTS_QSPCAVAIL_SHIFT;
if (hsotg->core_params->dma_enable <= 0 && qspcavail == 0) {
@ -1270,7 +1270,7 @@ next:
} while (hsotg->non_periodic_qh_ptr != orig_qh_ptr);
if (hsotg->core_params->dma_enable <= 0) {
tx_status = readl(hsotg->regs + GNPTXSTS);
tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
TXSTS_QSPCAVAIL_SHIFT;
fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
@ -1290,9 +1290,9 @@ next:
* level to ensure that new requests are loaded as
* soon as possible.)
*/
gintmsk = readl(hsotg->regs + GINTMSK);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk |= GINTSTS_NPTXFEMP;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
} else {
/*
* Disable the Tx FIFO empty interrupt since there are
@ -1301,9 +1301,9 @@ next:
* handlers to queue more transactions as transfer
* states change.
*/
gintmsk = readl(hsotg->regs + GINTMSK);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_NPTXFEMP;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
}
}
}
@ -1341,10 +1341,10 @@ void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
* Ensure NP Tx FIFO empty interrupt is disabled when
* there are no non-periodic transfers to process
*/
u32 gintmsk = readl(hsotg->regs + GINTMSK);
u32 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_NPTXFEMP;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
}
}
}
@ -1355,10 +1355,11 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
wf_otg);
u32 count = 0;
u32 gotgctl;
unsigned long flags;
dev_dbg(hsotg->dev, "%s()\n", __func__);
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl);
dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n",
!!(gotgctl & GOTGCTL_CONID_B));
@ -1382,8 +1383,10 @@ 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, false);
s3c_hsotg_core_connect(hsotg);
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_core_init_disconnected(hsotg, false);
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hsotg_core_connect(hsotg);
} else {
/* A-Device connector (Host Mode) */
dev_dbg(hsotg->dev, "connId A\n");
@ -1421,10 +1424,11 @@ static void dwc2_wakeup_detected(unsigned long data)
hprt0 = dwc2_read_hprt0(hsotg);
dev_dbg(hsotg->dev, "Resume: HPRT0=%0x\n", hprt0);
hprt0 &= ~HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
readl(hsotg->regs + HPRT0));
dwc2_readl(hsotg->regs + HPRT0));
hsotg->bus_suspended = 0;
dwc2_hcd_rem_wakeup(hsotg);
/* Change to L0 state */
@ -1451,30 +1455,35 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
spin_lock_irqsave(&hsotg->lock, flags);
if (windex == hsotg->otg_port && dwc2_host_is_b_hnp_enabled(hsotg)) {
gotgctl = readl(hsotg->regs + GOTGCTL);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
gotgctl |= GOTGCTL_HSTSETHNPEN;
writel(gotgctl, hsotg->regs + GOTGCTL);
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
hsotg->op_state = OTG_STATE_A_SUSPEND;
}
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_SUSP;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
/* Update lx_state */
hsotg->lx_state = DWC2_L2;
hsotg->bus_suspended = 1;
/* Suspend the Phy Clock */
pcgctl = readl(hsotg->regs + PCGCTL);
pcgctl |= PCGCTL_STOPPCLK;
writel(pcgctl, hsotg->regs + PCGCTL);
udelay(10);
/*
* If hibernation is supported, Phy clock will be suspended
* after registers are backuped.
*/
if (!hsotg->core_params->hibernation) {
/* Suspend the Phy Clock */
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgctl |= PCGCTL_STOPPCLK;
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
udelay(10);
}
/* For HNP the bus must be suspended for at least 200ms */
if (dwc2_host_is_b_hnp_enabled(hsotg)) {
pcgctl = readl(hsotg->regs + PCGCTL);
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgctl &= ~PCGCTL_STOPPCLK;
writel(pcgctl, hsotg->regs + PCGCTL);
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
spin_unlock_irqrestore(&hsotg->lock, flags);
@ -1484,6 +1493,44 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
}
}
/* Must NOT be called with interrupt disabled or spinlock held */
static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
{
unsigned long flags;
u32 hprt0;
u32 pcgctl;
spin_lock_irqsave(&hsotg->lock, flags);
/*
* If hibernation is supported, Phy clock is already resumed
* after registers restore.
*/
if (!hsotg->core_params->hibernation) {
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgctl &= ~PCGCTL_STOPPCLK;
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
spin_unlock_irqrestore(&hsotg->lock, flags);
usleep_range(20000, 40000);
spin_lock_irqsave(&hsotg->lock, flags);
}
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RES;
hprt0 &= ~HPRT0_SUSP;
dwc2_writel(hprt0, hsotg->regs + HPRT0);
spin_unlock_irqrestore(&hsotg->lock, flags);
msleep(USB_RESUME_TIMEOUT);
spin_lock_irqsave(&hsotg->lock, flags);
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
hsotg->bus_suspended = 0;
spin_unlock_irqrestore(&hsotg->lock, flags);
}
/* 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)
@ -1523,23 +1570,15 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
"ClearPortFeature USB_PORT_FEAT_ENABLE\n");
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_ENA;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
break;
case USB_PORT_FEAT_SUSPEND:
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
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;
msleep(USB_RESUME_TIMEOUT);
hprt0 &= ~HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
if (hsotg->bus_suspended)
dwc2_port_resume(hsotg);
break;
case USB_PORT_FEAT_POWER:
@ -1547,7 +1586,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
"ClearPortFeature USB_PORT_FEAT_POWER\n");
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 &= ~HPRT0_PWR;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
break;
case USB_PORT_FEAT_INDICATOR:
@ -1668,7 +1707,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
break;
}
hprt0 = readl(hsotg->regs + HPRT0);
hprt0 = dwc2_readl(hsotg->regs + HPRT0);
dev_vdbg(hsotg->dev, " HPRT0: 0x%08x\n", hprt0);
if (hprt0 & HPRT0_CONNSTS)
@ -1733,18 +1772,18 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
"SetPortFeature - USB_PORT_FEAT_POWER\n");
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_PWR;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
break;
case USB_PORT_FEAT_RESET:
hprt0 = dwc2_read_hprt0(hsotg);
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_RESET\n");
pcgctl = readl(hsotg->regs + PCGCTL);
pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
writel(pcgctl, hsotg->regs + PCGCTL);
dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
/* ??? Original driver does this */
writel(0, hsotg->regs + PCGCTL);
dwc2_writel(0, hsotg->regs + PCGCTL);
hprt0 = dwc2_read_hprt0(hsotg);
/* Clear suspend bit if resetting from suspend state */
@ -1759,13 +1798,13 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
hprt0 |= HPRT0_PWR | HPRT0_RST;
dev_dbg(hsotg->dev,
"In host mode, hprt0=%08x\n", hprt0);
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
}
/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
usleep_range(50000, 70000);
hprt0 &= ~HPRT0_RST;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
hsotg->lx_state = DWC2_L0; /* Now back to On state */
break;
@ -1781,7 +1820,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
"SetPortFeature - USB_PORT_FEAT_TEST\n");
hprt0 &= ~HPRT0_TSTCTL_MASK;
hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
break;
default:
@ -1838,7 +1877,7 @@ static int dwc2_hcd_is_status_changed(struct dwc2_hsotg *hsotg, int port)
int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
{
u32 hfnum = readl(hsotg->regs + HFNUM);
u32 hfnum = dwc2_readl(hsotg->regs + HFNUM);
#ifdef DWC2_DEBUG_SOF
dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
@ -1941,11 +1980,11 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
if (chan->xfer_started) {
u32 hfnum, hcchar, hctsiz, hcint, hcintmsk;
hfnum = readl(hsotg->regs + HFNUM);
hcchar = readl(hsotg->regs + HCCHAR(i));
hctsiz = readl(hsotg->regs + HCTSIZ(i));
hcint = readl(hsotg->regs + HCINT(i));
hcintmsk = readl(hsotg->regs + HCINTMSK(i));
hfnum = dwc2_readl(hsotg->regs + HFNUM);
hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(i));
hcint = dwc2_readl(hsotg->regs + HCINT(i));
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(i));
dev_dbg(hsotg->dev, " hfnum: 0x%08x\n", hfnum);
dev_dbg(hsotg->dev, " hcchar: 0x%08x\n", hcchar);
dev_dbg(hsotg->dev, " hctsiz: 0x%08x\n", hctsiz);
@ -1993,12 +2032,12 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, " periodic_channels: %d\n",
hsotg->periodic_channels);
dev_dbg(hsotg->dev, " periodic_usecs: %d\n", hsotg->periodic_usecs);
np_tx_status = readl(hsotg->regs + GNPTXSTS);
np_tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
dev_dbg(hsotg->dev, " NP Tx Req Queue Space Avail: %d\n",
(np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
dev_dbg(hsotg->dev, " NP Tx FIFO Space Avail: %d\n",
(np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
p_tx_status = readl(hsotg->regs + HPTXSTS);
p_tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
dev_dbg(hsotg->dev, " P Tx Req Queue Space Avail: %d\n",
(p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
dev_dbg(hsotg->dev, " P Tx FIFO Space Avail: %d\n",
@ -2194,11 +2233,6 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
usb_pipein(urb->pipe) ? "IN" : "OUT", status,
urb->actual_length);
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) {
for (i = 0; i < urb->number_of_packets; i++)
dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n",
i, urb->iso_frame_desc[i].status);
}
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
@ -2211,6 +2245,12 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
}
}
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) {
for (i = 0; i < urb->number_of_packets; i++)
dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n",
i, urb->iso_frame_desc[i].status);
}
urb->status = status;
if (!status) {
if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
@ -2262,7 +2302,7 @@ static void dwc2_hcd_reset_func(struct work_struct *work)
dev_dbg(hsotg->dev, "USB RESET function called\n");
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 &= ~HPRT0_RST;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_writel(hprt0, hsotg->regs + HPRT0);
hsotg->flags.b.port_reset_change = 1;
}
@ -2286,8 +2326,9 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
spin_lock_irqsave(&hsotg->lock, flags);
hsotg->lx_state = DWC2_L0;
hcd->state = HC_STATE_RUNNING;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
if (dwc2_is_device_mode(hsotg)) {
spin_unlock_irqrestore(&hsotg->lock, flags);
@ -2316,8 +2357,19 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
/* Turn off all host-specific interrupts */
dwc2_disable_host_interrupts(hsotg);
/* Wait for interrupt processing to finish */
synchronize_irq(hcd->irq);
spin_lock_irqsave(&hsotg->lock, flags);
/* Ensure hcd is disconnected */
dwc2_hcd_disconnect(hsotg);
dwc2_hcd_stop(hsotg);
hsotg->lx_state = DWC2_L3;
hcd->state = HC_STATE_HALT;
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
spin_unlock_irqrestore(&hsotg->lock, flags);
usleep_range(1000, 3000);
@ -2326,17 +2378,125 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
int ret = 0;
u32 hprt0;
spin_lock_irqsave(&hsotg->lock, flags);
if (hsotg->lx_state != DWC2_L0)
goto unlock;
if (!HCD_HW_ACCESSIBLE(hcd))
goto unlock;
if (!hsotg->core_params->hibernation)
goto skip_power_saving;
/*
* Drive USB suspend and disable port Power
* if usb bus is not suspended.
*/
if (!hsotg->bus_suspended) {
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_SUSP;
hprt0 &= ~HPRT0_PWR;
dwc2_writel(hprt0, hsotg->regs + HPRT0);
}
/* Enter hibernation */
ret = dwc2_enter_hibernation(hsotg);
if (ret) {
if (ret != -ENOTSUPP)
dev_err(hsotg->dev,
"enter hibernation failed\n");
goto skip_power_saving;
}
/* Ask phy to be suspended */
if (!IS_ERR_OR_NULL(hsotg->uphy)) {
spin_unlock_irqrestore(&hsotg->lock, flags);
usb_phy_set_suspend(hsotg->uphy, true);
spin_lock_irqsave(&hsotg->lock, flags);
}
/* After entering hibernation, hardware is no more accessible */
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
skip_power_saving:
hsotg->lx_state = DWC2_L2;
return 0;
unlock:
spin_unlock_irqrestore(&hsotg->lock, flags);
return ret;
}
static int _dwc2_hcd_resume(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&hsotg->lock, flags);
if (hsotg->lx_state != DWC2_L2)
goto unlock;
if (!hsotg->core_params->hibernation) {
hsotg->lx_state = DWC2_L0;
goto unlock;
}
/*
* Set HW accessible bit before powering on the controller
* since an interrupt may rise.
*/
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/*
* Enable power if not already done.
* This must not be spinlocked since duration
* of this call is unknown.
*/
if (!IS_ERR_OR_NULL(hsotg->uphy)) {
spin_unlock_irqrestore(&hsotg->lock, flags);
usb_phy_set_suspend(hsotg->uphy, false);
spin_lock_irqsave(&hsotg->lock, flags);
}
/* Exit hibernation */
ret = dwc2_exit_hibernation(hsotg, true);
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev, "exit hibernation failed\n");
hsotg->lx_state = DWC2_L0;
return 0;
spin_unlock_irqrestore(&hsotg->lock, flags);
if (hsotg->bus_suspended) {
spin_lock_irqsave(&hsotg->lock, flags);
hsotg->flags.b.port_suspend_change = 1;
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_port_resume(hsotg);
} else {
/* Wait for controller to correctly update D+/D- level */
usleep_range(3000, 5000);
/*
* Clear Port Enable and Port Status changes.
* Enable Port Power.
*/
dwc2_writel(HPRT0_PWR | HPRT0_CONNDET |
HPRT0_ENACHG, hsotg->regs + HPRT0);
/* Wait for controller to detect Port Connect */
usleep_range(5000, 7000);
}
return ret;
unlock:
spin_unlock_irqrestore(&hsotg->lock, flags);
return ret;
}
/* Returns the current frame number */
@ -2790,17 +2950,17 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
hsotg->status_buf = NULL;
}
ahbcfg = readl(hsotg->regs + GAHBCFG);
ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
/* Disable all interrupts */
ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
writel(ahbcfg, hsotg->regs + GAHBCFG);
writel(0, hsotg->regs + GINTMSK);
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
dwc2_writel(0, hsotg->regs + GINTMSK);
if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) {
dctl = readl(hsotg->regs + DCTL);
dctl = dwc2_readl(hsotg->regs + DCTL);
dctl |= DCTL_SFTDISCON;
writel(dctl, hsotg->regs + DCTL);
dwc2_writel(dctl, hsotg->regs + DCTL);
}
if (hsotg->wq_otg) {
@ -2841,7 +3001,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
retval = -ENOMEM;
hcfg = readl(hsotg->regs + HCFG);
hcfg = dwc2_readl(hsotg->regs + HCFG);
dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS

View File

@ -371,10 +371,10 @@ static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
*/
static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
{
u32 mask = readl(hsotg->regs + HCINTMSK(chnum));
u32 mask = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
mask &= ~intr;
writel(mask, hsotg->regs + HCINTMSK(chnum));
dwc2_writel(mask, hsotg->regs + HCINTMSK(chnum));
}
/*
@ -382,11 +382,11 @@ static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
*/
static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
{
return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
}
static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
{
return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
}
/*
@ -395,7 +395,7 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
*/
static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
{
u32 hprt0 = readl(hsotg->regs + HPRT0);
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
return hprt0;
@ -580,7 +580,8 @@ static inline u16 dwc2_micro_frame_num(u16 frame)
*/
static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
{
return readl(hsotg->regs + GINTSTS) & readl(hsotg->regs + GINTMSK);
return dwc2_readl(hsotg->regs + GINTSTS) &
dwc2_readl(hsotg->regs + GINTMSK);
}
static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
@ -732,7 +733,7 @@ do { \
qtd_list_entry); \
if (usb_pipeint(_qtd_->urb->pipe) && \
(_qh_)->start_split_frame != 0 && !_qtd_->complete_split) { \
_hfnum_.d32 = readl((_hcd_)->regs + HFNUM); \
_hfnum_.d32 = dwc2_readl((_hcd_)->regs + HFNUM); \
switch (_hfnum_.b.frnum & 0x7) { \
case 7: \
(_hcd_)->hfnum_7_samples_##_letter_++; \

View File

@ -169,19 +169,19 @@ static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
spin_lock_irqsave(&hsotg->lock, flags);
hcfg = readl(hsotg->regs + HCFG);
hcfg = dwc2_readl(hsotg->regs + HCFG);
if (hcfg & HCFG_PERSCHEDENA) {
/* already enabled */
spin_unlock_irqrestore(&hsotg->lock, flags);
return;
}
writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
dwc2_writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
hcfg &= ~HCFG_FRLISTEN_MASK;
hcfg |= fr_list_en | HCFG_PERSCHEDENA;
dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
writel(hcfg, hsotg->regs + HCFG);
dwc2_writel(hcfg, hsotg->regs + HCFG);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
@ -193,7 +193,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
spin_lock_irqsave(&hsotg->lock, flags);
hcfg = readl(hsotg->regs + HCFG);
hcfg = dwc2_readl(hsotg->regs + HCFG);
if (!(hcfg & HCFG_PERSCHEDENA)) {
/* already disabled */
spin_unlock_irqrestore(&hsotg->lock, flags);
@ -202,7 +202,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
hcfg &= ~HCFG_PERSCHEDENA;
dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
writel(hcfg, hsotg->regs + HCFG);
dwc2_writel(hcfg, hsotg->regs + HCFG);
spin_unlock_irqrestore(&hsotg->lock, flags);
}

View File

@ -148,7 +148,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
dwc2_hcd_queue_transactions(hsotg, tr_type);
/* Clear interrupt */
writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
dwc2_writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
}
/*
@ -164,7 +164,7 @@ static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
if (dbg_perio())
dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
grxsts = readl(hsotg->regs + GRXSTSP);
grxsts = dwc2_readl(hsotg->regs + GRXSTSP);
chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
chan = hsotg->hc_ptr_array[chnum];
if (!chan) {
@ -247,11 +247,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
/* Every time when port enables calculate HFIR.FrInterval */
hfir = readl(hsotg->regs + HFIR);
hfir = dwc2_readl(hsotg->regs + HFIR);
hfir &= ~HFIR_FRINT_MASK;
hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
HFIR_FRINT_MASK;
writel(hfir, hsotg->regs + HFIR);
dwc2_writel(hfir, hsotg->regs + HFIR);
/* Check if we need to adjust the PHY clock speed for low power */
if (!params->host_support_fs_ls_low_power) {
@ -260,7 +260,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
return;
}
usbcfg = readl(hsotg->regs + GUSBCFG);
usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
@ -268,11 +268,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
/* Set PHY low power clock select for FS/LS devices */
usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
writel(usbcfg, hsotg->regs + GUSBCFG);
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
do_reset = 1;
}
hcfg = readl(hsotg->regs + HCFG);
hcfg = dwc2_readl(hsotg->regs + HCFG);
fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
HCFG_FSLSPCLKSEL_SHIFT;
@ -286,7 +286,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
writel(hcfg, hsotg->regs + HCFG);
dwc2_writel(hcfg, hsotg->regs + HCFG);
do_reset = 1;
}
} else {
@ -297,7 +297,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
writel(hcfg, hsotg->regs + HCFG);
dwc2_writel(hcfg, hsotg->regs + HCFG);
do_reset = 1;
}
}
@ -305,7 +305,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
/* Not low power */
if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
writel(usbcfg, hsotg->regs + GUSBCFG);
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
do_reset = 1;
}
}
@ -332,7 +332,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
hprt0 = readl(hsotg->regs + HPRT0);
hprt0 = dwc2_readl(hsotg->regs + HPRT0);
hprt0_modify = hprt0;
/*
@ -388,7 +388,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
}
/* Clear Port Interrupts */
writel(hprt0_modify, hsotg->regs + HPRT0);
dwc2_writel(hprt0_modify, hsotg->regs + HPRT0);
}
/*
@ -408,7 +408,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
{
u32 hctsiz, count, length;
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
if (halt_status == DWC2_HC_XFER_COMPLETE) {
if (chan->ep_is_in) {
@ -491,7 +491,7 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
urb->status = 0;
}
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
dev_vdbg(hsotg->dev, " chan->xfer_len %d\n", chan->xfer_len);
@ -514,7 +514,7 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan, int chnum,
struct dwc2_qtd *qtd)
{
u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
@ -771,9 +771,9 @@ cleanup:
}
}
haintmsk = readl(hsotg->regs + HAINTMSK);
haintmsk = dwc2_readl(hsotg->regs + HAINTMSK);
haintmsk &= ~(1 << chan->hc_num);
writel(haintmsk, hsotg->regs + HAINTMSK);
dwc2_writel(haintmsk, hsotg->regs + HAINTMSK);
/* Try to queue more transfers now that there's a free channel */
tr_type = dwc2_hcd_select_transactions(hsotg);
@ -820,9 +820,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
* is enabled so that the non-periodic schedule will
* be processed
*/
gintmsk = readl(hsotg->regs + GINTMSK);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk |= GINTSTS_NPTXFEMP;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
} else {
dev_vdbg(hsotg->dev, "isoc/intr\n");
/*
@ -839,9 +839,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
* enabled so that the periodic schedule will be
* processed
*/
gintmsk = readl(hsotg->regs + GINTMSK);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk |= GINTSTS_PTXFEMP;
writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
}
}
}
@ -906,7 +906,7 @@ static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg,
struct dwc2_qtd *qtd,
enum dwc2_halt_status halt_status)
{
u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
qtd->error_count = 0;
@ -1184,7 +1184,7 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
urb->actual_length += xfer_length;
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
dev_vdbg(hsotg->dev, " chan->start_pkt_count %d\n",
@ -1505,10 +1505,10 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
hcchar = readl(hsotg->regs + HCCHAR(chnum));
hcsplt = readl(hsotg->regs + HCSPLT(chnum));
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
hc_dma = readl(hsotg->regs + HCDMA(chnum));
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
hc_dma = dwc2_readl(hsotg->regs + HCDMA(chnum));
dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
dev_err(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
@ -1721,10 +1721,10 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
* This code is here only as a check. This condition should
* never happen. Ignore the halt if it does occur.
*/
hcchar = readl(hsotg->regs + HCCHAR(chnum));
hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
hcsplt = readl(hsotg->regs + HCSPLT(chnum));
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
dev_dbg(hsotg->dev,
"%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
__func__);
@ -1748,7 +1748,7 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
* when the halt interrupt occurs. Halt the channel again if it does
* occur.
*/
hcchar = readl(hsotg->regs + HCCHAR(chnum));
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
if (hcchar & HCCHAR_CHDIS) {
dev_warn(hsotg->dev,
"%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
@ -1808,7 +1808,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
return;
}
hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
if (chan->hcint & HCINTMSK_XFERCOMPL) {
/*
@ -1903,7 +1903,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
dev_err(hsotg->dev,
"hcint 0x%08x, intsts 0x%08x\n",
chan->hcint,
readl(hsotg->regs + GINTSTS));
dwc2_readl(hsotg->regs + GINTSTS));
goto error;
}
}
@ -1949,6 +1949,24 @@ static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg,
}
}
/*
* Check if the given qtd is still the top of the list (and thus valid).
*
* If dwc2_hcd_qtd_unlink_and_free() has been called since we grabbed
* the qtd from the top of the list, this will return false (otherwise true).
*/
static bool dwc2_check_qtd_still_ok(struct dwc2_qtd *qtd, struct dwc2_qh *qh)
{
struct dwc2_qtd *cur_head;
if (qh == NULL)
return false;
cur_head = list_first_entry(&qh->qtd_list, struct dwc2_qtd,
qtd_list_entry);
return (cur_head == qtd);
}
/* Handles interrupt for a specific Host Channel */
static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
{
@ -1958,11 +1976,11 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
chan = hsotg->hc_ptr_array[chnum];
hcint = readl(hsotg->regs + HCINT(chnum));
hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
hcint = dwc2_readl(hsotg->regs + HCINT(chnum));
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
if (!chan) {
dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
writel(hcint, hsotg->regs + HCINT(chnum));
dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
return;
}
@ -1974,7 +1992,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
hcint, hcintmsk, hcint & hcintmsk);
}
writel(hcint, hsotg->regs + HCINT(chnum));
dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
chan->hcint = hcint;
hcint &= hcintmsk;
@ -2031,27 +2049,59 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
*/
hcint &= ~HCINTMSK_NYET;
}
if (hcint & HCINTMSK_CHHLTD)
dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_AHBERR)
dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_STALL)
dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_NAK)
dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_ACK)
dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_NYET)
dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_XACTERR)
dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_BBLERR)
dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_FRMOVRUN)
dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_DATATGLERR)
dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
if (hcint & HCINTMSK_CHHLTD) {
dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_AHBERR) {
dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_STALL) {
dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_NAK) {
dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_ACK) {
dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_NYET) {
dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_XACTERR) {
dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_BBLERR) {
dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_FRMOVRUN) {
dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
if (hcint & HCINTMSK_DATATGLERR) {
dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
if (!dwc2_check_qtd_still_ok(qtd, chan->qh))
goto exit;
}
exit:
chan->hcint = 0;
}
@ -2066,7 +2116,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
u32 haint;
int i;
haint = readl(hsotg->regs + HAINT);
haint = dwc2_readl(hsotg->regs + HAINT);
if (dbg_perio()) {
dev_vdbg(hsotg->dev, "%s()\n", __func__);
@ -2134,8 +2184,8 @@ irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg)
"DWC OTG HCD Finished Servicing Interrupts\n");
dev_vdbg(hsotg->dev,
"DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
readl(hsotg->regs + GINTSTS),
readl(hsotg->regs + GINTMSK));
dwc2_readl(hsotg->regs + GINTSTS),
dwc2_readl(hsotg->regs + GINTMSK));
}
}

View File

@ -106,6 +106,9 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
qh->ep_type == USB_ENDPOINT_XFER_ISOC,
bytecount));
/* Ensure frame_number corresponds to the reality */
hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
/* Start in a slightly future (micro)frame */
qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
SCHEDULE_SLOP);
@ -115,7 +118,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
if (qh->ep_type == USB_ENDPOINT_XFER_INT)
qh->interval = 8;
#endif
hprt = readl(hsotg->regs + HPRT0);
hprt = dwc2_readl(hsotg->regs + HPRT0);
prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
if (prtspd == HPRT0_SPD_HIGH_SPEED &&
(dev_speed == USB_SPEED_LOW ||
@ -583,6 +586,14 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
/* QH already in a schedule */
return 0;
if (!dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number) &&
!hsotg->frame_number) {
dev_dbg(hsotg->dev,
"reset frame number counter\n");
qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
SCHEDULE_SLOP);
}
/* Add the new QH to the appropriate schedule */
if (dwc2_qh_is_non_per(qh)) {
/* Always start in inactive schedule */
@ -595,9 +606,9 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
if (status)
return status;
if (!hsotg->periodic_qh_count) {
intr_mask = readl(hsotg->regs + GINTMSK);
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
intr_mask |= GINTSTS_SOF;
writel(intr_mask, hsotg->regs + GINTMSK);
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
}
hsotg->periodic_qh_count++;
@ -632,9 +643,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
dwc2_deschedule_periodic(hsotg, qh);
hsotg->periodic_qh_count--;
if (!hsotg->periodic_qh_count) {
intr_mask = readl(hsotg->regs + GINTMSK);
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
intr_mask &= ~GINTSTS_SOF;
writel(intr_mask, hsotg->regs + GINTMSK);
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
}
}

View File

@ -142,6 +142,7 @@
#define GINTSTS_RESETDET (1 << 23)
#define GINTSTS_FET_SUSP (1 << 22)
#define GINTSTS_INCOMPL_IP (1 << 21)
#define GINTSTS_INCOMPL_SOOUT (1 << 21)
#define GINTSTS_INCOMPL_SOIN (1 << 20)
#define GINTSTS_OEPINT (1 << 19)
#define GINTSTS_IEPINT (1 << 18)

View File

@ -37,11 +37,14 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_data/s3c-hsotg.h>
#include <linux/usb/of.h>
@ -111,6 +114,145 @@ static const struct dwc2_core_params params_rk3066 = {
.hibernation = -1,
};
static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
{
struct platform_device *pdev = to_platform_device(hsotg->dev);
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
if (ret)
return ret;
ret = clk_prepare_enable(hsotg->clk);
if (ret)
return ret;
if (hsotg->uphy)
ret = usb_phy_init(hsotg->uphy);
else if (hsotg->plat && hsotg->plat->phy_init)
ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
else {
ret = phy_power_on(hsotg->phy);
if (ret == 0)
ret = phy_init(hsotg->phy);
}
return ret;
}
/**
* dwc2_lowlevel_hw_enable - enable platform lowlevel hw resources
* @hsotg: The driver state
*
* A wrapper for platform code responsible for controlling
* low-level USB platform resources (phy, clock, regulators)
*/
int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
{
int ret = __dwc2_lowlevel_hw_enable(hsotg);
if (ret == 0)
hsotg->ll_hw_enabled = true;
return ret;
}
static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
{
struct platform_device *pdev = to_platform_device(hsotg->dev);
int ret = 0;
if (hsotg->uphy)
usb_phy_shutdown(hsotg->uphy);
else if (hsotg->plat && hsotg->plat->phy_exit)
ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
else {
ret = phy_exit(hsotg->phy);
if (ret == 0)
ret = phy_power_off(hsotg->phy);
}
if (ret)
return ret;
clk_disable_unprepare(hsotg->clk);
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
return ret;
}
/**
* dwc2_lowlevel_hw_disable - disable platform lowlevel hw resources
* @hsotg: The driver state
*
* A wrapper for platform code responsible for controlling
* low-level USB platform resources (phy, clock, regulators)
*/
int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
{
int ret = __dwc2_lowlevel_hw_disable(hsotg);
if (ret == 0)
hsotg->ll_hw_enabled = false;
return ret;
}
static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
{
int i, ret;
/* Set default UTMI width */
hsotg->phyif = GUSBCFG_PHYIF16;
/*
* Attempt to find a generic PHY, then look for an old style
* USB PHY and then fall back to pdata
*/
hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy");
if (IS_ERR(hsotg->phy)) {
hsotg->phy = NULL;
hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
if (IS_ERR(hsotg->uphy))
hsotg->uphy = NULL;
else
hsotg->plat = dev_get_platdata(hsotg->dev);
}
if (hsotg->phy) {
/*
* If using the generic PHY framework, check if the PHY bus
* width is 8-bit and set the phyif appropriately.
*/
if (phy_get_bus_width(hsotg->phy) == 8)
hsotg->phyif = GUSBCFG_PHYIF8;
}
if (!hsotg->phy && !hsotg->uphy && !hsotg->plat) {
dev_err(hsotg->dev, "no platform data or transceiver defined\n");
return -EPROBE_DEFER;
}
/* Clock */
hsotg->clk = devm_clk_get(hsotg->dev, "otg");
if (IS_ERR(hsotg->clk)) {
hsotg->clk = NULL;
dev_dbg(hsotg->dev, "cannot get otg clock\n");
}
/* Regulators */
for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
if (ret) {
dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
return ret;
}
return 0;
}
/**
* dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
* DWC_otg driver
@ -130,7 +272,10 @@ static int dwc2_driver_remove(struct platform_device *dev)
if (hsotg->hcd_enabled)
dwc2_hcd_remove(hsotg);
if (hsotg->gadget_enabled)
s3c_hsotg_remove(hsotg);
dwc2_hsotg_remove(hsotg);
if (hsotg->ll_hw_enabled)
dwc2_lowlevel_hw_disable(hsotg);
return 0;
}
@ -163,8 +308,6 @@ 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;
@ -220,34 +363,25 @@ static int dwc2_driver_probe(struct platform_device *dev)
dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
(unsigned long)res->start, hsotg->regs);
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);
hsotg->dr_mode = usb_get_dr_mode(&dev->dev);
if (IS_ENABLED(CONFIG_USB_DWC2_HOST) &&
hsotg->dr_mode != USB_DR_MODE_HOST) {
hsotg->dr_mode = USB_DR_MODE_HOST;
dev_warn(hsotg->dev,
"Configuration mismatch. Forcing host mode\n");
} else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) &&
hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
hsotg->dr_mode = USB_DR_MODE_PERIPHERAL;
dev_warn(hsotg->dev,
"Configuration mismatch. Forcing peripheral mode\n");
}
spin_lock_init(&hsotg->lock);
mutex_init(&hsotg->init_mutex);
/* Detect config values from hardware */
retval = dwc2_get_hwparams(hsotg);
retval = dwc2_lowlevel_hw_init(hsotg);
if (retval)
return retval;
spin_lock_init(&hsotg->lock);
hsotg->core_params = devm_kzalloc(&dev->dev,
sizeof(*hsotg->core_params), GFP_KERNEL);
if (!hsotg->core_params)
@ -255,13 +389,22 @@ static int dwc2_driver_probe(struct platform_device *dev)
dwc2_set_all_params(hsotg->core_params, -1);
retval = dwc2_lowlevel_hw_enable(hsotg);
if (retval)
return retval;
/* Detect config values from hardware */
retval = dwc2_get_hwparams(hsotg);
if (retval)
goto error;
/* Validate parameter values */
dwc2_set_parameters(hsotg, params);
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
retval = dwc2_gadget_init(hsotg, irq);
if (retval)
return retval;
goto error;
hsotg->gadget_enabled = 1;
}
@ -269,8 +412,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
retval = dwc2_hcd_init(hsotg, irq);
if (retval) {
if (hsotg->gadget_enabled)
s3c_hsotg_remove(hsotg);
return retval;
dwc2_hsotg_remove(hsotg);
goto error;
}
hsotg->hcd_enabled = 1;
}
@ -279,6 +422,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
dwc2_debugfs_init(hsotg);
/* Gadget code manages lowlevel hw on its own */
if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
dwc2_lowlevel_hw_disable(hsotg);
return 0;
error:
dwc2_lowlevel_hw_disable(hsotg);
return retval;
}
@ -287,15 +438,12 @@ 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)) {
ret = s3c_hsotg_suspend(dwc2);
} else {
if (dwc2->lx_state == DWC2_L0)
return 0;
phy_exit(dwc2->phy);
phy_power_off(dwc2->phy);
if (dwc2_is_device_mode(dwc2))
dwc2_hsotg_suspend(dwc2);
if (dwc2->ll_hw_enabled)
ret = __dwc2_lowlevel_hw_disable(dwc2);
}
return ret;
}
@ -304,13 +452,15 @@ 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)) {
ret = s3c_hsotg_resume(dwc2);
} else {
phy_power_on(dwc2->phy);
phy_init(dwc2->phy);
if (dwc2->ll_hw_enabled) {
ret = __dwc2_lowlevel_hw_enable(dwc2);
if (ret)
return ret;
}
if (dwc2_is_device_mode(dwc2))
ret = dwc2_hsotg_resume(dwc2);
return ret;
}

View File

@ -34,6 +34,7 @@
#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/pinctrl/consumer.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@ -143,6 +144,32 @@ static int dwc3_soft_reset(struct dwc3 *dwc)
return 0;
}
/*
* dwc3_frame_length_adjustment - Adjusts frame length if required
* @dwc3: Pointer to our controller context structure
* @fladj: Value of GFLADJ_30MHZ to adjust frame length
*/
static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
{
u32 reg;
u32 dft;
if (dwc->revision < DWC3_REVISION_250A)
return;
if (fladj == 0)
return;
reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
dft = reg & DWC3_GFLADJ_30MHZ_MASK;
if (!dev_WARN_ONCE(dwc->dev, dft == fladj,
"request value same as default, ignoring\n")) {
reg &= ~DWC3_GFLADJ_30MHZ_MASK;
reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj;
dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
}
}
/**
* dwc3_free_one_event_buffer - Frees one event buffer
* @dwc: Pointer to our controller context structure
@ -488,6 +515,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_u2_susphy_quirk)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
if (dwc->dis_enblslpm_quirk)
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
return 0;
@ -507,12 +537,18 @@ static int dwc3_core_init(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
/* This should read as U3 followed by revision number */
if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
if ((reg & DWC3_GSNPSID_MASK) == 0x55330000) {
/* Detected DWC_usb3 IP */
dwc->revision = reg;
} else if ((reg & DWC3_GSNPSID_MASK) == 0x33310000) {
/* Detected DWC_usb31 IP */
dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
dwc->revision |= DWC3_REVISION_IS_DWC31;
} else {
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
ret = -ENODEV;
goto err0;
}
dwc->revision = reg;
/*
* Write Linux Version Code to our GUID register so it's easy to figure
@ -773,12 +809,12 @@ static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dwc3_platform_data *pdata = dev_get_platdata(dev);
struct device_node *node = dev->of_node;
struct resource *res;
struct dwc3 *dwc;
u8 lpm_nyet_threshold;
u8 tx_de_emphasis;
u8 hird_threshold;
u32 fladj = 0;
int ret;
@ -842,51 +878,56 @@ static int dwc3_probe(struct platform_device *pdev)
*/
hird_threshold = 12;
if (node) {
dwc->maximum_speed = of_usb_get_maximum_speed(node);
dwc->has_lpm_erratum = of_property_read_bool(node,
dwc->maximum_speed = usb_get_maximum_speed(dev);
dwc->dr_mode = usb_get_dr_mode(dev);
dwc->has_lpm_erratum = device_property_read_bool(dev,
"snps,has-lpm-erratum");
of_property_read_u8(node, "snps,lpm-nyet-threshold",
device_property_read_u8(dev, "snps,lpm-nyet-threshold",
&lpm_nyet_threshold);
dwc->is_utmi_l1_suspend = of_property_read_bool(node,
dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
"snps,is-utmi-l1-suspend");
of_property_read_u8(node, "snps,hird-threshold",
device_property_read_u8(dev, "snps,hird-threshold",
&hird_threshold);
dwc->usb3_lpm_capable = of_property_read_bool(node,
dwc->usb3_lpm_capable = device_property_read_bool(dev,
"snps,usb3_lpm_capable");
dwc->needs_fifo_resize = of_property_read_bool(node,
dwc->needs_fifo_resize = device_property_read_bool(dev,
"tx-fifo-resize");
dwc->dr_mode = of_usb_get_dr_mode(node);
dwc->disable_scramble_quirk = of_property_read_bool(node,
dwc->disable_scramble_quirk = device_property_read_bool(dev,
"snps,disable_scramble_quirk");
dwc->u2exit_lfps_quirk = of_property_read_bool(node,
dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
"snps,u2exit_lfps_quirk");
dwc->u2ss_inp3_quirk = of_property_read_bool(node,
dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
"snps,u2ss_inp3_quirk");
dwc->req_p1p2p3_quirk = of_property_read_bool(node,
dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
"snps,req_p1p2p3_quirk");
dwc->del_p1p2p3_quirk = of_property_read_bool(node,
dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
"snps,del_p1p2p3_quirk");
dwc->del_phy_power_chg_quirk = of_property_read_bool(node,
dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
"snps,del_phy_power_chg_quirk");
dwc->lfps_filter_quirk = of_property_read_bool(node,
dwc->lfps_filter_quirk = device_property_read_bool(dev,
"snps,lfps_filter_quirk");
dwc->rx_detect_poll_quirk = of_property_read_bool(node,
dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
"snps,rx_detect_poll_quirk");
dwc->dis_u3_susphy_quirk = of_property_read_bool(node,
dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
"snps,dis_u3_susphy_quirk");
dwc->dis_u2_susphy_quirk = of_property_read_bool(node,
dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
"snps,dis_u2_susphy_quirk");
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
"snps,dis_enblslpm_quirk");
dwc->tx_de_emphasis_quirk = of_property_read_bool(node,
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
"snps,tx_de_emphasis_quirk");
of_property_read_u8(node, "snps,tx_de_emphasis",
device_property_read_u8(dev, "snps,tx_de_emphasis",
&tx_de_emphasis);
of_property_read_string(node, "snps,hsphy_interface",
&dwc->hsphy_interface);
} else if (pdata) {
device_property_read_string(dev, "snps,hsphy_interface",
&dwc->hsphy_interface);
device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
&fladj);
if (pdata) {
dwc->maximum_speed = pdata->maximum_speed;
dwc->has_lpm_erratum = pdata->has_lpm_erratum;
if (pdata->lpm_nyet_threshold)
@ -909,12 +950,14 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
if (pdata->tx_de_emphasis)
tx_de_emphasis = pdata->tx_de_emphasis;
dwc->hsphy_interface = pdata->hsphy_interface;
fladj = pdata->fladj_value;
}
/* default to superspeed if no maximum_speed passed */
@ -971,6 +1014,9 @@ static int dwc3_probe(struct platform_device *pdev)
goto err1;
}
/* Adjust Frame Length */
dwc3_frame_length_adjustment(dwc, fladj);
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
ret = phy_power_on(dwc->usb2_generic_phy);
@ -1091,6 +1137,8 @@ static int dwc3_suspend(struct device *dev)
phy_exit(dwc->usb2_generic_phy);
phy_exit(dwc->usb3_generic_phy);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
@ -1100,6 +1148,8 @@ static int dwc3_resume(struct device *dev)
unsigned long flags;
int ret;
pinctrl_pm_select_default_state(dev);
usb_phy_init(dwc->usb3_phy);
usb_phy_init(dwc->usb2_phy);
ret = phy_init(dwc->usb2_generic_phy);

View File

@ -108,6 +108,9 @@
#define DWC3_GPRTBIMAP_FS0 0xc188
#define DWC3_GPRTBIMAP_FS1 0xc18c
#define DWC3_VER_NUMBER 0xc1a0
#define DWC3_VER_TYPE 0xc1a4
#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04))
#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04))
@ -124,6 +127,7 @@
#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
#define DWC3_GHWPARAMS8 0xc600
#define DWC3_GFLADJ 0xc630
/* Device Registers */
#define DWC3_DCFG 0xc700
@ -175,6 +179,7 @@
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
#define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4)
#define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8)
/* Global USB2 PHY Vendor Control Register */
#define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25)
@ -234,6 +239,10 @@
/* Global HWPARAMS6 Register */
#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7)
/* Global Frame Length Adjustment Register */
#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
#define DWC3_GFLADJ_30MHZ_MASK 0x3f
/* Device Configuration Register */
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@ -712,6 +721,8 @@ struct dwc3_scratchpad_array {
* @rx_detect_poll_quirk: set if we enable rx_detect to polling lfps quirk
* @dis_u3_susphy_quirk: set if we disable usb3 suspend phy
* @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
* @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
* disabling the suspend signal to the PHY.
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
* @tx_de_emphasis: Tx de-emphasis value
* 0 - -6dB de-emphasis
@ -766,6 +777,14 @@ struct dwc3 {
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
/*
* All 3.1 IP version constants are greater than the 3.0 IP
* version constants. This works for most version checks in
* dwc3. However, in the future, this may not apply as
* features may be developed on newer versions of the 3.0 IP
* that are not in the 3.1 IP.
*/
u32 revision;
#define DWC3_REVISION_173A 0x5533173a
@ -788,6 +807,13 @@ struct dwc3 {
#define DWC3_REVISION_270A 0x5533270a
#define DWC3_REVISION_280A 0x5533280a
/*
* NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really
* just so dwc31 revisions are always larger than dwc3.
*/
#define DWC3_REVISION_IS_DWC31 0x80000000
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31)
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
enum dwc3_link_state link_state;
@ -841,6 +867,7 @@ struct dwc3 {
unsigned rx_detect_poll_quirk:1;
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;

View File

@ -26,12 +26,14 @@
#include "platform_data.h"
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
#define PCI_DEVICE_ID_INTEL_BSW 0x22B7
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31 0xabcf
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
@ -106,6 +108,22 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
}
}
if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS &&
(pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {
struct dwc3_platform_data pdata;
memset(&pdata, 0, sizeof(pdata));
pdata.usb3_lpm_capable = true;
pdata.has_lpm_erratum = true;
pdata.dis_enblslpm_quirk = true;
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
sizeof(pdata));
}
return 0;
}
@ -154,6 +172,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,
goto err;
dwc3->dev.parent = dev;
ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev));
ret = platform_device_add(dwc3);
if (ret) {
@ -178,6 +197,14 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
},
{
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
},
{
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
},
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },

View File

@ -195,6 +195,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
struct resource *res;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node, *child;
struct platform_device *child_pdev;
struct regmap *regmap;
int ret;
@ -253,8 +254,6 @@ static int st_dwc3_probe(struct platform_device *pdev)
goto undo_softreset;
}
dwc3_data->dr_mode = of_usb_get_dr_mode(child);
/* Allocate and initialize the core */
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
@ -262,6 +261,15 @@ static int st_dwc3_probe(struct platform_device *pdev)
goto undo_softreset;
}
child_pdev = of_find_device_by_node(child);
if (!child_pdev) {
dev_err(dev, "failed to find dwc3 core device\n");
ret = -ENODEV;
goto undo_softreset;
}
dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev);
/*
* Configure the USB port as device or host according to the static
* configuration passed from DT.

View File

@ -948,7 +948,6 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
return -EBUSY;
}
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
/*
* If we are getting here after a short-out-packet we don't enqueue any
@ -1050,6 +1049,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
req->direction = dep->direction;
req->epnum = dep->number;
trace_dwc3_ep_queue(req);
/*
* We only add to our list of requests now and
* start consuming the list once we get XferNotReady
@ -1069,6 +1070,19 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
list_add_tail(&req->list, &dep->request_list);
/*
* If there are no pending requests and the endpoint isn't already
* busy, we will just start the request straight away.
*
* This will save one IRQ (XFER_NOT_READY) and possibly make it a
* little bit faster.
*/
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
!(dep->flags & DWC3_EP_BUSY)) {
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
goto out;
}
/*
* There are a few special cases:
*
@ -1096,10 +1110,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
}
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
if (ret && ret != -EBUSY)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
return ret;
if (!ret)
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
goto out;
}
/*
@ -1113,10 +1127,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
WARN_ON_ONCE(!dep->resource_index);
ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
false);
if (ret && ret != -EBUSY)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
return ret;
goto out;
}
/*
@ -1124,14 +1135,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* right away, otherwise host will not know we have streams to be
* handled.
*/
if (dep->stream_capable) {
if (dep->stream_capable)
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
if (ret && ret != -EBUSY)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
}
return 0;
out:
if (ret && ret != -EBUSY)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
if (ret == -EBUSY)
ret = 0;
return ret;
}
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
@ -1159,8 +1173,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
goto out;
}
trace_dwc3_ep_queue(req);
ret = __dwc3_gadget_ep_queue(dep, req);
out:
@ -1872,27 +1884,32 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
unsigned int i;
int ret;
req = next_request(&dep->req_queued);
if (!req) {
WARN_ON_ONCE(1);
return 1;
}
i = 0;
do {
slot = req->start_slot + i;
if ((slot == DWC3_TRB_NUM - 1) &&
req = next_request(&dep->req_queued);
if (!req) {
WARN_ON_ONCE(1);
return 1;
}
i = 0;
do {
slot = req->start_slot + i;
if ((slot == DWC3_TRB_NUM - 1) &&
usb_endpoint_xfer_isoc(dep->endpoint.desc))
slot++;
slot %= DWC3_TRB_NUM;
trb = &dep->trb_pool[slot];
slot++;
slot %= DWC3_TRB_NUM;
trb = &dep->trb_pool[slot];
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
event, status);
if (ret)
break;
} while (++i < req->request.num_mapped_sgs);
dwc3_gadget_giveback(dep, req, status);
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
event, status);
if (ret)
break;
} while (++i < req->request.num_mapped_sgs);
dwc3_gadget_giveback(dep, req, status);
} while (1);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
@ -1955,6 +1972,14 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
dwc->u1u2 = 0;
}
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
int ret;
ret = __dwc3_gadget_kick_transfer(dep, 0, is_xfer_complete);
if (!ret || ret == -EBUSY)
return;
}
}
static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
@ -1992,15 +2017,16 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dwc3_gadget_start_isoc(dwc, dep, event);
} else {
int active;
int ret;
active = event->status & DEPEVT_STATUS_TRANSFER_ACTIVE;
dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
dep->name, event->status &
DEPEVT_STATUS_TRANSFER_ACTIVE
? "Transfer Active"
dep->name, active ? "Transfer Active"
: "Transfer Not Active");
ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
ret = __dwc3_gadget_kick_transfer(dep, 0, !active);
if (!ret || ret == -EBUSY)
return;

View File

@ -42,9 +42,12 @@ struct dwc3_platform_data {
unsigned rx_detect_poll_quirk:1;
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
u32 fladj_value;
const char *hsphy_interface;
};

View File

@ -113,7 +113,7 @@ config USB_GADGET_VBUS_DRAW
config USB_GADGET_STORAGE_NUM_BUFFERS
int "Number of storage pipeline buffers"
range 2 4
range 2 32
default 2
help
Usually 2 buffers are enough to establish a good buffering

View File

@ -839,9 +839,7 @@ int usb_add_config(struct usb_composite_dev *cdev,
}
}
/* set_alt(), or next bind(), sets up
* ep->driver_data as needed.
*/
/* set_alt(), or next bind(), sets up ep->claimed as needed */
usb_ep_autoconfig_reset(cdev->gadget);
done:
@ -1506,6 +1504,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
} else {
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
}
} else {
cdev->desc.bcdUSB = cpu_to_le16(0x0200);
}
value = min(w_length, (u16) sizeof cdev->desc);

View File

@ -53,13 +53,13 @@
* the restrictions that may apply. Some combinations of driver
* and hardware won't be able to autoconfigure.
*
* On success, this returns an un-claimed usb_ep, and modifies the endpoint
* On success, this returns an claimed usb_ep, and modifies the endpoint
* descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
* is initialized as if the endpoint were used at full speed and
* the bmAttribute field in the ep companion descriptor is
* updated with the assigned number of streams if it is
* different from the original value. To prevent the endpoint
* from being returned by a later autoconfig call, claim it by
* from being returned by a later autoconfig call, claims it by
* assigning ep->claimed to true.
*
* On failure, this returns a null endpoint descriptor.
@ -154,10 +154,10 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
* USB controller, and it can't know all the restrictions that may apply.
* Some combinations of driver and hardware won't be able to autoconfigure.
*
* On success, this returns an un-claimed usb_ep, and modifies the endpoint
* On success, this returns an claimed usb_ep, and modifies the endpoint
* descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
* is initialized as if the endpoint were used at full speed. To prevent
* the endpoint from being returned by a later autoconfig call, claim it
* the endpoint from being returned by a later autoconfig call, claims it
* by assigning ep->claimed to true.
*
* On failure, this returns a null endpoint descriptor.
@ -171,6 +171,23 @@ struct usb_ep *usb_ep_autoconfig(
}
EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
/**
* usb_ep_autoconfig_release - releases endpoint and set it to initial state
* @ep: endpoint which should be released
*
* This function can be used during function bind for endpoints obtained
* from usb_ep_autoconfig(). It unclaims endpoint claimed by
* usb_ep_autoconfig() to make it available for other functions. Endpoint
* which was released is no longer invalid and shouldn't be used in
* context of function which released it.
*/
void usb_ep_autoconfig_release(struct usb_ep *ep)
{
ep->claimed = false;
ep->driver_data = NULL;
}
EXPORT_SYMBOL_GPL(usb_ep_autoconfig_release);
/**
* usb_ep_autoconfig_reset - reset endpoint autoconfig state
* @gadget: device for which autoconfig state will be reset

View File

@ -428,21 +428,18 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
/* we know alt == 0, so this is an activation or a reset */
if (intf == acm->ctrl_id) {
if (acm->notify->driver_data) {
dev_vdbg(&cdev->gadget->dev,
"reset acm control interface %d\n", intf);
usb_ep_disable(acm->notify);
}
dev_vdbg(&cdev->gadget->dev,
"reset acm control interface %d\n", intf);
usb_ep_disable(acm->notify);
if (!acm->notify->desc)
if (config_ep_by_speed(cdev->gadget, f, acm->notify))
return -EINVAL;
usb_ep_enable(acm->notify);
acm->notify->driver_data = acm;
} else if (intf == acm->data_id) {
if (acm->port.in->driver_data) {
if (acm->notify->enabled) {
dev_dbg(&cdev->gadget->dev,
"reset acm ttyGS%d\n", acm->port_num);
gserial_disconnect(&acm->port);
@ -475,7 +472,6 @@ static void acm_disable(struct usb_function *f)
dev_dbg(&cdev->gadget->dev, "acm ttyGS%d deactivated\n", acm->port_num);
gserial_disconnect(&acm->port);
usb_ep_disable(acm->notify);
acm->notify->driver_data = NULL;
}
/*-------------------------------------------------------------------------*/
@ -655,19 +651,16 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
acm->port.in = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
if (!ep)
goto fail;
acm->port.out = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
if (!ep)
goto fail;
acm->notify = ep;
ep->driver_data = cdev; /* claim */
/* allocate notification */
acm->notify_req = gs_alloc_req(ep,
@ -709,14 +702,6 @@ fail:
if (acm->notify_req)
gs_free_req(acm->notify, acm->notify_req);
/* we might as well release our claims on endpoints */
if (acm->notify)
acm->notify->driver_data = NULL;
if (acm->port.out)
acm->port.out->driver_data = NULL;
if (acm->port.in)
acm->port.in->driver_data = NULL;
ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
return status;

View File

@ -541,24 +541,21 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (alt != 0)
goto fail;
if (ecm->notify->driver_data) {
VDBG(cdev, "reset ecm control %d\n", intf);
usb_ep_disable(ecm->notify);
}
VDBG(cdev, "reset ecm control %d\n", intf);
usb_ep_disable(ecm->notify);
if (!(ecm->notify->desc)) {
VDBG(cdev, "init ecm ctrl %d\n", intf);
if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
goto fail;
}
usb_ep_enable(ecm->notify);
ecm->notify->driver_data = ecm;
/* Data interface has two altsettings, 0 and 1 */
} else if (intf == ecm->data_id) {
if (alt > 1)
goto fail;
if (ecm->port.in_ep->driver_data) {
if (ecm->port.in_ep->enabled) {
DBG(cdev, "reset ecm\n");
gether_disconnect(&ecm->port);
}
@ -618,7 +615,7 @@ static int ecm_get_alt(struct usb_function *f, unsigned intf)
if (intf == ecm->ctrl_id)
return 0;
return ecm->port.in_ep->driver_data ? 1 : 0;
return ecm->port.in_ep->enabled ? 1 : 0;
}
static void ecm_disable(struct usb_function *f)
@ -628,14 +625,11 @@ static void ecm_disable(struct usb_function *f)
DBG(cdev, "ecm deactivated\n");
if (ecm->port.in_ep->driver_data)
if (ecm->port.in_ep->enabled)
gether_disconnect(&ecm->port);
if (ecm->notify->driver_data) {
usb_ep_disable(ecm->notify);
ecm->notify->driver_data = NULL;
ecm->notify->desc = NULL;
}
usb_ep_disable(ecm->notify);
ecm->notify->desc = NULL;
}
/*-------------------------------------------------------------------------*/
@ -750,13 +744,11 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
ecm->port.in_ep = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc);
if (!ep)
goto fail;
ecm->port.out_ep = ep;
ep->driver_data = cdev; /* claim */
/* NOTE: a status/notification endpoint is *OPTIONAL* but we
* don't treat it that way. It's simpler, and some newer CDC
@ -766,7 +758,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
ecm->notify = ep;
ep->driver_data = cdev; /* claim */
status = -ENOMEM;
@ -820,14 +811,6 @@ fail:
usb_ep_free_request(ecm->notify, ecm->notify_req);
}
/* we might as well release our claims on endpoints */
if (ecm->notify)
ecm->notify->driver_data = NULL;
if (ecm->port.out_ep)
ecm->port.out_ep->driver_data = NULL;
if (ecm->port.in_ep)
ecm->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;

View File

@ -195,11 +195,8 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
goto fail;
if (intf == eem->ctrl_id) {
if (eem->port.in_ep->driver_data) {
DBG(cdev, "reset eem\n");
gether_disconnect(&eem->port);
}
DBG(cdev, "reset eem\n");
gether_disconnect(&eem->port);
if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
DBG(cdev, "init eem\n");
@ -237,7 +234,7 @@ static void eem_disable(struct usb_function *f)
DBG(cdev, "eem deactivated\n");
if (eem->port.in_ep->driver_data)
if (eem->port.in_ep->enabled)
gether_disconnect(&eem->port);
}
@ -293,13 +290,11 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
eem->port.in_ep = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc);
if (!ep)
goto fail;
eem->port.out_ep = ep;
ep->driver_data = cdev; /* claim */
status = -ENOMEM;
@ -325,11 +320,6 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
fail:
if (eem->port.out_ep)
eem->port.out_ep->driver_data = NULL;
if (eem->port.in_ep)
eem->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;

View File

@ -492,10 +492,7 @@ static void hidg_disable(struct usb_function *f)
struct f_hidg_req_list *list, *next;
usb_ep_disable(hidg->in_ep);
hidg->in_ep->driver_data = NULL;
usb_ep_disable(hidg->out_ep);
hidg->out_ep->driver_data = NULL;
list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
list_del(&list->list);
@ -513,8 +510,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (hidg->in_ep != NULL) {
/* restart endpoint */
if (hidg->in_ep->driver_data != NULL)
usb_ep_disable(hidg->in_ep);
usb_ep_disable(hidg->in_ep);
status = config_ep_by_speed(f->config->cdev->gadget, f,
hidg->in_ep);
@ -533,8 +529,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (hidg->out_ep != NULL) {
/* restart endpoint */
if (hidg->out_ep->driver_data != NULL)
usb_ep_disable(hidg->out_ep);
usb_ep_disable(hidg->out_ep);
status = config_ep_by_speed(f->config->cdev->gadget, f,
hidg->out_ep);
@ -566,7 +561,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
hidg->out_ep->name, status);
} else {
usb_ep_disable(hidg->out_ep);
hidg->out_ep->driver_data = NULL;
status = -ENOMEM;
goto fail;
}
@ -614,13 +608,11 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
if (!ep)
goto fail;
ep->driver_data = c->cdev; /* claim */
hidg->in_ep = ep;
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
if (!ep)
goto fail;
ep->driver_data = c->cdev; /* claim */
hidg->out_ep = ep;
/* preallocate request and buffer */

View File

@ -34,6 +34,9 @@ struct f_loopback {
struct usb_ep *in_ep;
struct usb_ep *out_ep;
unsigned qlen;
unsigned buflen;
};
static inline struct f_loopback *func_to_loop(struct usb_function *f)
@ -41,13 +44,10 @@ static inline struct f_loopback *func_to_loop(struct usb_function *f)
return container_of(f, struct f_loopback, function);
}
static unsigned qlen;
static unsigned buflen;
/*-------------------------------------------------------------------------*/
static struct usb_interface_descriptor loopback_intf = {
.bLength = sizeof loopback_intf,
.bLength = sizeof(loopback_intf),
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 2,
@ -195,12 +195,10 @@ autoconf_fail:
f->name, cdev->gadget->name);
return -ENODEV;
}
loop->in_ep->driver_data = cdev; /* claim */
loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
if (!loop->out_ep)
goto autoconf_fail;
loop->out_ep->driver_data = cdev; /* claim */
/* support high speed hardware */
hs_loop_source_desc.bEndpointAddress =
@ -245,22 +243,38 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
int status = req->status;
switch (status) {
case 0: /* normal completion? */
if (ep == loop->out_ep) {
req->zero = (req->actual < req->length);
req->length = req->actual;
/*
* We received some data from the host so let's
* queue it so host can read the from our in ep
*/
struct usb_request *in_req = req->context;
in_req->zero = (req->actual < req->length);
in_req->length = req->actual;
ep = loop->in_ep;
req = in_req;
} else {
/*
* We have just looped back a bunch of data
* to host. Now let's wait for some more data.
*/
req = req->context;
ep = loop->out_ep;
}
/* queue the buffer for some later OUT packet */
req->length = buflen;
/* queue the buffer back to host or for next bunch of data */
status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status == 0)
if (status == 0) {
return;
} else {
ERROR(cdev, "Unable to loop back buffer to %s: %d\n",
ep->name, status);
goto free_req;
}
/* "should never get here" */
/* FALLTHROUGH */
default:
ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
@ -274,6 +288,10 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
free_req:
usb_ep_free_request(ep == loop->in_ep ?
loop->out_ep : loop->in_ep,
req->context);
free_ep_req(ep, req);
return;
}
@ -290,53 +308,77 @@ static void disable_loopback(struct f_loopback *loop)
static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
{
return alloc_ep_req(ep, len, buflen);
struct f_loopback *loop = ep->driver_data;
return alloc_ep_req(ep, len, loop->buflen);
}
static int enable_endpoint(struct usb_composite_dev *cdev, struct f_loopback *loop,
struct usb_ep *ep)
static int alloc_requests(struct usb_composite_dev *cdev,
struct f_loopback *loop)
{
struct usb_request *req;
unsigned i;
int result;
/*
* one endpoint writes data back IN to the host while another endpoint
* just reads OUT packets
*/
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
if (result)
goto fail0;
result = usb_ep_enable(ep);
if (result < 0)
goto fail0;
ep->driver_data = loop;
struct usb_request *in_req, *out_req;
int i;
int result = 0;
/*
* allocate a bunch of read buffers and queue them all at once.
* we buffer at most 'qlen' transfers; fewer if any need more
* than 'buflen' bytes each.
* we buffer at most 'qlen' transfers; We allocate buffers only
* for out transfer and reuse them in IN transfers to implement
* our loopback functionality
*/
for (i = 0; i < qlen && result == 0; i++) {
req = lb_alloc_ep_req(ep, 0);
if (!req)
goto fail1;
for (i = 0; i < loop->qlen && result == 0; i++) {
result = -ENOMEM;
req->complete = loopback_complete;
result = usb_ep_queue(ep, req, GFP_ATOMIC);
in_req = usb_ep_alloc_request(loop->in_ep, GFP_KERNEL);
if (!in_req)
goto fail;
out_req = lb_alloc_ep_req(loop->out_ep, 0);
if (!out_req)
goto fail_in;
in_req->complete = loopback_complete;
out_req->complete = loopback_complete;
in_req->buf = out_req->buf;
/* length will be set in complete routine */
in_req->context = out_req;
out_req->context = in_req;
result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
if (result) {
ERROR(cdev, "%s queue req --> %d\n",
ep->name, result);
goto fail1;
loop->out_ep->name, result);
goto fail_out;
}
}
return 0;
fail1:
usb_ep_disable(ep);
fail_out:
free_ep_req(loop->out_ep, out_req);
fail_in:
usb_ep_free_request(loop->in_ep, in_req);
fail:
return result;
}
fail0:
static int enable_endpoint(struct usb_composite_dev *cdev,
struct f_loopback *loop, struct usb_ep *ep)
{
int result;
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
if (result)
goto out;
result = usb_ep_enable(ep);
if (result < 0)
goto out;
ep->driver_data = loop;
result = 0;
out:
return result;
}
@ -347,13 +389,24 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
result = enable_endpoint(cdev, loop, loop->in_ep);
if (result)
return result;
goto out;
result = enable_endpoint(cdev, loop, loop->out_ep);
if (result)
return result;
goto disable_in;
result = alloc_requests(cdev, loop);
if (result)
goto disable_out;
DBG(cdev, "%s enabled\n", loop->function.name);
return 0;
disable_out:
usb_ep_disable(loop->out_ep);
disable_in:
usb_ep_disable(loop->in_ep);
out:
return result;
}
@ -364,8 +417,7 @@ static int loopback_set_alt(struct usb_function *f,
struct usb_composite_dev *cdev = f->config->cdev;
/* we know alt is zero */
if (loop->in_ep->driver_data)
disable_loopback(loop);
disable_loopback(loop);
return enable_loopback(cdev, loop);
}
@ -391,10 +443,10 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
lb_opts->refcnt++;
mutex_unlock(&lb_opts->lock);
buflen = lb_opts->bulk_buflen;
qlen = lb_opts->qlen;
if (!qlen)
qlen = 32;
loop->buflen = lb_opts->bulk_buflen;
loop->qlen = lb_opts->qlen;
if (!loop->qlen)
loop->qlen = 32;
loop->function.name = "loopback";
loop->function.bind = loopback_bind;
@ -434,7 +486,7 @@ static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->qlen);
result = sprintf(page, "%d\n", opts->qlen);
mutex_unlock(&opts->lock);
return result;
@ -473,7 +525,7 @@ static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->bulk_buflen);
result = sprintf(page, "%d\n", opts->bulk_buflen);
mutex_unlock(&opts->lock);
return result;

View File

@ -2258,12 +2258,10 @@ reset:
/* Disable the endpoints */
if (fsg->bulk_in_enabled) {
usb_ep_disable(fsg->bulk_in);
fsg->bulk_in->driver_data = NULL;
fsg->bulk_in_enabled = 0;
}
if (fsg->bulk_out_enabled) {
usb_ep_disable(fsg->bulk_out);
fsg->bulk_out->driver_data = NULL;
fsg->bulk_out_enabled = 0;
}
@ -2662,10 +2660,12 @@ EXPORT_SYMBOL_GPL(fsg_common_put);
/* check if fsg_num_buffers is within a valid range */
static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers)
{
if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4)
#define FSG_MAX_NUM_BUFFERS 32
if (fsg_num_buffers >= 2 && fsg_num_buffers <= FSG_MAX_NUM_BUFFERS)
return 0;
pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
fsg_num_buffers, 2, 4);
fsg_num_buffers, 2, FSG_MAX_NUM_BUFFERS);
return -EINVAL;
}
@ -3070,13 +3070,11 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
if (!ep)
goto autoconf_fail;
ep->driver_data = fsg->common; /* claim the endpoint */
fsg->bulk_in = ep;
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
if (!ep)
goto autoconf_fail;
ep->driver_data = fsg->common; /* claim the endpoint */
fsg->bulk_out = ep;
/* Assume endpoint addresses are the same for both speeds */

View File

@ -302,8 +302,7 @@ static int f_midi_start_ep(struct f_midi *midi,
int err;
struct usb_composite_dev *cdev = f->config->cdev;
if (ep->driver_data)
usb_ep_disable(ep);
usb_ep_disable(ep);
err = config_ep_by_speed(midi->gadget, f, ep);
if (err) {
@ -341,8 +340,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (err)
return err;
if (midi->out_ep->driver_data)
usb_ep_disable(midi->out_ep);
usb_ep_disable(midi->out_ep);
err = config_ep_by_speed(midi->gadget, f, midi->out_ep);
if (err) {
@ -547,10 +545,16 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
}
}
if (req->length > 0)
usb_ep_queue(ep, req, GFP_ATOMIC);
else
if (req->length > 0) {
int err;
err = usb_ep_queue(ep, req, GFP_ATOMIC);
if (err < 0)
ERROR(midi, "%s queue req: %d\n",
midi->in_ep->name, err);
} else {
free_ep_req(ep, req);
}
}
static void f_midi_in_tasklet(unsigned long data)
@ -757,12 +761,10 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc);
if (!midi->in_ep)
goto fail;
midi->in_ep->driver_data = cdev; /* claim */
midi->out_ep = usb_ep_autoconfig(cdev->gadget, &bulk_out_desc);
if (!midi->out_ep)
goto fail;
midi->out_ep->driver_data = cdev; /* claim */
/* allocate temporary function list */
midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function),
@ -889,12 +891,6 @@ fail_f_midi:
fail:
f_midi_unregister_card(midi);
fail_register:
/* we might as well release our claims on endpoints */
if (midi->out_ep)
midi->out_ep->driver_data = NULL;
if (midi->in_ep)
midi->in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;

View File

@ -586,7 +586,7 @@ static void ncm_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
unsigned in_size;
struct usb_function *f = req->context;
struct f_ncm *ncm = func_to_ncm(f);
struct usb_composite_dev *cdev = ep->driver_data;
struct usb_composite_dev *cdev = f->config->cdev;
req->context = NULL;
if (req->status || req->actual != req->length) {
@ -803,10 +803,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (alt != 0)
goto fail;
if (ncm->notify->driver_data) {
DBG(cdev, "reset ncm control %d\n", intf);
usb_ep_disable(ncm->notify);
}
DBG(cdev, "reset ncm control %d\n", intf);
usb_ep_disable(ncm->notify);
if (!(ncm->notify->desc)) {
DBG(cdev, "init ncm ctrl %d\n", intf);
@ -814,14 +812,13 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
goto fail;
}
usb_ep_enable(ncm->notify);
ncm->notify->driver_data = ncm;
/* Data interface has two altsettings, 0 and 1 */
} else if (intf == ncm->data_id) {
if (alt > 1)
goto fail;
if (ncm->port.in_ep->driver_data) {
if (ncm->port.in_ep->enabled) {
DBG(cdev, "reset ncm\n");
ncm->timer_stopping = true;
ncm->netdev = NULL;
@ -885,7 +882,7 @@ static int ncm_get_alt(struct usb_function *f, unsigned intf)
if (intf == ncm->ctrl_id)
return 0;
return ncm->port.in_ep->driver_data ? 1 : 0;
return ncm->port.in_ep->enabled ? 1 : 0;
}
static struct sk_buff *package_for_tx(struct f_ncm *ncm)
@ -1276,15 +1273,14 @@ static void ncm_disable(struct usb_function *f)
DBG(cdev, "ncm deactivated\n");
if (ncm->port.in_ep->driver_data) {
if (ncm->port.in_ep->enabled) {
ncm->timer_stopping = true;
ncm->netdev = NULL;
gether_disconnect(&ncm->port);
}
if (ncm->notify->driver_data) {
if (ncm->notify->enabled) {
usb_ep_disable(ncm->notify);
ncm->notify->driver_data = NULL;
ncm->notify->desc = NULL;
}
}
@ -1402,19 +1398,16 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
ncm->port.in_ep = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_out_desc);
if (!ep)
goto fail;
ncm->port.out_ep = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_notify_desc);
if (!ep)
goto fail;
ncm->notify = ep;
ep->driver_data = cdev; /* claim */
status = -ENOMEM;
@ -1468,14 +1461,6 @@ fail:
usb_ep_free_request(ncm->notify, ncm->notify_req);
}
/* we might as well release our claims on endpoints */
if (ncm->notify)
ncm->notify->driver_data = NULL;
if (ncm->port.out_ep)
ncm->port.out_ep->driver_data = NULL;
if (ncm->port.in_ep)
ncm->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;

View File

@ -206,7 +206,7 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (alt > 1)
goto fail;
if (obex->port.in->driver_data) {
if (obex->port.in->enabled) {
dev_dbg(&cdev->gadget->dev,
"reset obex ttyGS%d\n", obex->port_num);
gserial_disconnect(&obex->port);
@ -348,13 +348,11 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
obex->port.in = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_out_desc);
if (!ep)
goto fail;
obex->port.out = ep;
ep->driver_data = cdev; /* claim */
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
@ -378,12 +376,6 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
fail:
/* we might as well release our claims on endpoints */
if (obex->port.out)
obex->port.out->driver_data = NULL;
if (obex->port.in)
obex->port.in->driver_data = NULL;
ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
return status;

View File

@ -418,7 +418,7 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
spin_lock(&port->lock);
if (fp->in_ep->driver_data)
if (fp->in_ep->enabled)
__pn_reset(f);
if (alt == 1) {
@ -530,13 +530,11 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto err;
fp->out_ep = ep;
ep->driver_data = fp; /* Claim */
ep = usb_ep_autoconfig(gadget, &pn_fs_source_desc);
if (!ep)
goto err;
fp->in_ep = ep;
ep->driver_data = fp; /* Claim */
pn_hs_sink_desc.bEndpointAddress = pn_fs_sink_desc.bEndpointAddress;
pn_hs_source_desc.bEndpointAddress = pn_fs_source_desc.bEndpointAddress;
@ -575,10 +573,6 @@ err_req:
usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
usb_free_all_descriptors(f);
err:
if (fp->out_ep)
fp->out_ep->driver_data = NULL;
if (fp->in_ep)
fp->in_ep->driver_data = NULL;
ERROR(cdev, "USB CDC Phonet: cannot autoconfigure\n");
return status;
}

View File

@ -1039,12 +1039,10 @@ autoconf_fail:
cdev->gadget->name);
return -ENODEV;
}
in_ep->driver_data = in_ep; /* claim */
out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
if (!out_ep)
goto autoconf_fail;
out_ep->driver_data = out_ep; /* claim */
/* assumes that all endpoints are dual-speed */
hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;

View File

@ -543,22 +543,20 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
/* we know alt == 0 */
if (intf == rndis->ctrl_id) {
if (rndis->notify->driver_data) {
VDBG(cdev, "reset rndis control %d\n", intf);
usb_ep_disable(rndis->notify);
}
VDBG(cdev, "reset rndis control %d\n", intf);
usb_ep_disable(rndis->notify);
if (!rndis->notify->desc) {
VDBG(cdev, "init rndis ctrl %d\n", intf);
if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
goto fail;
}
usb_ep_enable(rndis->notify);
rndis->notify->driver_data = rndis;
} else if (intf == rndis->data_id) {
struct net_device *net;
if (rndis->port.in_ep->driver_data) {
if (rndis->port.in_ep->enabled) {
DBG(cdev, "reset rndis\n");
gether_disconnect(&rndis->port);
}
@ -612,7 +610,7 @@ static void rndis_disable(struct usb_function *f)
struct f_rndis *rndis = func_to_rndis(f);
struct usb_composite_dev *cdev = f->config->cdev;
if (!rndis->notify->driver_data)
if (!rndis->notify->enabled)
return;
DBG(cdev, "rndis deactivated\n");
@ -621,7 +619,6 @@ static void rndis_disable(struct usb_function *f)
gether_disconnect(&rndis->port);
usb_ep_disable(rndis->notify);
rndis->notify->driver_data = NULL;
}
/*-------------------------------------------------------------------------*/
@ -745,13 +742,11 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
rndis->port.in_ep = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
if (!ep)
goto fail;
rndis->port.out_ep = ep;
ep->driver_data = cdev; /* claim */
/* NOTE: a status/notification endpoint is, strictly speaking,
* optional. We don't treat it that way though! It's simpler,
@ -761,7 +756,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
rndis->notify = ep;
ep->driver_data = cdev; /* claim */
status = -ENOMEM;
@ -829,14 +823,6 @@ fail:
usb_ep_free_request(rndis->notify, rndis->notify_req);
}
/* we might as well release our claims on endpoints */
if (rndis->notify)
rndis->notify->driver_data = NULL;
if (rndis->port.out_ep)
rndis->port.out_ep->driver_data = NULL;
if (rndis->port.in_ep)
rndis->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;

View File

@ -153,7 +153,7 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
/* we know alt == 0, so this is an activation or a reset */
if (gser->port.in->driver_data) {
if (gser->port.in->enabled) {
dev_dbg(&cdev->gadget->dev,
"reset generic ttyGS%d\n", gser->port_num);
gserial_disconnect(&gser->port);
@ -219,13 +219,11 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
gser->port.in = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
if (!ep)
goto fail;
gser->port.out = ep;
ep->driver_data = cdev; /* claim */
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
@ -249,12 +247,6 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
fail:
/* we might as well release our claims on endpoints */
if (gser->port.out)
gser->port.out->driver_data = NULL;
if (gser->port.in)
gser->port.in->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;

View File

@ -50,6 +50,13 @@ struct f_sourcesink {
struct usb_ep *iso_in_ep;
struct usb_ep *iso_out_ep;
int cur_alt;
unsigned pattern;
unsigned isoc_interval;
unsigned isoc_maxpacket;
unsigned isoc_mult;
unsigned isoc_maxburst;
unsigned buflen;
};
static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
@ -57,13 +64,6 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
return container_of(f, struct f_sourcesink, function);
}
static unsigned pattern;
static unsigned isoc_interval;
static unsigned isoc_maxpacket;
static unsigned isoc_mult;
static unsigned isoc_maxburst;
static unsigned buflen;
/*-------------------------------------------------------------------------*/
static struct usb_interface_descriptor source_sink_intf_alt0 = {
@ -298,7 +298,9 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
{
return alloc_ep_req(ep, len, buflen);
struct f_sourcesink *ss = ep->driver_data;
return alloc_ep_req(ep, len, ss->buflen);
}
void free_ep_req(struct usb_ep *ep, struct usb_request *req)
@ -311,13 +313,9 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
{
int value;
if (ep->driver_data) {
value = usb_ep_disable(ep);
if (value < 0)
DBG(cdev, "disable %s --> %d\n",
ep->name, value);
ep->driver_data = NULL;
}
value = usb_ep_disable(ep);
if (value < 0)
DBG(cdev, "disable %s --> %d\n", ep->name, value);
}
void disable_endpoints(struct usb_composite_dev *cdev,
@ -355,42 +353,37 @@ autoconf_fail:
f->name, cdev->gadget->name);
return -ENODEV;
}
ss->in_ep->driver_data = cdev; /* claim */
ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
if (!ss->out_ep)
goto autoconf_fail;
ss->out_ep->driver_data = cdev; /* claim */
/* sanity check the isoc module parameters */
if (isoc_interval < 1)
isoc_interval = 1;
if (isoc_interval > 16)
isoc_interval = 16;
if (isoc_mult > 2)
isoc_mult = 2;
if (isoc_maxburst > 15)
isoc_maxburst = 15;
if (ss->isoc_interval < 1)
ss->isoc_interval = 1;
if (ss->isoc_interval > 16)
ss->isoc_interval = 16;
if (ss->isoc_mult > 2)
ss->isoc_mult = 2;
if (ss->isoc_maxburst > 15)
ss->isoc_maxburst = 15;
/* fill in the FS isoc descriptors from the module parameters */
fs_iso_source_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
1023 : isoc_maxpacket;
fs_iso_source_desc.bInterval = isoc_interval;
fs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
1023 : isoc_maxpacket;
fs_iso_sink_desc.bInterval = isoc_interval;
fs_iso_source_desc.wMaxPacketSize = ss->isoc_maxpacket > 1023 ?
1023 : ss->isoc_maxpacket;
fs_iso_source_desc.bInterval = ss->isoc_interval;
fs_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket > 1023 ?
1023 : ss->isoc_maxpacket;
fs_iso_sink_desc.bInterval = ss->isoc_interval;
/* allocate iso endpoints */
ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
if (!ss->iso_in_ep)
goto no_iso;
ss->iso_in_ep->driver_data = cdev; /* claim */
ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
if (ss->iso_out_ep) {
ss->iso_out_ep->driver_data = cdev; /* claim */
} else {
ss->iso_in_ep->driver_data = NULL;
if (!ss->iso_out_ep) {
usb_ep_autoconfig_release(ss->iso_in_ep);
ss->iso_in_ep = NULL;
no_iso:
/*
@ -403,8 +396,8 @@ no_iso:
ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
}
if (isoc_maxpacket > 1024)
isoc_maxpacket = 1024;
if (ss->isoc_maxpacket > 1024)
ss->isoc_maxpacket = 1024;
/* support high speed hardware */
hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
@ -415,15 +408,15 @@ no_iso:
* We assume that the user knows what they are doing and won't
* give parameters that their UDC doesn't support.
*/
hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
hs_iso_source_desc.bInterval = isoc_interval;
hs_iso_source_desc.wMaxPacketSize = ss->isoc_maxpacket;
hs_iso_source_desc.wMaxPacketSize |= ss->isoc_mult << 11;
hs_iso_source_desc.bInterval = ss->isoc_interval;
hs_iso_source_desc.bEndpointAddress =
fs_iso_source_desc.bEndpointAddress;
hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
hs_iso_sink_desc.bInterval = isoc_interval;
hs_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket;
hs_iso_sink_desc.wMaxPacketSize |= ss->isoc_mult << 11;
hs_iso_sink_desc.bInterval = ss->isoc_interval;
hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
/* support super speed hardware */
@ -437,21 +430,21 @@ no_iso:
* We assume that the user knows what they are doing and won't
* give parameters that their UDC doesn't support.
*/
ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
ss_iso_source_desc.bInterval = isoc_interval;
ss_iso_source_comp_desc.bmAttributes = isoc_mult;
ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
ss_iso_source_comp_desc.wBytesPerInterval =
isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
ss_iso_source_desc.wMaxPacketSize = ss->isoc_maxpacket;
ss_iso_source_desc.bInterval = ss->isoc_interval;
ss_iso_source_comp_desc.bmAttributes = ss->isoc_mult;
ss_iso_source_comp_desc.bMaxBurst = ss->isoc_maxburst;
ss_iso_source_comp_desc.wBytesPerInterval = ss->isoc_maxpacket *
(ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
ss_iso_source_desc.bEndpointAddress =
fs_iso_source_desc.bEndpointAddress;
ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
ss_iso_sink_desc.bInterval = isoc_interval;
ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
ss_iso_sink_comp_desc.wBytesPerInterval =
isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
ss_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket;
ss_iso_sink_desc.bInterval = ss->isoc_interval;
ss_iso_sink_comp_desc.bmAttributes = ss->isoc_mult;
ss_iso_sink_comp_desc.bMaxBurst = ss->isoc_maxburst;
ss_iso_sink_comp_desc.wBytesPerInterval = ss->isoc_maxpacket *
(ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
ret = usb_assign_descriptors(f, fs_source_sink_descs,
@ -489,12 +482,13 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
unsigned i;
u8 *buf = req->buf;
struct usb_composite_dev *cdev = ss->function.config->cdev;
int max_packet_size = le16_to_cpu(ss->out_ep->desc->wMaxPacketSize);
if (pattern == 2)
if (ss->pattern == 2)
return 0;
for (i = 0; i < req->actual; i++, buf++) {
switch (pattern) {
switch (ss->pattern) {
/* all-zeroes has no synchronization issues */
case 0:
@ -510,7 +504,7 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
* stutter for any reason, including buffer duplication...)
*/
case 1:
if (*buf == (u8)(i % 63))
if (*buf == (u8)((i % max_packet_size) % 63))
continue;
break;
}
@ -525,14 +519,16 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
{
unsigned i;
u8 *buf = req->buf;
int max_packet_size = le16_to_cpu(ep->desc->wMaxPacketSize);
struct f_sourcesink *ss = ep->driver_data;
switch (pattern) {
switch (ss->pattern) {
case 0:
memset(req->buf, 0, req->length);
break;
case 1:
for (i = 0; i < req->length; i++)
*buf++ = (u8) (i % 63);
*buf++ = (u8) ((i % max_packet_size) % 63);
break;
case 2:
break;
@ -556,7 +552,7 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
case 0: /* normal completion? */
if (ep == ss->out_ep) {
check_read_data(ss, req);
if (pattern != 2)
if (ss->pattern != 2)
memset(req->buf, 0x55, req->length);
}
break;
@ -605,15 +601,16 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
if (is_iso) {
switch (speed) {
case USB_SPEED_SUPER:
size = isoc_maxpacket * (isoc_mult + 1) *
(isoc_maxburst + 1);
size = ss->isoc_maxpacket *
(ss->isoc_mult + 1) *
(ss->isoc_maxburst + 1);
break;
case USB_SPEED_HIGH:
size = isoc_maxpacket * (isoc_mult + 1);
size = ss->isoc_maxpacket * (ss->isoc_mult + 1);
break;
default:
size = isoc_maxpacket > 1023 ?
1023 : isoc_maxpacket;
size = ss->isoc_maxpacket > 1023 ?
1023 : ss->isoc_maxpacket;
break;
}
ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
@ -629,7 +626,7 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
req->complete = source_sink_complete;
if (is_in)
reinit_write_data(ep, req);
else if (pattern != 2)
else if (ss->pattern != 2)
memset(req->buf, 0x55, req->length);
status = usb_ep_queue(ep, req, GFP_ATOMIC);
@ -683,7 +680,6 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
fail:
ep = ss->in_ep;
usb_ep_disable(ep);
ep->driver_data = NULL;
return result;
}
@ -702,7 +698,6 @@ fail:
fail2:
ep = ss->out_ep;
usb_ep_disable(ep);
ep->driver_data = NULL;
goto fail;
}
@ -724,10 +719,8 @@ fail2:
if (result < 0) {
fail3:
ep = ss->iso_in_ep;
if (ep) {
if (ep)
usb_ep_disable(ep);
ep->driver_data = NULL;
}
goto fail2;
}
}
@ -746,7 +739,6 @@ fail3:
result = source_sink_start_ep(ss, false, true, speed);
if (result < 0) {
usb_ep_disable(ep);
ep->driver_data = NULL;
goto fail3;
}
}
@ -763,8 +755,7 @@ static int sourcesink_set_alt(struct usb_function *f,
struct f_sourcesink *ss = func_to_ss(f);
struct usb_composite_dev *cdev = f->config->cdev;
if (ss->in_ep->driver_data)
disable_source_sink(ss);
disable_source_sink(ss);
return enable_source_sink(cdev, ss, alt);
}
@ -872,12 +863,12 @@ static struct usb_function *source_sink_alloc_func(
ss_opts->refcnt++;
mutex_unlock(&ss_opts->lock);
pattern = ss_opts->pattern;
isoc_interval = ss_opts->isoc_interval;
isoc_maxpacket = ss_opts->isoc_maxpacket;
isoc_mult = ss_opts->isoc_mult;
isoc_maxburst = ss_opts->isoc_maxburst;
buflen = ss_opts->bulk_buflen;
ss->pattern = ss_opts->pattern;
ss->isoc_interval = ss_opts->isoc_interval;
ss->isoc_maxpacket = ss_opts->isoc_maxpacket;
ss->isoc_mult = ss_opts->isoc_mult;
ss->isoc_maxburst = ss_opts->isoc_maxburst;
ss->buflen = ss_opts->bulk_buflen;
ss->function.name = "source/sink";
ss->function.bind = sourcesink_bind;
@ -919,7 +910,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, "%u", opts->pattern);
result = sprintf(page, "%u\n", opts->pattern);
mutex_unlock(&opts->lock);
return result;
@ -963,7 +954,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, "%u", opts->isoc_interval);
result = sprintf(page, "%u\n", opts->isoc_interval);
mutex_unlock(&opts->lock);
return result;
@ -1007,7 +998,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, "%u", opts->isoc_maxpacket);
result = sprintf(page, "%u\n", opts->isoc_maxpacket);
mutex_unlock(&opts->lock);
return result;
@ -1051,7 +1042,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, "%u", opts->isoc_mult);
result = sprintf(page, "%u\n", opts->isoc_mult);
mutex_unlock(&opts->lock);
return result;
@ -1095,7 +1086,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, "%u", opts->isoc_maxburst);
result = sprintf(page, "%u\n", opts->isoc_maxburst);
mutex_unlock(&opts->lock);
return result;
@ -1139,7 +1130,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, "%u", opts->bulk_buflen);
result = sprintf(page, "%u\n", opts->bulk_buflen);
mutex_unlock(&opts->lock);
return result;

View File

@ -262,7 +262,7 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
/* we know alt == 0, so this is an activation or a reset */
if (geth->port.in_ep->driver_data) {
if (geth->port.in_ep->enabled) {
DBG(cdev, "reset cdc subset\n");
gether_disconnect(&geth->port);
}
@ -343,13 +343,11 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
if (!ep)
goto fail;
geth->port.in_ep = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc);
if (!ep)
goto fail;
geth->port.out_ep = ep;
ep->driver_data = cdev; /* claim */
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
@ -380,12 +378,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
fail:
/* we might as well release our claims on endpoints */
if (geth->port.out_ep)
geth->port.out_ep->driver_data = NULL;
if (geth->port.in_ep)
geth->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;

View File

@ -593,7 +593,6 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
return err;
usb_ep_enable(out_ep);
out_ep->driver_data = audio;
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
if (IS_ERR(audio->copy_buf))
return -ENOMEM;
@ -718,7 +717,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
goto fail;
audio->out_ep = ep;
audio->out_ep->desc = &as_out_ep_desc;
ep->driver_data = cdev; /* claim */
status = -ENOMEM;
@ -730,8 +728,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
fail:
gaudio_cleanup(&audio->card);
if (ep)
ep->driver_data = NULL;
return status;
}

View File

@ -1081,14 +1081,12 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
goto err;
}
agdev->out_ep->driver_data = agdev;
agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
if (!agdev->in_ep) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
goto err;
}
agdev->in_ep->driver_data = agdev;
uac2->p_prm.uac2 = uac2;
uac2->c_prm.uac2 = uac2;
@ -1132,10 +1130,6 @@ err_free_descs:
err:
kfree(agdev->uac2.p_prm.rbuf);
kfree(agdev->uac2.c_prm.rbuf);
if (agdev->in_ep)
agdev->in_ep->driver_data = NULL;
if (agdev->out_ep)
agdev->out_ep->driver_data = NULL;
return -EINVAL;
}
@ -1583,11 +1577,6 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
prm = &agdev->uac2.c_prm;
kfree(prm->rbuf);
usb_free_all_descriptors(f);
if (agdev->in_ep)
agdev->in_ep->driver_data = NULL;
if (agdev->out_ep)
agdev->out_ep->driver_data = NULL;
}
static struct usb_function *afunc_alloc(struct usb_function_instance *fi)

View File

@ -280,7 +280,7 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface)
else if (interface != uvc->streaming_intf)
return -EINVAL;
else
return uvc->video.ep->driver_data ? 1 : 0;
return uvc->video.ep->enabled ? 1 : 0;
}
static int
@ -298,18 +298,14 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (alt)
return -EINVAL;
if (uvc->control_ep->driver_data) {
INFO(cdev, "reset UVC Control\n");
usb_ep_disable(uvc->control_ep);
uvc->control_ep->driver_data = NULL;
}
INFO(cdev, "reset UVC Control\n");
usb_ep_disable(uvc->control_ep);
if (!uvc->control_ep->desc)
if (config_ep_by_speed(cdev->gadget, f, uvc->control_ep))
return -EINVAL;
usb_ep_enable(uvc->control_ep);
uvc->control_ep->driver_data = uvc;
if (uvc->state == UVC_STATE_DISCONNECTED) {
memset(&v4l2_event, 0, sizeof(v4l2_event));
@ -336,10 +332,8 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (uvc->state != UVC_STATE_STREAMING)
return 0;
if (uvc->video.ep) {
if (uvc->video.ep)
usb_ep_disable(uvc->video.ep);
uvc->video.ep->driver_data = NULL;
}
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMOFF;
@ -355,18 +349,14 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (!uvc->video.ep)
return -EINVAL;
if (uvc->video.ep->driver_data) {
INFO(cdev, "reset UVC\n");
usb_ep_disable(uvc->video.ep);
uvc->video.ep->driver_data = NULL;
}
INFO(cdev, "reset UVC\n");
usb_ep_disable(uvc->video.ep);
ret = config_ep_by_speed(f->config->cdev->gadget,
&(uvc->func), uvc->video.ep);
if (ret)
return ret;
usb_ep_enable(uvc->video.ep);
uvc->video.ep->driver_data = uvc;
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
@ -392,15 +382,8 @@ uvc_function_disable(struct usb_function *f)
uvc->state = UVC_STATE_DISCONNECTED;
if (uvc->video.ep->driver_data) {
usb_ep_disable(uvc->video.ep);
uvc->video.ep->driver_data = NULL;
}
if (uvc->control_ep->driver_data) {
usb_ep_disable(uvc->control_ep);
uvc->control_ep->driver_data = NULL;
}
usb_ep_disable(uvc->video.ep);
usb_ep_disable(uvc->control_ep);
}
/* --------------------------------------------------------------------------
@ -651,7 +634,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
goto error;
}
uvc->control_ep = ep;
ep->driver_data = uvc;
if (gadget_is_superspeed(c->cdev->gadget))
ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
@ -666,7 +648,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
goto error;
}
uvc->video.ep = ep;
ep->driver_data = uvc;
uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
@ -755,11 +736,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
error:
v4l2_device_unregister(&uvc->v4l2_dev);
if (uvc->control_ep)
uvc->control_ep->driver_data = NULL;
if (uvc->video.ep)
uvc->video.ep->driver_data = NULL;
if (uvc->control_req)
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf);
@ -886,8 +862,6 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
video_unregister_device(&uvc->vdev);
v4l2_device_unregister(&uvc->v4l2_dev);
uvc->control_ep->driver_data = NULL;
uvc->video.ep->driver_data = NULL;
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf);

View File

@ -48,6 +48,11 @@
#define UETH__VERSION "29-May-2008"
/* Experiments show that both Linux and Windows hosts allow up to 16k
* frame sizes. Set the max size to 15k+52 to prevent allocating 32k
* blocks and still have efficient handling. */
#define GETHER_MAX_ETH_FRAME_LEN 15412
struct eth_dev {
/* lock is held while accessing port_usb
*/
@ -146,7 +151,7 @@ static int ueth_change_mtu(struct net_device *net, int new_mtu)
spin_lock_irqsave(&dev->lock, flags);
if (dev->port_usb)
status = -EBUSY;
else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
else if (new_mtu <= ETH_HLEN || new_mtu > GETHER_MAX_ETH_FRAME_LEN)
status = -ERANGE;
else
net->mtu = new_mtu;
@ -294,7 +299,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
while (skb2) {
if (status < 0
|| ETH_HLEN > skb2->len
|| skb2->len > VLAN_ETH_FRAME_LEN) {
|| skb2->len > GETHER_MAX_ETH_FRAME_LEN) {
dev->net->stats.rx_errors++;
dev->net->stats.rx_length_errors++;
DBG(dev, "rx length %d\n", skb2->len);
@ -1144,7 +1149,6 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->req_lock);
}
spin_unlock(&dev->req_lock);
link->in_ep->driver_data = NULL;
link->in_ep->desc = NULL;
usb_ep_disable(link->out_ep);
@ -1159,7 +1163,6 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->req_lock);
}
spin_unlock(&dev->req_lock);
link->out_ep->driver_data = NULL;
link->out_ep->desc = NULL;
/* finish forgetting about this USB link episode */

View File

@ -876,7 +876,6 @@ static void gs_close(struct tty_struct *tty, struct file *file)
else
gs_buf_clear(&port->port_write_buf);
tty->driver_data = NULL;
port->port.tty = NULL;
port->openclose = false;
@ -1224,7 +1223,6 @@ int gserial_connect(struct gserial *gser, u8 port_num)
fail_out:
usb_ep_disable(gser->in);
gser->in->driver_data = NULL;
return status;
}
EXPORT_SYMBOL_GPL(gserial_connect);
@ -1264,10 +1262,7 @@ void gserial_disconnect(struct gserial *gser)
/* disable endpoints, aborting down any active I/O */
usb_ep_disable(gser->out);
gser->out->driver_data = NULL;
usb_ep_disable(gser->in);
gser->in->driver_data = NULL;
/* finally, free any unused/unusable I/O buffers */
spin_lock_irqsave(&port->port_lock, flags);

View File

@ -79,10 +79,7 @@ static int dbgp_consume(char *buf, unsigned len)
static void __disable_ep(struct usb_ep *ep)
{
if (ep && ep->driver_data == dbgp.gadget) {
usb_ep_disable(ep);
ep->driver_data = NULL;
}
usb_ep_disable(ep);
}
static void dbgp_disable_ep(void)
@ -171,7 +168,6 @@ static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
int err;
ep->desc = desc;
err = usb_ep_enable(ep);
ep->driver_data = dbgp.gadget;
return err;
}
@ -229,8 +225,6 @@ static void dbgp_unbind(struct usb_gadget *gadget)
usb_ep_free_request(gadget->ep0, dbgp.req);
dbgp.req = NULL;
}
gadget->ep0->driver_data = NULL;
}
#ifdef CONFIG_USB_G_DBGP_SERIAL
@ -249,18 +243,15 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget)
goto fail_1;
}
dbgp.i_ep->driver_data = gadget;
i_desc.wMaxPacketSize =
cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc);
if (!dbgp.o_ep) {
dbgp.i_ep->driver_data = NULL;
stp = 2;
goto fail_2;
goto fail_1;
}
dbgp.o_ep->driver_data = gadget;
o_desc.wMaxPacketSize =
cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
@ -277,8 +268,6 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget)
return 0;
fail_2:
dbgp.i_ep->driver_data = NULL;
fail_1:
dev_dbg(&dbgp.gadget->dev, "ep config: failure (%d)\n", stp);
return -ENODEV;
@ -306,7 +295,6 @@ static int dbgp_bind(struct usb_gadget *gadget,
}
dbgp.req->length = DBGP_REQ_EP0_LEN;
gadget->ep0->driver_data = gadget;
#ifdef CONFIG_USB_G_DBGP_SERIAL
dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
@ -356,8 +344,6 @@ static int dbgp_setup(struct usb_gadget *gadget,
void *data = NULL;
u16 len = 0;
gadget->ep0->driver_data = gadget;
if (request == USB_REQ_GET_DESCRIPTOR) {
switch (value>>8) {
case USB_DT_DEVICE:

View File

@ -2018,14 +2018,6 @@ static struct usb_configuration usbg_config_driver = {
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
static void give_back_ep(struct usb_ep **pep)
{
struct usb_ep *ep = *pep;
if (!ep)
return;
ep->driver_data = NULL;
}
static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
{
struct f_uas *fu = to_f_uas(f);
@ -2045,29 +2037,24 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
&uasp_bi_ep_comp_desc);
if (!ep)
goto ep_fail;
ep->driver_data = fu;
fu->ep_in = ep;
ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
&uasp_bo_ep_comp_desc);
if (!ep)
goto ep_fail;
ep->driver_data = fu;
fu->ep_out = ep;
ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
&uasp_status_in_ep_comp_desc);
if (!ep)
goto ep_fail;
ep->driver_data = fu;
fu->ep_status = ep;
ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
&uasp_cmd_comp_desc);
if (!ep)
goto ep_fail;
ep->driver_data = fu;
fu->ep_cmd = ep;
/* Assume endpoint addresses are the same for both speeds */
@ -2091,11 +2078,6 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
return 0;
ep_fail:
pr_err("Can't claim all required eps\n");
give_back_ep(&fu->ep_in);
give_back_ep(&fu->ep_out);
give_back_ep(&fu->ep_status);
give_back_ep(&fu->ep_cmd);
return -ENOTSUPP;
}

View File

@ -55,7 +55,7 @@ config USB_LPC32XX
config USB_ATMEL_USBA
tristate "Atmel USBA"
depends on AVR32 || ARCH_AT91
depends on ((AVR32 && !OF) || ARCH_AT91)
help
USBA is the integrated high-speed USB Device controller on
the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.

View File

@ -65,18 +65,10 @@
static void udc_tasklet_disconnect(unsigned long);
static void empty_req_queue(struct udc_ep *);
static int udc_probe(struct udc *dev);
static void udc_basic_init(struct udc *dev);
static void udc_setup_endpoints(struct udc *dev);
static void udc_soft_reset(struct udc *dev);
static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
unsigned long buf_len, gfp_t gfp_flags);
static int udc_remote_wakeup(struct udc *dev);
static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
static void udc_pci_remove(struct pci_dev *pdev);
/* description */
static const char mod_desc[] = UDC_MOD_DESCRIPTION;
@ -615,6 +607,30 @@ udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
return &req->req;
}
/* frees pci pool descriptors of a DMA chain */
static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
{
int ret_val = 0;
struct udc_data_dma *td;
struct udc_data_dma *td_last = NULL;
unsigned int i;
DBG(dev, "free chain req = %p\n", req);
/* do not free first desc., will be done by free for request */
td_last = req->td_data;
td = phys_to_virt(td_last->next);
for (i = 1; i < req->chain_len; i++) {
pci_pool_free(dev->data_requests, td,
(dma_addr_t)td_last->next);
td_last = td;
td = phys_to_virt(td_last->next);
}
return ret_val;
}
/* Frees request packet, called by gadget driver */
static void
udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
@ -789,6 +805,123 @@ udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
return finished;
}
/* Creates or re-inits a DMA chain */
static int udc_create_dma_chain(
struct udc_ep *ep,
struct udc_request *req,
unsigned long buf_len, gfp_t gfp_flags
)
{
unsigned long bytes = req->req.length;
unsigned int i;
dma_addr_t dma_addr;
struct udc_data_dma *td = NULL;
struct udc_data_dma *last = NULL;
unsigned long txbytes;
unsigned create_new_chain = 0;
unsigned len;
VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
bytes, buf_len);
dma_addr = DMA_DONT_USE;
/* unset L bit in first desc for OUT */
if (!ep->in)
req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
/* alloc only new desc's if not already available */
len = req->req.length / ep->ep.maxpacket;
if (req->req.length % ep->ep.maxpacket)
len++;
if (len > req->chain_len) {
/* shorter chain already allocated before */
if (req->chain_len > 1)
udc_free_dma_chain(ep->dev, req);
req->chain_len = len;
create_new_chain = 1;
}
td = req->td_data;
/* gen. required number of descriptors and buffers */
for (i = buf_len; i < bytes; i += buf_len) {
/* create or determine next desc. */
if (create_new_chain) {
td = pci_pool_alloc(ep->dev->data_requests,
gfp_flags, &dma_addr);
if (!td)
return -ENOMEM;
td->status = 0;
} else if (i == buf_len) {
/* first td */
td = (struct udc_data_dma *)phys_to_virt(
req->td_data->next);
td->status = 0;
} else {
td = (struct udc_data_dma *)phys_to_virt(last->next);
td->status = 0;
}
if (td)
td->bufptr = req->req.dma + i; /* assign buffer */
else
break;
/* short packet ? */
if ((bytes - i) >= buf_len) {
txbytes = buf_len;
} else {
/* short packet */
txbytes = bytes - i;
}
/* link td and assign tx bytes */
if (i == buf_len) {
if (create_new_chain)
req->td_data->next = dma_addr;
/*
* else
* req->td_data->next = virt_to_phys(td);
*/
/* write tx bytes */
if (ep->in) {
/* first desc */
req->td_data->status =
AMD_ADDBITS(req->td_data->status,
ep->ep.maxpacket,
UDC_DMA_IN_STS_TXBYTES);
/* second desc */
td->status = AMD_ADDBITS(td->status,
txbytes,
UDC_DMA_IN_STS_TXBYTES);
}
} else {
if (create_new_chain)
last->next = dma_addr;
/*
* else
* last->next = virt_to_phys(td);
*/
if (ep->in) {
/* write tx bytes */
td->status = AMD_ADDBITS(td->status,
txbytes,
UDC_DMA_IN_STS_TXBYTES);
}
}
last = td;
}
/* set last bit */
if (td) {
td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
/* last desc. points to itself */
req->td_data_last = td;
}
return 0;
}
/* create/re-init a DMA descriptor or a DMA descriptor chain */
static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
{
@ -913,32 +1046,6 @@ __acquires(ep->dev->lock)
ep->halted = halted;
}
/* frees pci pool descriptors of a DMA chain */
static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
{
int ret_val = 0;
struct udc_data_dma *td;
struct udc_data_dma *td_last = NULL;
unsigned int i;
DBG(dev, "free chain req = %p\n", req);
/* do not free first desc., will be done by free for request */
td_last = req->td_data;
td = phys_to_virt(td_last->next);
for (i = 1; i < req->chain_len; i++) {
pci_pool_free(dev->data_requests, td,
(dma_addr_t) td_last->next);
td_last = td;
td = phys_to_virt(td_last->next);
}
return ret_val;
}
/* Iterates to the end of a DMA chain and returns last descriptor */
static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
{
@ -975,125 +1082,6 @@ static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
}
/* Creates or re-inits a DMA chain */
static int udc_create_dma_chain(
struct udc_ep *ep,
struct udc_request *req,
unsigned long buf_len, gfp_t gfp_flags
)
{
unsigned long bytes = req->req.length;
unsigned int i;
dma_addr_t dma_addr;
struct udc_data_dma *td = NULL;
struct udc_data_dma *last = NULL;
unsigned long txbytes;
unsigned create_new_chain = 0;
unsigned len;
VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
bytes, buf_len);
dma_addr = DMA_DONT_USE;
/* unset L bit in first desc for OUT */
if (!ep->in)
req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
/* alloc only new desc's if not already available */
len = req->req.length / ep->ep.maxpacket;
if (req->req.length % ep->ep.maxpacket)
len++;
if (len > req->chain_len) {
/* shorter chain already allocated before */
if (req->chain_len > 1)
udc_free_dma_chain(ep->dev, req);
req->chain_len = len;
create_new_chain = 1;
}
td = req->td_data;
/* gen. required number of descriptors and buffers */
for (i = buf_len; i < bytes; i += buf_len) {
/* create or determine next desc. */
if (create_new_chain) {
td = pci_pool_alloc(ep->dev->data_requests,
gfp_flags, &dma_addr);
if (!td)
return -ENOMEM;
td->status = 0;
} else if (i == buf_len) {
/* first td */
td = (struct udc_data_dma *) phys_to_virt(
req->td_data->next);
td->status = 0;
} else {
td = (struct udc_data_dma *) phys_to_virt(last->next);
td->status = 0;
}
if (td)
td->bufptr = req->req.dma + i; /* assign buffer */
else
break;
/* short packet ? */
if ((bytes - i) >= buf_len) {
txbytes = buf_len;
} else {
/* short packet */
txbytes = bytes - i;
}
/* link td and assign tx bytes */
if (i == buf_len) {
if (create_new_chain)
req->td_data->next = dma_addr;
/*
else
req->td_data->next = virt_to_phys(td);
*/
/* write tx bytes */
if (ep->in) {
/* first desc */
req->td_data->status =
AMD_ADDBITS(req->td_data->status,
ep->ep.maxpacket,
UDC_DMA_IN_STS_TXBYTES);
/* second desc */
td->status = AMD_ADDBITS(td->status,
txbytes,
UDC_DMA_IN_STS_TXBYTES);
}
} else {
if (create_new_chain)
last->next = dma_addr;
/*
else
last->next = virt_to_phys(td);
*/
if (ep->in) {
/* write tx bytes */
td->status = AMD_ADDBITS(td->status,
txbytes,
UDC_DMA_IN_STS_TXBYTES);
}
}
last = td;
}
/* set last bit */
if (td) {
td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
/* last desc. points to itself */
req->td_data_last = td;
}
return 0;
}
/* Enabling RX DMA */
static void udc_set_rde(struct udc *dev)
{
@ -1453,6 +1441,26 @@ static int udc_get_frame(struct usb_gadget *gadget)
return -EOPNOTSUPP;
}
/* Initiates a remote wakeup */
static int udc_remote_wakeup(struct udc *dev)
{
unsigned long flags;
u32 tmp;
DBG(dev, "UDC initiates remote wakeup\n");
spin_lock_irqsave(&dev->lock, flags);
tmp = readl(&dev->regs->ctl);
tmp |= AMD_BIT(UDC_DEVCTL_RES);
writel(tmp, &dev->regs->ctl);
tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
writel(tmp, &dev->regs->ctl);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
/* Remote wakeup gadget interface */
static int udc_wakeup(struct usb_gadget *gadget)
{
@ -1498,33 +1506,6 @@ static void make_ep_lists(struct udc *dev)
dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
}
/* init registers at driver load time */
static int startup_registers(struct udc *dev)
{
u32 tmp;
/* init controller by soft reset */
udc_soft_reset(dev);
/* mask not needed interrupts */
udc_mask_unused_interrupts(dev);
/* put into initial config */
udc_basic_init(dev);
/* link up all endpoints */
udc_setup_endpoints(dev);
/* program speed */
tmp = readl(&dev->regs->cfg);
if (use_fullspeed)
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
else
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
writel(tmp, &dev->regs->cfg);
return 0;
}
/* Inits UDC context */
static void udc_basic_init(struct udc *dev)
{
@ -1563,6 +1544,33 @@ static void udc_basic_init(struct udc *dev)
dev->data_ep_queued = 0;
}
/* init registers at driver load time */
static int startup_registers(struct udc *dev)
{
u32 tmp;
/* init controller by soft reset */
udc_soft_reset(dev);
/* mask not needed interrupts */
udc_mask_unused_interrupts(dev);
/* put into initial config */
udc_basic_init(dev);
/* link up all endpoints */
udc_setup_endpoints(dev);
/* program speed */
tmp = readl(&dev->regs->cfg);
if (use_fullspeed)
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
else
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
writel(tmp, &dev->regs->cfg);
return 0;
}
/* Sets initial endpoint parameters */
static void udc_setup_endpoints(struct udc *dev)
{
@ -2177,7 +2185,7 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
}
/* DMA */
} else if (!ep->cancel_transfer && req != NULL) {
} else if (!ep->cancel_transfer && req) {
ret_val = IRQ_HANDLED;
/* check for DMA done */
@ -3107,6 +3115,17 @@ static void udc_remove(struct udc *dev)
udc = NULL;
}
/* free all the dma pools */
static void free_dma_pools(struct udc *dev)
{
dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td,
dev->ep[UDC_EP0OUT_IX].td_phys);
dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td_stp,
dev->ep[UDC_EP0OUT_IX].td_stp_dma);
dma_pool_destroy(dev->stp_requests);
dma_pool_destroy(dev->data_requests);
}
/* Reset all pci context */
static void udc_pci_remove(struct pci_dev *pdev)
{
@ -3116,35 +3135,19 @@ static void udc_pci_remove(struct pci_dev *pdev)
usb_del_gadget_udc(&udc->gadget);
/* gadget driver must not be registered */
BUG_ON(dev->driver != NULL);
if (WARN_ON(dev->driver))
return;
/* dma pool cleanup */
if (dev->data_requests)
pci_pool_destroy(dev->data_requests);
if (dev->stp_requests) {
/* cleanup DMA desc's for ep0in */
pci_pool_free(dev->stp_requests,
dev->ep[UDC_EP0OUT_IX].td_stp,
dev->ep[UDC_EP0OUT_IX].td_stp_dma);
pci_pool_free(dev->stp_requests,
dev->ep[UDC_EP0OUT_IX].td,
dev->ep[UDC_EP0OUT_IX].td_phys);
pci_pool_destroy(dev->stp_requests);
}
free_dma_pools(dev);
/* reset controller */
writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
if (dev->irq_registered)
free_irq(pdev->irq, dev);
if (dev->virt_addr)
iounmap(dev->virt_addr);
if (dev->mem_region)
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (dev->active)
pci_disable_device(pdev);
free_irq(pdev->irq, dev);
iounmap(dev->virt_addr);
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
pci_disable_device(pdev);
udc_remove(dev);
}
@ -3169,8 +3172,7 @@ static int init_dma_pools(struct udc *dev)
sizeof(struct udc_data_dma), 0, 0);
if (!dev->data_requests) {
DBG(dev, "can't get request data pool\n");
retval = -ENOMEM;
goto finished;
return -ENOMEM;
}
/* EP0 in dma regs = dev control regs */
@ -3182,27 +3184,101 @@ static int init_dma_pools(struct udc *dev)
if (!dev->stp_requests) {
DBG(dev, "can't get stp request pool\n");
retval = -ENOMEM;
goto finished;
goto err_create_dma_pool;
}
/* setup */
td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
&dev->ep[UDC_EP0OUT_IX].td_stp_dma);
if (td_stp == NULL) {
if (!td_stp) {
retval = -ENOMEM;
goto finished;
goto err_alloc_dma;
}
dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
/* data: 0 packets !? */
td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
&dev->ep[UDC_EP0OUT_IX].td_phys);
if (td_data == NULL) {
if (!td_data) {
retval = -ENOMEM;
goto finished;
goto err_alloc_phys;
}
dev->ep[UDC_EP0OUT_IX].td = td_data;
return 0;
err_alloc_phys:
dma_pool_free(dev->stp_requests, dev->ep[UDC_EP0OUT_IX].td_stp,
dev->ep[UDC_EP0OUT_IX].td_stp_dma);
err_alloc_dma:
dma_pool_destroy(dev->stp_requests);
dev->stp_requests = NULL;
err_create_dma_pool:
dma_pool_destroy(dev->data_requests);
dev->data_requests = NULL;
return retval;
}
/* general probe */
static int udc_probe(struct udc *dev)
{
char tmp[128];
u32 reg;
int retval;
/* mark timer as not initialized */
udc_timer.data = 0;
udc_pollstall_timer.data = 0;
/* device struct setup */
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.name = name;
dev->gadget.max_speed = USB_SPEED_HIGH;
/* init registers, interrupts, ... */
startup_registers(dev);
dev_info(&dev->pdev->dev, "%s\n", mod_desc);
snprintf(tmp, sizeof(tmp), "%d", dev->irq);
dev_info(&dev->pdev->dev,
"irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
tmp, dev->phys_addr, dev->chiprev,
(dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
strcpy(tmp, UDC_DRIVER_VERSION_STRING);
if (dev->chiprev == UDC_HSA0_REV) {
dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
retval = -ENODEV;
goto finished;
}
dev_info(&dev->pdev->dev,
"driver version: %s(for Geode5536 B1)\n", tmp);
udc = dev;
retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
gadget_release);
if (retval)
goto finished;
/* timer init */
init_timer(&udc_timer);
udc_timer.function = udc_timer_function;
udc_timer.data = 1;
/* timer pollstall init */
init_timer(&udc_pollstall_timer);
udc_pollstall_timer.function = udc_pollstall_timer_function;
udc_pollstall_timer.data = 1;
/* set SD */
reg = readl(&dev->regs->ctl);
reg |= AMD_BIT(UDC_DEVCTL_SD);
writel(reg, &dev->regs->ctl);
/* print dev register info */
print_regs(dev);
return 0;
finished:
return retval;
}
@ -3234,7 +3310,6 @@ static int udc_pci_probe(
retval = -ENODEV;
goto err_pcidev;
}
dev->active = 1;
/* PCI resource allocation */
resource = pci_resource_start(pdev, 0);
@ -3245,10 +3320,9 @@ static int udc_pci_probe(
retval = -EBUSY;
goto err_memreg;
}
dev->mem_region = 1;
dev->virt_addr = ioremap_nocache(resource, len);
if (dev->virt_addr == NULL) {
if (!dev->virt_addr) {
dev_dbg(&pdev->dev, "start address cannot be mapped\n");
retval = -EFAULT;
goto err_ioremap;
@ -3276,7 +3350,6 @@ static int udc_pci_probe(
retval = -EBUSY;
goto err_irq;
}
dev->irq_registered = 1;
pci_set_drvdata(pdev, dev);
@ -3290,7 +3363,7 @@ static int udc_pci_probe(
if (use_dma) {
retval = init_dma_pools(dev);
if (retval != 0)
goto finished;
goto err_dma;
}
dev->phys_addr = resource;
@ -3298,13 +3371,17 @@ static int udc_pci_probe(
dev->pdev = pdev;
/* general probing */
if (udc_probe(dev) == 0)
return 0;
finished:
udc_pci_remove(pdev);
return retval;
if (udc_probe(dev)) {
retval = -ENODEV;
goto err_probe;
}
return 0;
err_probe:
if (use_dma)
free_dma_pools(dev);
err_dma:
free_irq(pdev->irq, dev);
err_irq:
iounmap(dev->virt_addr);
err_ioremap:
@ -3316,92 +3393,6 @@ err_pcidev:
return retval;
}
/* general probe */
static int udc_probe(struct udc *dev)
{
char tmp[128];
u32 reg;
int retval;
/* mark timer as not initialized */
udc_timer.data = 0;
udc_pollstall_timer.data = 0;
/* device struct setup */
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.name = name;
dev->gadget.max_speed = USB_SPEED_HIGH;
/* init registers, interrupts, ... */
startup_registers(dev);
dev_info(&dev->pdev->dev, "%s\n", mod_desc);
snprintf(tmp, sizeof tmp, "%d", dev->irq);
dev_info(&dev->pdev->dev,
"irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
tmp, dev->phys_addr, dev->chiprev,
(dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
strcpy(tmp, UDC_DRIVER_VERSION_STRING);
if (dev->chiprev == UDC_HSA0_REV) {
dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
retval = -ENODEV;
goto finished;
}
dev_info(&dev->pdev->dev,
"driver version: %s(for Geode5536 B1)\n", tmp);
udc = dev;
retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
gadget_release);
if (retval)
goto finished;
/* timer init */
init_timer(&udc_timer);
udc_timer.function = udc_timer_function;
udc_timer.data = 1;
/* timer pollstall init */
init_timer(&udc_pollstall_timer);
udc_pollstall_timer.function = udc_pollstall_timer_function;
udc_pollstall_timer.data = 1;
/* set SD */
reg = readl(&dev->regs->ctl);
reg |= AMD_BIT(UDC_DEVCTL_SD);
writel(reg, &dev->regs->ctl);
/* print dev register info */
print_regs(dev);
return 0;
finished:
return retval;
}
/* Initiates a remote wakeup */
static int udc_remote_wakeup(struct udc *dev)
{
unsigned long flags;
u32 tmp;
DBG(dev, "UDC initiates remote wakeup\n");
spin_lock_irqsave(&dev->lock, flags);
tmp = readl(&dev->regs->ctl);
tmp |= AMD_BIT(UDC_DEVCTL_RES);
writel(tmp, &dev->regs->ctl);
tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
writel(tmp, &dev->regs->ctl);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
/* PCI device parameters */
static const struct pci_device_id pci_id[] = {
{

View File

@ -526,14 +526,11 @@ struct udc {
struct udc_ep ep[UDC_EP_NUM];
struct usb_gadget_driver *driver;
/* operational flags */
unsigned active : 1,
stall_ep0in : 1,
unsigned stall_ep0in : 1,
waiting_zlp_ack_ep0in : 1,
set_cfg_not_acked : 1,
irq_registered : 1,
data_ep_enabled : 1,
data_ep_queued : 1,
mem_region : 1,
sys_suspended : 1,
connected;

View File

@ -112,6 +112,14 @@ struct at91_udc_caps {
void (*pullup)(struct at91_udc *udc, int is_on);
};
struct at91_udc_data {
int vbus_pin; /* high == host powering us */
u8 vbus_active_low; /* vbus polarity */
u8 vbus_polled; /* Use polling, not interrupt */
int pullup_pin; /* active == D+ pulled up */
u8 pullup_active_low; /* true == pullup_pin is active low */
};
/*
* driver is non-SMP, and just blocks IRQs whenever it needs
* access protection for chip registers or driver state

View File

@ -833,10 +833,10 @@ static const struct usb_ep_ops dummy_ep_ops = {
/* there are both host and device side versions of this call ... */
static int dummy_g_get_frame(struct usb_gadget *_gadget)
{
struct timeval tv;
struct timespec64 ts64;
do_gettimeofday(&tv);
return tv.tv_usec / 1000;
ktime_get_ts64(&ts64);
return ts64.tv_nsec / NSEC_PER_MSEC;
}
static int dummy_wakeup(struct usb_gadget *_gadget)

View File

@ -1913,7 +1913,7 @@ static void defect7374_disable_data_eps(struct net2280 *dev)
for (i = 1; i < 5; i++) {
ep = &dev->ep[i];
writel(0, &ep->cfg->ep_cfg);
writel(i, &ep->cfg->ep_cfg);
}
/* CSROUT, CSRIN, PCIOUT, PCIIN, STATIN, RCIN */

View File

@ -330,7 +330,7 @@ struct pch_vbus_gpio_data {
* @prot_stall: protcol stall requested
* @irq_registered: irq registered with system
* @mem_region: device memory mapped
* @registered: driver regsitered with system
* @registered: driver registered with system
* @suspended: driver in suspended state
* @connected: gadget driver associated
* @vbus_session: required vbus_session state
@ -2747,18 +2747,18 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
if (dev_intr & UDC_DEVINT_US) {
if (dev->driver
&& dev->driver->suspend) {
spin_lock(&dev->lock);
dev->driver->suspend(&dev->gadget);
spin_unlock(&dev->lock);
dev->driver->suspend(&dev->gadget);
spin_lock(&dev->lock);
}
vbus = pch_vbus_gpio_get_value(dev);
if ((dev->vbus_session == 0)
&& (vbus != 1)) {
if (dev->driver && dev->driver->disconnect) {
spin_lock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
spin_unlock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
pch_udc_reconnect(dev);
} else if ((dev->vbus_session == 0)

View File

@ -17,6 +17,7 @@
static int override_alt = -1;
module_param_named(alt, override_alt, int, 0644);
MODULE_PARM_DESC(alt, ">= 0 to override altsetting selection");
static void complicated_callback(struct urb *urb);
/*-------------------------------------------------------------------------*/
@ -95,6 +96,7 @@ static struct usb_device *testdev_to_usbdev(struct usbtest_dev *test)
dev_warn(&(tdev)->intf->dev , fmt , ## args)
#define GUARD_BYTE 0xA5
#define MAX_SGLEN 128
/*-------------------------------------------------------------------------*/
@ -238,7 +240,8 @@ static struct urb *usbtest_alloc_urb(
unsigned long bytes,
unsigned transfer_flags,
unsigned offset,
u8 bInterval)
u8 bInterval,
usb_complete_t complete_fn)
{
struct urb *urb;
@ -247,10 +250,10 @@ static struct urb *usbtest_alloc_urb(
return urb;
if (bInterval)
usb_fill_int_urb(urb, udev, pipe, NULL, bytes, simple_callback,
usb_fill_int_urb(urb, udev, pipe, NULL, bytes, complete_fn,
NULL, bInterval);
else
usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback,
usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, complete_fn,
NULL);
urb->interval = (udev->speed == USB_SPEED_HIGH)
@ -295,7 +298,17 @@ static struct urb *simple_alloc_urb(
u8 bInterval)
{
return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0,
bInterval);
bInterval, simple_callback);
}
static struct urb *complicated_alloc_urb(
struct usb_device *udev,
int pipe,
unsigned long bytes,
u8 bInterval)
{
return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0,
bInterval, complicated_callback);
}
static unsigned pattern;
@ -303,11 +316,20 @@ static unsigned mod_pattern;
module_param_named(pattern, mod_pattern, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(mod_pattern, "i/o pattern (0 == zeroes)");
static inline void simple_fill_buf(struct urb *urb)
static unsigned get_maxpacket(struct usb_device *udev, int pipe)
{
struct usb_host_endpoint *ep;
ep = usb_pipe_endpoint(udev, pipe);
return le16_to_cpup(&ep->desc.wMaxPacketSize);
}
static void simple_fill_buf(struct urb *urb)
{
unsigned i;
u8 *buf = urb->transfer_buffer;
unsigned len = urb->transfer_buffer_length;
unsigned maxpacket;
switch (pattern) {
default:
@ -316,8 +338,9 @@ static inline void simple_fill_buf(struct urb *urb)
memset(buf, 0, len);
break;
case 1: /* mod63 */
maxpacket = get_maxpacket(urb->dev, urb->pipe);
for (i = 0; i < len; i++)
*buf++ = (u8) (i % 63);
*buf++ = (u8) ((i % maxpacket) % 63);
break;
}
}
@ -349,6 +372,7 @@ static int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
u8 expected;
u8 *buf = urb->transfer_buffer;
unsigned len = urb->actual_length;
unsigned maxpacket = get_maxpacket(urb->dev, urb->pipe);
int ret = check_guard_bytes(tdev, urb);
if (ret)
@ -366,7 +390,7 @@ static int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
* with set_interface or set_config.
*/
case 1: /* mod63 */
expected = i % 63;
expected = (i % maxpacket) % 63;
break;
/* always fail unsupported patterns */
default:
@ -478,11 +502,13 @@ static void free_sglist(struct scatterlist *sg, int nents)
}
static struct scatterlist *
alloc_sglist(int nents, int max, int vary)
alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe)
{
struct scatterlist *sg;
unsigned i;
unsigned size = max;
unsigned maxpacket =
get_maxpacket(interface_to_usbdev(dev->intf), pipe);
if (max == 0)
return NULL;
@ -511,7 +537,7 @@ alloc_sglist(int nents, int max, int vary)
break;
case 1:
for (j = 0; j < size; j++)
*buf++ = (u8) (j % 63);
*buf++ = (u8) ((j % maxpacket) % 63);
break;
}
@ -1719,7 +1745,7 @@ static int ctrl_out(struct usbtest_dev *dev,
for (i = 0; i < count; i++) {
/* write patterned data */
for (j = 0; j < len; j++)
buf[j] = i + j;
buf[j] = (u8)(i + j);
retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x5b, USB_DIR_OUT|USB_TYPE_VENDOR,
0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
@ -1749,9 +1775,9 @@ static int ctrl_out(struct usbtest_dev *dev,
/* fail if we can't verify */
for (j = 0; j < len; j++) {
if (buf[j] != (u8) (i + j)) {
if (buf[j] != (u8)(i + j)) {
ERROR(dev, "ctrl_out, byte %d is %d not %d\n",
j, buf[j], (u8) i + j);
j, buf[j], (u8)(i + j));
retval = -EBADMSG;
break;
}
@ -1781,12 +1807,12 @@ static int ctrl_out(struct usbtest_dev *dev,
/*-------------------------------------------------------------------------*/
/* ISO tests ... mimics common usage
/* ISO/BULK tests ... mimics common usage
* - buffer length is split into N packets (mostly maxpacket sized)
* - multi-buffers according to sglen
*/
struct iso_context {
struct transfer_context {
unsigned count;
unsigned pending;
spinlock_t lock;
@ -1795,11 +1821,12 @@ struct iso_context {
unsigned long errors;
unsigned long packet_count;
struct usbtest_dev *dev;
bool is_iso;
};
static void iso_callback(struct urb *urb)
static void complicated_callback(struct urb *urb)
{
struct iso_context *ctx = urb->context;
struct transfer_context *ctx = urb->context;
spin_lock(&ctx->lock);
ctx->count--;
@ -1808,7 +1835,7 @@ static void iso_callback(struct urb *urb)
if (urb->error_count > 0)
ctx->errors += urb->error_count;
else if (urb->status != 0)
ctx->errors += urb->number_of_packets;
ctx->errors += (ctx->is_iso ? urb->number_of_packets : 1);
else if (urb->actual_length != urb->transfer_buffer_length)
ctx->errors++;
else if (check_guard_bytes(ctx->dev, urb) != 0)
@ -1895,7 +1922,7 @@ static struct urb *iso_alloc_urb(
urb->iso_frame_desc[i].offset = maxp * i;
}
urb->complete = iso_callback;
urb->complete = complicated_callback;
/* urb->context = SET BY CALLER */
urb->interval = 1 << (desc->bInterval - 1);
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
@ -1903,37 +1930,33 @@ static struct urb *iso_alloc_urb(
}
static int
test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
test_queue(struct usbtest_dev *dev, struct usbtest_param *param,
int pipe, struct usb_endpoint_descriptor *desc, unsigned offset)
{
struct iso_context context;
struct transfer_context context;
struct usb_device *udev;
unsigned i;
unsigned long packets = 0;
int status = 0;
struct urb *urbs[10]; /* FIXME no limit */
if (param->sglen > 10)
return -EDOM;
struct urb *urbs[param->sglen];
memset(&context, 0, sizeof(context));
context.count = param->iterations * param->sglen;
context.dev = dev;
context.is_iso = !!desc;
init_completion(&context.done);
spin_lock_init(&context.lock);
memset(urbs, 0, sizeof(urbs));
udev = testdev_to_usbdev(dev);
dev_info(&dev->intf->dev,
"iso period %d %sframes, wMaxPacket %d, transactions: %d\n",
1 << (desc->bInterval - 1),
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
usb_endpoint_maxp(desc) & 0x7ff,
1 + (0x3 & (usb_endpoint_maxp(desc) >> 11)));
for (i = 0; i < param->sglen; i++) {
urbs[i] = iso_alloc_urb(udev, pipe, desc,
if (context.is_iso)
urbs[i] = iso_alloc_urb(udev, pipe, desc,
param->length, offset);
else
urbs[i] = complicated_alloc_urb(udev, pipe,
param->length, 0);
if (!urbs[i]) {
status = -ENOMEM;
goto fail;
@ -1942,11 +1965,21 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
urbs[i]->context = &context;
}
packets *= param->iterations;
dev_info(&dev->intf->dev,
"total %lu msec (%lu packets)\n",
(packets * (1 << (desc->bInterval - 1)))
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
packets);
if (context.is_iso) {
dev_info(&dev->intf->dev,
"iso period %d %sframes, wMaxPacket %d, transactions: %d\n",
1 << (desc->bInterval - 1),
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
usb_endpoint_maxp(desc) & 0x7ff,
1 + (0x3 & (usb_endpoint_maxp(desc) >> 11)));
dev_info(&dev->intf->dev,
"total %lu msec (%lu packets)\n",
(packets * (1 << (desc->bInterval - 1)))
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
packets);
}
spin_lock_irq(&context.lock);
for (i = 0; i < param->sglen; i++) {
@ -1983,7 +2016,8 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
;
else if (context.submit_error)
status = -EACCES;
else if (context.errors > context.packet_count / 10)
else if (context.errors >
(context.is_iso ? context.packet_count / 10 : 0))
status = -EIO;
return status;
@ -2004,8 +2038,8 @@ static int test_unaligned_bulk(
const char *label)
{
int retval;
struct urb *urb = usbtest_alloc_urb(
testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1, 0);
struct urb *urb = usbtest_alloc_urb(testdev_to_usbdev(tdev),
pipe, length, transfer_flags, 1, 0, simple_callback);
if (!urb)
return -ENOMEM;
@ -2061,6 +2095,9 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
if (param->iterations <= 0)
return -EINVAL;
if (param->sglen > MAX_SGLEN)
return -EINVAL;
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
@ -2176,7 +2213,8 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
"TEST 5: write %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
sg = alloc_sglist(param->sglen, param->length, 0);
sg = alloc_sglist(param->sglen, param->length,
0, dev, dev->out_pipe);
if (!sg) {
retval = -ENOMEM;
break;
@ -2194,7 +2232,8 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
"TEST 6: read %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
sg = alloc_sglist(param->sglen, param->length, 0);
sg = alloc_sglist(param->sglen, param->length,
0, dev, dev->in_pipe);
if (!sg) {
retval = -ENOMEM;
break;
@ -2211,7 +2250,8 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
"TEST 7: write/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length);
sg = alloc_sglist(param->sglen, param->length, param->vary);
sg = alloc_sglist(param->sglen, param->length,
param->vary, dev, dev->out_pipe);
if (!sg) {
retval = -ENOMEM;
break;
@ -2228,7 +2268,8 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
"TEST 8: read/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length);
sg = alloc_sglist(param->sglen, param->length, param->vary);
sg = alloc_sglist(param->sglen, param->length,
param->vary, dev, dev->in_pipe);
if (!sg) {
retval = -ENOMEM;
break;
@ -2325,7 +2366,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
param->iterations,
param->sglen, param->length);
/* FIRMWARE: iso sink */
retval = test_iso_queue(dev, param,
retval = test_queue(dev, param,
dev->out_iso_pipe, dev->iso_out, 0);
break;
@ -2338,7 +2379,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
param->iterations,
param->sglen, param->length);
/* FIRMWARE: iso source */
retval = test_iso_queue(dev, param,
retval = test_queue(dev, param,
dev->in_iso_pipe, dev->iso_in, 0);
break;
@ -2419,7 +2460,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
"TEST 22: write %d iso odd, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
retval = test_iso_queue(dev, param,
retval = test_queue(dev, param,
dev->out_iso_pipe, dev->iso_out, 1);
break;
@ -2430,7 +2471,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
"TEST 23: read %d iso odd, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
retval = test_iso_queue(dev, param,
retval = test_queue(dev, param,
dev->in_iso_pipe, dev->iso_in, 1);
break;
@ -2487,6 +2528,25 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
retval = simple_io(dev, urb, param->iterations, 0, 0, "test26");
simple_free_urb(urb);
break;
case 27:
/* We do performance test, so ignore data compare */
if (dev->out_pipe == 0 || param->sglen == 0 || pattern != 0)
break;
dev_info(&intf->dev,
"TEST 27: bulk write %dMbytes\n", (param->iterations *
param->sglen * param->length) / (1024 * 1024));
retval = test_queue(dev, param,
dev->out_pipe, NULL, 0);
break;
case 28:
if (dev->in_pipe == 0 || param->sglen == 0 || pattern != 0)
break;
dev_info(&intf->dev,
"TEST 28: bulk read %dMbytes\n", (param->iterations *
param->sglen * param->length) / (1024 * 1024));
retval = test_queue(dev, param,
dev->in_pipe, NULL, 0);
break;
}
do_gettimeofday(&param->duration);
param->duration.tv_sec -= start.tv_sec;

View File

@ -1028,18 +1028,22 @@ void musb_start(struct musb *musb)
{
void __iomem *regs = musb->mregs;
u8 devctl = musb_readb(regs, MUSB_DEVCTL);
u8 power;
dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
musb_enable_interrupts(musb);
musb_writeb(regs, MUSB_TESTMODE, 0);
/* put into basic highspeed mode and start session */
musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
| MUSB_POWER_HSENAB
/* ENSUSPEND wedges tusb */
/* | MUSB_POWER_ENSUSPEND */
);
power = MUSB_POWER_ISOUPDATE;
/*
* treating UNKNOWN as unspecified maximum speed, in which case
* we will default to high-speed.
*/
if (musb->config->maximum_speed == USB_SPEED_HIGH ||
musb->config->maximum_speed == USB_SPEED_UNKNOWN)
power |= MUSB_POWER_HSENAB;
musb_writeb(regs, MUSB_POWER, power);
musb->is_active = 0;
devctl = musb_readb(regs, MUSB_DEVCTL);
@ -1771,13 +1775,20 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
unsigned long flags;
unsigned long val;
int vbus;
u8 devctl;
spin_lock_irqsave(&musb->lock, flags);
val = musb->a_wait_bcon;
/* FIXME get_vbus_status() is normally #defined as false...
* and is effectively TUSB-specific.
*/
vbus = musb_platform_get_vbus_status(musb);
if (vbus < 0) {
/* Use default MUSB method by means of DEVCTL register */
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if ((devctl & MUSB_DEVCTL_VBUS)
== (3 << MUSB_DEVCTL_VBUS_SHIFT))
vbus = 1;
else
vbus = 0;
}
spin_unlock_irqrestore(&musb->lock, flags);
return sprintf(buf, "Vbus %s, timeout %lu msec\n",

View File

@ -579,7 +579,7 @@ static inline int musb_platform_recover(struct musb *musb)
static inline int musb_platform_get_vbus_status(struct musb *musb)
{
if (!musb->ops->vbus_status)
return 0;
return -EINVAL;
return musb->ops->vbus_status(musb);
}

View File

@ -666,7 +666,7 @@ static int get_musb_port_mode(struct device *dev)
{
enum usb_dr_mode mode;
mode = of_usb_get_dr_mode(dev->of_node);
mode = usb_get_dr_mode(dev);
switch (mode) {
case USB_DR_MODE_HOST:
return MUSB_PORT_MODE_HOST;
@ -747,6 +747,19 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
if (!ret && val)
config->multipoint = true;
config->maximum_speed = usb_get_maximum_speed(&parent->dev);
switch (config->maximum_speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL:
break;
case USB_SPEED_SUPER:
dev_warn(dev, "ignore incorrect maximum_speed "
"(super-speed) setting in dts");
/* fall through */
default:
config->maximum_speed = USB_SPEED_HIGH;
}
ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
if (ret) {
dev_err(dev, "failed to add platform_data\n");

View File

@ -341,6 +341,16 @@ static void sunxi_musb_disable(struct musb *musb)
clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags);
}
struct dma_controller *sunxi_musb_dma_controller_create(struct musb *musb,
void __iomem *base)
{
return NULL;
}
void sunxi_musb_dma_controller_destroy(struct dma_controller *c)
{
}
/*
* sunxi musb register layout
* 0x00 - 0x17 fifo regs, 1 long per fifo
@ -566,6 +576,8 @@ static const struct musb_platform_ops sunxi_musb_ops = {
.writeb = sunxi_musb_writeb,
.readw = sunxi_musb_readw,
.writew = sunxi_musb_writew,
.dma_init = sunxi_musb_dma_controller_create,
.dma_exit = sunxi_musb_dma_controller_destroy,
.set_vbus = sunxi_musb_set_vbus,
.pre_root_reset_end = sunxi_musb_pre_root_reset_end,
.post_root_reset_end = sunxi_musb_post_root_reset_end,
@ -617,7 +629,7 @@ static int sunxi_musb_probe(struct platform_device *pdev)
return -ENOMEM;
memset(&pdata, 0, sizeof(pdata));
switch (of_usb_get_dr_mode(np)) {
switch (usb_get_dr_mode(&pdev->dev)) {
#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST
case USB_DR_MODE_HOST:
pdata.mode = MUSB_PORT_MODE_HOST;

View File

@ -1529,7 +1529,7 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
if (IS_ERR(motg->phy_rst))
motg->phy_rst = NULL;
pdata->mode = of_usb_get_dr_mode(node);
pdata->mode = usb_get_dr_mode(&pdev->dev);
if (pdata->mode == USB_DR_MODE_UNKNOWN)
pdata->mode = USB_DR_MODE_OTG;

View File

@ -71,7 +71,7 @@ struct phy_8x16 {
struct reset_control *phy_reset;
struct extcon_specific_cable_nb vbus_cable;
struct extcon_dev *vbus_edev;
struct notifier_block vbus_notify;
struct gpio_desc *switch_gpio;
@ -234,7 +234,7 @@ static int phy_8x16_init(struct usb_phy *phy)
val = ULPI_PWR_OTG_COMP_DISABLE;
usb_phy_io_write(phy, val, ULPI_SET(ULPI_PWR_CLK_MNG_REG));
state = extcon_get_cable_state(qphy->vbus_cable.edev, "USB");
state = extcon_get_cable_state_(qphy->vbus_edev, EXTCON_USB);
if (state)
phy_8x16_vbus_on(qphy);
else
@ -314,7 +314,6 @@ static int phy_8x16_reboot_notify(struct notifier_block *this,
static int phy_8x16_probe(struct platform_device *pdev)
{
struct extcon_dev *edev;
struct phy_8x16 *qphy;
struct resource *res;
struct usb_phy *phy;
@ -349,9 +348,9 @@ static int phy_8x16_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
edev = extcon_get_edev_by_phandle(phy->dev, 0);
if (IS_ERR(edev))
return PTR_ERR(edev);
qphy->vbus_edev = extcon_get_edev_by_phandle(phy->dev, 0);
if (IS_ERR(qphy->vbus_edev))
return PTR_ERR(qphy->vbus_edev);
ret = clk_set_rate(qphy->core_clk, INT_MAX);
if (ret < 0)
@ -370,8 +369,8 @@ static int phy_8x16_probe(struct platform_device *pdev)
goto off_clks;
qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify;
ret = extcon_register_interest(&qphy->vbus_cable, edev->name,
"USB", &qphy->vbus_notify);
ret = extcon_register_notifier(qphy->vbus_edev, EXTCON_USB,
&qphy->vbus_notify);
if (ret < 0)
goto off_power;
@ -385,7 +384,8 @@ static int phy_8x16_probe(struct platform_device *pdev)
return 0;
off_extcon:
extcon_unregister_interest(&qphy->vbus_cable);
extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB,
&qphy->vbus_notify);
off_power:
phy_8x16_regulators_disable(qphy);
off_clks:
@ -400,7 +400,8 @@ static int phy_8x16_remove(struct platform_device *pdev)
struct phy_8x16 *qphy = platform_get_drvdata(pdev);
unregister_reboot_notifier(&qphy->reboot_notify);
extcon_unregister_interest(&qphy->vbus_cable);
extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB,
&qphy->vbus_notify);
/*
* Ensure that D+/D- lines are routed to uB connector, so

View File

@ -1029,7 +1029,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
}
if (of_find_property(np, "dr_mode", NULL))
tegra_phy->mode = of_usb_get_dr_mode(np);
tegra_phy->mode = usb_get_dr_mode(&pdev->dev);
else
tegra_phy->mode = USB_DR_MODE_HOST;

View File

@ -25,15 +25,6 @@
*/
#define ATMEL_MAX_UART 7
/* USB Device */
struct at91_udc_data {
int vbus_pin; /* high == host powering us */
u8 vbus_active_low; /* vbus polarity */
u8 vbus_polled; /* Use polling, not interrupt */
int pullup_pin; /* active == D+ pulled up */
u8 pullup_active_low; /* true == pullup_pin is active low */
};
/* Compact Flash */
struct at91_cf_data {
int irq_pin; /* I/O IRQ */

View File

@ -17,19 +17,19 @@
struct platform_device;
enum s3c_hsotg_dmamode {
enum dwc2_hsotg_dmamode {
S3C_HSOTG_DMA_NONE, /* do not use DMA at-all */
S3C_HSOTG_DMA_ONLY, /* always use DMA */
S3C_HSOTG_DMA_DRV, /* DMA is chosen by driver */
};
/**
* struct s3c_hsotg_plat - platform data for high-speed otg/udc
* struct dwc2_hsotg_plat - platform data for high-speed otg/udc
* @dma: Whether to use DMA or not.
* @is_osc: The clock source is an oscillator, not a crystal
*/
struct s3c_hsotg_plat {
enum s3c_hsotg_dmamode dma;
struct dwc2_hsotg_plat {
enum dwc2_hsotg_dmamode dma;
unsigned int is_osc:1;
int phy_type;
@ -37,6 +37,6 @@ struct s3c_hsotg_plat {
int (*phy_exit)(struct platform_device *pdev, int type);
};
extern void s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd);
extern void dwc2_hsotg_set_platdata(struct dwc2_hsotg_plat *pd);
#endif /* __LINUX_USB_S3C_HSOTG_H */

View File

@ -32,9 +32,9 @@
#ifndef __LINUX_USB_CH9_H
#define __LINUX_USB_CH9_H
#include <linux/device.h>
#include <uapi/linux/usb/ch9.h>
/**
* usb_speed_string() - Returns human readable-name of the speed.
* @speed: The speed to return human-readable name for. If it's not
@ -43,6 +43,15 @@
*/
extern const char *usb_speed_string(enum usb_device_speed speed);
/**
* usb_get_maximum_speed - Get maximum requested speed for a given USB
* controller.
* @dev: Pointer to the given USB controller device
*
* The function gets the maximum speed string from property "maximum-speed",
* and returns the corresponding enum usb_device_speed.
*/
extern enum usb_device_speed usb_get_maximum_speed(struct device *dev);
/**
* usb_state_string - Returns human readable name for the state.

View File

@ -215,6 +215,7 @@ struct usb_ep {
struct list_head ep_list;
struct usb_ep_caps caps;
bool claimed;
bool enabled;
unsigned maxpacket:16;
unsigned maxpacket_limit:16;
unsigned max_streams:16;
@ -264,7 +265,18 @@ static inline void usb_ep_set_maxpacket_limit(struct usb_ep *ep,
*/
static inline int usb_ep_enable(struct usb_ep *ep)
{
return ep->ops->enable(ep, ep->desc);
int ret;
if (ep->enabled)
return 0;
ret = ep->ops->enable(ep, ep->desc);
if (ret)
return ret;
ep->enabled = true;
return 0;
}
/**
@ -281,7 +293,18 @@ static inline int usb_ep_enable(struct usb_ep *ep)
*/
static inline int usb_ep_disable(struct usb_ep *ep)
{
return ep->ops->disable(ep);
int ret;
if (!ep->enabled)
return 0;
ret = ep->ops->disable(ep);
if (ret)
return ret;
ep->enabled = false;
return 0;
}
/**
@ -1233,6 +1256,8 @@ extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *,
struct usb_endpoint_descriptor *,
struct usb_ss_ep_comp_descriptor *);
extern void usb_ep_autoconfig_release(struct usb_ep *);
extern void usb_ep_autoconfig_reset(struct usb_gadget *);
#endif /* __LINUX_USB_GADGET_H */

View File

@ -95,7 +95,7 @@ struct musb_hdrc_config {
/* musb CLKIN in Blackfin in MHZ */
unsigned char clkin;
#endif
u32 maximum_speed;
};
struct musb_hdrc_platform_data {

View File

@ -12,22 +12,10 @@
#include <linux/usb/phy.h>
#if IS_ENABLED(CONFIG_OF)
enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np);
enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np);
bool of_usb_host_tpl_support(struct device_node *np);
int of_usb_update_otg_caps(struct device_node *np,
struct usb_otg_caps *otg_caps);
#else
static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
{
return USB_DR_MODE_UNKNOWN;
}
static inline enum usb_device_speed
of_usb_get_maximum_speed(struct device_node *np)
{
return USB_SPEED_UNKNOWN;
}
static inline bool of_usb_host_tpl_support(struct device_node *np)
{
return false;

View File

@ -119,4 +119,13 @@ enum usb_dr_mode {
USB_DR_MODE_OTG,
};
/**
* usb_get_dr_mode - Get dual role mode for given device
* @dev: Pointer to the given device
*
* The function gets phy interface string from property 'dr_mode',
* and returns the correspondig enum usb_dr_mode
*/
extern enum usb_dr_mode usb_get_dr_mode(struct device *dev);
#endif /* __LINUX_USB_OTG_H */

View File

@ -63,7 +63,7 @@ enum usb_otg_state {
struct usb_phy;
struct usb_otg;
/* for transceivers connected thru an ULPI interface, the user must
/* for phys connected thru an ULPI interface, the user must
* provide access ops
*/
struct usb_phy_io_ops {
@ -92,10 +92,10 @@ struct usb_phy {
u16 port_status;
u16 port_change;
/* to support controllers that have multiple transceivers */
/* to support controllers that have multiple phys */
struct list_head head;
/* initialize/shutdown the OTG controller */
/* initialize/shutdown the phy */
int (*init)(struct usb_phy *x);
void (*shutdown)(struct usb_phy *x);
@ -106,7 +106,7 @@ struct usb_phy {
int (*set_power)(struct usb_phy *x,
unsigned mA);
/* Set transceiver into suspend mode */
/* Set phy into suspend mode */
int (*set_suspend)(struct usb_phy *x,
int suspend);

View File

@ -394,7 +394,7 @@ int main (int argc, char **argv)
* low speed, interrupt 8 * 1 = 8
*/
param.iterations = 1000;
param.length = 512;
param.length = 1024;
param.vary = 512;
param.sglen = 32;
@ -454,10 +454,10 @@ usage:
"\t-t testnum only run specified case\n"
"\t-n no test running, show devices to be tested\n"
"Case arguments:\n"
"\t-c iterations default 1000\n"
"\t-s packetsize default 512\n"
"\t-g sglen default 32\n"
"\t-v vary default 512\n",
"\t-c iterations default 1000\n"
"\t-s transfer length default 1024\n"
"\t-g sglen default 32\n"
"\t-v vary default 512\n",
argv[0]);
return 1;
}