From 51f141a97a1406bb0b59d490e837a39ccb7c3999 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 18 Nov 2015 14:34:09 +0900 Subject: usb: renesas_usbhs: Modify pipe configuration The current code has info->bufnmb_last to calculate the BUFNMB bits of PIPEBUF register. However, since the bufnmb_last is initialized in the usbhs_pipe_init() only, this driver is possible to set unexpected value to the register if usb_ep_{enable,disable}() are called many times. So, this patch modifies the pipe configuration via struct renesas_usbhs_driver_param to simplify the code. Also this patch changes: - a double buffer configuration - isochronous buffer size from 512 to 1024 Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- include/linux/usb/renesas_usbhs.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'include/linux/usb') diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index bfb74723f151..4db191fe8c2c 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -105,12 +105,26 @@ struct renesas_usbhs_platform_callback { * some register needs USB chip specific parameters. * This struct show it to driver */ + +struct renesas_usbhs_driver_pipe_config { + u8 type; /* USB_ENDPOINT_XFER_xxx */ + u16 bufsize; + u8 bufnum; + bool double_buf; +}; +#define RENESAS_USBHS_PIPE(_type, _size, _num, _double_buf) { \ + .type = (_type), \ + .bufsize = (_size), \ + .bufnum = (_num), \ + .double_buf = (_double_buf), \ + } + struct renesas_usbhs_driver_param { /* * pipe settings */ - u32 *pipe_type; /* array of USB_ENDPOINT_XFER_xxx (from ep0) */ - int pipe_size; /* pipe_type array size */ + struct renesas_usbhs_driver_pipe_config *pipe_configs; + int pipe_size; /* pipe_configs array size */ /* * option: -- cgit v1.2.3 From 98bfb39466954c69d2a448e6ddcab6d91cd48e25 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Tue, 3 Nov 2015 11:51:15 -0600 Subject: usb: of: add an api to get dr_mode by the phy node Some USB phy drivers have different handling for the controller in each dr_mode. But the phy driver does not have visibility to the dr_mode of the controller. This adds an api to return the dr_mode of the controller which associates the given phy node. Signed-off-by: Bin Liu Signed-off-by: Felipe Balbi --- drivers/usb/common/common.c | 60 ++++++++++++++++++++++++++++++++++++++++----- include/linux/usb/of.h | 5 ++++ 2 files changed, 59 insertions(+), 6 deletions(-) (limited to 'include/linux/usb') diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 673d53038ed2..e6ec125e4485 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -17,6 +17,7 @@ #include #include #include +#include const char *usb_otg_state_string(enum usb_otg_state state) { @@ -106,24 +107,71 @@ static const char *const usb_dr_modes[] = { [USB_DR_MODE_OTG] = "otg", }; +static enum usb_dr_mode usb_get_dr_mode_from_string(const char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) + if (!strcmp(usb_dr_modes[i], str)) + return i; + + return USB_DR_MODE_UNKNOWN; +} + enum usb_dr_mode usb_get_dr_mode(struct device *dev) { const char *dr_mode; - int err, i; + int err; err = device_property_read_string(dev, "dr_mode", &dr_mode); if (err < 0) return USB_DR_MODE_UNKNOWN; - for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) - if (!strcmp(dr_mode, usb_dr_modes[i])) - return i; - - return USB_DR_MODE_UNKNOWN; + return usb_get_dr_mode_from_string(dr_mode); } EXPORT_SYMBOL_GPL(usb_get_dr_mode); #ifdef CONFIG_OF +/** + * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device + * which is associated with the given phy device_node + * @np: Pointer to the given phy device_node + * + * In dts a usb controller associates with phy devices. The function gets + * the string from property 'dr_mode' of the controller associated with the + * given phy device node, and returns the correspondig enum usb_dr_mode. + */ +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +{ + struct device_node *controller = NULL; + struct device_node *phy; + const char *dr_mode; + int index; + int err; + + do { + controller = of_find_node_with_property(controller, "phys"); + index = 0; + do { + phy = of_parse_phandle(controller, "phys", index); + of_node_put(phy); + if (phy == phy_np) + goto finish; + index++; + } while (phy); + } while (controller); + +finish: + err = of_property_read_string(controller, "dr_mode", &dr_mode); + of_node_put(controller); + + if (err < 0) + return USB_DR_MODE_UNKNOWN; + + return usb_get_dr_mode_from_string(dr_mode); +} +EXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy); + /** * of_usb_host_tpl_support - to get if Targeted Peripheral List is supported * for given targeted hosts (non-PC hosts) diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index c3fe9e48ce27..3805757dcdc2 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -12,10 +12,15 @@ #include #if IS_ENABLED(CONFIG_OF) +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_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 +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +{ + return USB_DR_MODE_UNKNOWN; +} static inline bool of_usb_host_tpl_support(struct device_node *np) { return false; -- cgit v1.2.3 From 2284b29d3d9dd16490909962574d7f3fef83fd97 Mon Sep 17 00:00:00 2001 From: Ruslan Bilovol Date: Mon, 23 Nov 2015 09:56:35 +0100 Subject: usb: gadget: bind UDC by name passed via usb_gadget_driver structure Introduce new 'udc_name' member to usb_gadget_driver structure. The 'udc_name' is a name of UDC that usb_gadget_driver should be bound to. If udc_name is NULL, it will be bound to any available UDC. Tested-by: Maxime Ripard Signed-off-by: Ruslan Bilovol Signed-off-by: Marek Szyprowski Tested-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/udc-core.c | 24 +++++++++++++++++++----- include/linux/usb/gadget.h | 4 ++++ 2 files changed, 23 insertions(+), 5 deletions(-) (limited to 'include/linux/usb') diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f660afba715d..429d64e67941 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -549,21 +549,35 @@ EXPORT_SYMBOL_GPL(usb_udc_attach_driver); int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; - int ret; + int ret = -ENODEV; if (!driver || !driver->bind || !driver->setup) return -EINVAL; mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) { - /* For now we take the first one */ - if (!udc->driver) + if (driver->udc_name) { + list_for_each_entry(udc, &udc_list, list) { + ret = strcmp(driver->udc_name, dev_name(&udc->dev)); + if (!ret) + break; + } + if (ret) + ret = -ENODEV; + else if (udc->driver) + ret = -EBUSY; + else goto found; + } else { + list_for_each_entry(udc, &udc_list, list) { + /* For now we take the first one */ + if (!udc->driver) + goto found; + } } pr_debug("couldn't find an available UDC\n"); mutex_unlock(&udc_lock); - return -ENODEV; + return ret; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(&udc_lock); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3d583a10b926..63963c21866d 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1012,6 +1012,8 @@ static inline int usb_gadget_activate(struct usb_gadget *gadget) * @reset: Invoked on USB bus reset. It is mandatory for all gadget drivers * and should be called in_interrupt. * @driver: Driver model state for this driver. + * @udc_name: A name of UDC this driver should be bound to. If udc_name is NULL, + * this driver will be bound to any available UDC. * * Devices are disabled till a gadget driver successfully bind()s, which * means the driver will handle setup() requests needed to enumerate (and @@ -1072,6 +1074,8 @@ struct usb_gadget_driver { /* FIXME support safe rmmod */ struct device_driver driver; + + char *udc_name; }; -- cgit v1.2.3 From 88f73ebdfa75602af18e070a4d5d6d9091bcfada Mon Sep 17 00:00:00 2001 From: Ruslan Bilovol Date: Mon, 23 Nov 2015 09:56:37 +0100 Subject: usb: gadget: udc-core: remove unused usb_udc_attach_driver() Now when last user of usb_udc_attach_driver() is switched to passing UDC name via usb_gadget_driver struct, it's safe to remove this function Tested-by: Maxime Ripard Signed-off-by: Ruslan Bilovol Signed-off-by: Marek Szyprowski Tested-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/udc-core.c | 26 -------------------------- include/linux/usb/gadget.h | 2 -- 2 files changed, 28 deletions(-) (limited to 'include/linux/usb') diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 429d64e67941..f76ebc8c1ed2 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -520,32 +520,6 @@ err1: return ret; } -int usb_udc_attach_driver(const char *name, struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) { - ret = strcmp(name, dev_name(&udc->dev)); - if (!ret) - break; - } - if (ret) { - ret = -ENODEV; - goto out; - } - if (udc->driver) { - ret = -EBUSY; - goto out; - } - ret = udc_bind_to_driver(udc, driver); -out: - mutex_unlock(&udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_udc_attach_driver); - int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 63963c21866d..ce2188d338e6 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1121,8 +1121,6 @@ extern int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)); extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget); extern void usb_del_gadget_udc(struct usb_gadget *gadget); -extern int usb_udc_attach_driver(const char *name, - struct usb_gadget_driver *driver); /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 855ed04a3758b205e84b269f92d26ab36ed8e2f7 Mon Sep 17 00:00:00 2001 From: Ruslan Bilovol Date: Mon, 23 Nov 2015 09:56:38 +0100 Subject: usb: gadget: udc-core: independent registration of gadgets and gadget drivers Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. Tested-by: Maxime Ripard Signed-off-by: Ruslan Bilovol [simplified code as requested by Alan Stern and Felipe Balbi, fixed checkpatch issues] Signed-off-by: Marek Szyprowski Tested-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/udc-core.c | 41 ++++++++++++++++++++++++++++++--------- include/linux/usb/gadget.h | 2 ++ 2 files changed, 34 insertions(+), 9 deletions(-) (limited to 'include/linux/usb') diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index f76ebc8c1ed2..fd73a3ea07c2 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -51,8 +51,12 @@ struct usb_udc { static struct class *udc_class; static LIST_HEAD(udc_list); +static LIST_HEAD(gadget_driver_pending_list); static DEFINE_MUTEX(udc_lock); +static int udc_bind_to_driver(struct usb_udc *udc, + struct usb_gadget_driver *driver); + /* ------------------------------------------------------------------------- */ #ifdef CONFIG_HAS_DMA @@ -356,6 +360,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) { struct usb_udc *udc; + struct usb_gadget_driver *driver; int ret = -ENOMEM; udc = kzalloc(sizeof(*udc), GFP_KERNEL); @@ -403,6 +408,18 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); udc->vbus = true; + /* pick up one of pending gadget drivers */ + list_for_each_entry(driver, &gadget_driver_pending_list, pending) { + if (!driver->udc_name || strcmp(driver->udc_name, + dev_name(&udc->dev)) == 0) { + ret = udc_bind_to_driver(udc, driver); + if (ret) + goto err4; + list_del(&driver->pending); + break; + } + } + mutex_unlock(&udc_lock); return 0; @@ -473,10 +490,14 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) mutex_lock(&udc_lock); list_del(&udc->list); - mutex_unlock(&udc_lock); - if (udc->driver) + if (udc->driver) { + struct usb_gadget_driver *driver = udc->driver; + usb_gadget_remove_driver(udc); + list_add(&driver->pending, &gadget_driver_pending_list); + } + mutex_unlock(&udc_lock); kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); flush_work(&gadget->work); @@ -535,11 +556,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) if (!ret) break; } - if (ret) - ret = -ENODEV; - else if (udc->driver) - ret = -EBUSY; - else + if (!ret && !udc->driver) goto found; } else { list_for_each_entry(udc, &udc_list, list) { @@ -549,9 +566,11 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) } } - pr_debug("couldn't find an available UDC\n"); + list_add_tail(&driver->pending, &gadget_driver_pending_list); + pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", + driver->function); mutex_unlock(&udc_lock); - return ret; + return 0; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(&udc_lock); @@ -577,6 +596,10 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) break; } + if (ret) { + list_del(&driver->pending); + ret = 0; + } mutex_unlock(&udc_lock); return ret; } diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index ce2188d338e6..92467eea76de 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1014,6 +1014,7 @@ static inline int usb_gadget_activate(struct usb_gadget *gadget) * @driver: Driver model state for this driver. * @udc_name: A name of UDC this driver should be bound to. If udc_name is NULL, * this driver will be bound to any available UDC. + * @pending: UDC core private data used for deferred probe of this driver. * * Devices are disabled till a gadget driver successfully bind()s, which * means the driver will handle setup() requests needed to enumerate (and @@ -1076,6 +1077,7 @@ struct usb_gadget_driver { struct device_driver driver; char *udc_name; + struct list_head pending; }; -- cgit v1.2.3 From 8055555fc4590fbda32d4bbf7888bdb2cd4b2b74 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 30 Nov 2015 21:37:12 -0800 Subject: usb: musb: core: Fix handling of the phy notifications We currently can't unload omap2430 MUSB platform glue driver module and this cause issues for fixing the MUSB code further. The reason we can't remove omap2430 is because it uses the PHY functions and also exports the omap_musb_mailbox function that some PHY drivers are using. Let's fix the issue by exporting a more generic musb_mailbox function from the MUSB core and allow platform glue layers to register phy_callback function as needed. And now we can now also get rid of the include/linux/musb-omap.h. Cc: Bin Liu Cc: Felipe Balbi Cc: Kishon Vijay Abraham I Cc: NeilBrown Reviewed-by: Kishon Vijay Abraham I Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi --- drivers/phy/phy-twl4030-usb.c | 32 ++++++++++++++++---------------- drivers/usb/musb/musb_core.c | 21 +++++++++++++++++++++ drivers/usb/musb/musb_core.h | 2 ++ drivers/usb/musb/omap2430.c | 27 ++++++++++++++------------- drivers/usb/phy/phy-twl6030-usb.c | 30 +++++++++++++++--------------- include/linux/usb/musb-omap.h | 30 ------------------------------ include/linux/usb/musb.h | 15 +++++++++++++++ 7 files changed, 83 insertions(+), 74 deletions(-) delete mode 100644 include/linux/usb/musb-omap.h (limited to 'include/linux/usb') diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 3a707dd14238..4a3fc6e59f8e 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -148,10 +148,10 @@ * If VBUS is valid or ID is ground, then we know a * cable is present and we need to be runtime-enabled */ -static inline bool cable_present(enum omap_musb_vbus_id_status stat) +static inline bool cable_present(enum musb_vbus_id_status stat) { - return stat == OMAP_MUSB_VBUS_VALID || - stat == OMAP_MUSB_ID_GROUND; + return stat == MUSB_VBUS_VALID || + stat == MUSB_ID_GROUND; } struct twl4030_usb { @@ -170,7 +170,7 @@ struct twl4030_usb { enum twl4030_usb_mode usb_mode; int irq; - enum omap_musb_vbus_id_status linkstat; + enum musb_vbus_id_status linkstat; bool vbus_supplied; struct delayed_work id_workaround_work; @@ -276,11 +276,11 @@ static bool twl4030_is_driving_vbus(struct twl4030_usb *twl) return (ret & (ULPI_OTG_DRVVBUS | ULPI_OTG_CHRGVBUS)) ? true : false; } -static enum omap_musb_vbus_id_status +static enum musb_vbus_id_status twl4030_usb_linkstat(struct twl4030_usb *twl) { int status; - enum omap_musb_vbus_id_status linkstat = OMAP_MUSB_UNKNOWN; + enum musb_vbus_id_status linkstat = MUSB_UNKNOWN; twl->vbus_supplied = false; @@ -306,14 +306,14 @@ static enum omap_musb_vbus_id_status } if (status & BIT(2)) - linkstat = OMAP_MUSB_ID_GROUND; + linkstat = MUSB_ID_GROUND; else if (status & BIT(7)) - linkstat = OMAP_MUSB_VBUS_VALID; + linkstat = MUSB_VBUS_VALID; else - linkstat = OMAP_MUSB_VBUS_OFF; + linkstat = MUSB_VBUS_OFF; } else { - if (twl->linkstat != OMAP_MUSB_UNKNOWN) - linkstat = OMAP_MUSB_VBUS_OFF; + if (twl->linkstat != MUSB_UNKNOWN) + linkstat = MUSB_VBUS_OFF; } dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", @@ -535,7 +535,7 @@ static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL); static irqreturn_t twl4030_usb_irq(int irq, void *_twl) { struct twl4030_usb *twl = _twl; - enum omap_musb_vbus_id_status status; + enum musb_vbus_id_status status; bool status_changed = false; status = twl4030_usb_linkstat(twl); @@ -567,11 +567,11 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) pm_runtime_mark_last_busy(twl->dev); pm_runtime_put_autosuspend(twl->dev); } - omap_musb_mailbox(status); + musb_mailbox(status); } /* don't schedule during sleep - irq works right then */ - if (status == OMAP_MUSB_ID_GROUND && pm_runtime_active(twl->dev)) { + if (status == MUSB_ID_GROUND && pm_runtime_active(twl->dev)) { cancel_delayed_work(&twl->id_workaround_work); schedule_delayed_work(&twl->id_workaround_work, HZ); } @@ -670,7 +670,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) twl->dev = &pdev->dev; twl->irq = platform_get_irq(pdev, 0); twl->vbus_supplied = false; - twl->linkstat = OMAP_MUSB_UNKNOWN; + twl->linkstat = MUSB_UNKNOWN; twl->phy.dev = twl->dev; twl->phy.label = "twl4030"; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index cd37e9fc2e62..04548423094b 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1702,6 +1702,23 @@ EXPORT_SYMBOL_GPL(musb_dma_completion); #define use_dma 0 #endif +static void (*musb_phy_callback)(enum musb_vbus_id_status status); + +/* + * musb_mailbox - optional phy notifier function + * @status phy state change + * + * Optionally gets called from the USB PHY. Note that the USB PHY must be + * disabled at the point the phy_callback is registered or unregistered. + */ +void musb_mailbox(enum musb_vbus_id_status status) +{ + if (musb_phy_callback) + musb_phy_callback(status); + +}; +EXPORT_SYMBOL_GPL(musb_mailbox); + /*-------------------------------------------------------------------------*/ static ssize_t @@ -2114,6 +2131,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb->xceiv->io_ops = &musb_ulpi_access; } + if (musb->ops->phy_callback) + musb_phy_callback = musb->ops->phy_callback; + pm_runtime_get_sync(musb->controller); if (use_dma && dev->dma_mask) { @@ -2292,6 +2312,7 @@ static int musb_remove(struct platform_device *pdev) */ musb_exit_debugfs(musb); musb_shutdown(pdev); + musb_phy_callback = NULL; if (musb->dma_controller) musb_dma_controller_destroy(musb->dma_controller); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 2337d7a7d62d..fd215fb45fd4 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -168,6 +168,7 @@ struct musb_io; * @adjust_channel_params: pre check for standard dma channel_program func * @pre_root_reset_end: called before the root usb port reset flag gets cleared * @post_root_reset_end: called after the root usb port reset flag gets cleared + * @phy_callback: optional callback function for the phy to call */ struct musb_platform_ops { @@ -214,6 +215,7 @@ struct musb_platform_ops { dma_addr_t *dma_addr, u32 *len); void (*pre_root_reset_end)(struct musb *musb); void (*post_root_reset_end)(struct musb *musb); + void (*phy_callback)(enum musb_vbus_id_status status); }; /* diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 1bd9232ff76f..bf05f807729f 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -46,7 +46,7 @@ struct omap2430_glue { struct device *dev; struct platform_device *musb; - enum omap_musb_vbus_id_status status; + enum musb_vbus_id_status status; struct work_struct omap_musb_mailbox_work; struct device *control_otghs; }; @@ -234,7 +234,7 @@ static inline void omap2430_low_level_init(struct musb *musb) musb_writel(musb->mregs, OTG_FORCESTDBY, l); } -void omap_musb_mailbox(enum omap_musb_vbus_id_status status) +static void omap2430_musb_mailbox(enum musb_vbus_id_status status) { struct omap2430_glue *glue = _glue; @@ -251,7 +251,6 @@ void omap_musb_mailbox(enum omap_musb_vbus_id_status status) schedule_work(&glue->omap_musb_mailbox_work); } -EXPORT_SYMBOL_GPL(omap_musb_mailbox); static void omap_musb_set_mailbox(struct omap2430_glue *glue) { @@ -262,7 +261,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) struct usb_otg *otg = musb->xceiv->otg; switch (glue->status) { - case OMAP_MUSB_ID_GROUND: + case MUSB_ID_GROUND: dev_dbg(dev, "ID GND\n"); otg->default_a = true; @@ -276,7 +275,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) } break; - case OMAP_MUSB_VBUS_VALID: + case MUSB_VBUS_VALID: dev_dbg(dev, "VBUS Connect\n"); otg->default_a = false; @@ -287,8 +286,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); break; - case OMAP_MUSB_ID_FLOAT: - case OMAP_MUSB_VBUS_OFF: + case MUSB_ID_FLOAT: + case MUSB_VBUS_OFF: dev_dbg(dev, "VBUS Disconnect\n"); musb->xceiv->last_event = USB_EVENT_NONE; @@ -430,7 +429,7 @@ static int omap2430_musb_init(struct musb *musb) setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); - if (glue->status != OMAP_MUSB_UNKNOWN) + if (glue->status != MUSB_UNKNOWN) omap_musb_set_mailbox(glue); phy_init(musb->phy); @@ -455,7 +454,7 @@ static void omap2430_musb_enable(struct musb *musb) switch (glue->status) { - case OMAP_MUSB_ID_GROUND: + case MUSB_ID_GROUND: omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST); if (data->interface_type != MUSB_INTERFACE_UTMI) break; @@ -474,7 +473,7 @@ static void omap2430_musb_enable(struct musb *musb) } break; - case OMAP_MUSB_VBUS_VALID: + case MUSB_VBUS_VALID: omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); break; @@ -488,7 +487,7 @@ static void omap2430_musb_disable(struct musb *musb) struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - if (glue->status != OMAP_MUSB_UNKNOWN) + if (glue->status != MUSB_UNKNOWN) omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DISCONNECT); } @@ -520,6 +519,8 @@ static const struct musb_platform_ops omap2430_ops = { .enable = omap2430_musb_enable, .disable = omap2430_musb_disable, + + .phy_callback = omap2430_musb_mailbox, }; static u64 omap2430_dmamask = DMA_BIT_MASK(32); @@ -551,7 +552,7 @@ static int omap2430_probe(struct platform_device *pdev) glue->dev = &pdev->dev; glue->musb = musb; - glue->status = OMAP_MUSB_UNKNOWN; + glue->status = MUSB_UNKNOWN; glue->control_otghs = ERR_PTR(-ENODEV); if (np) { diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 12741856a75c..014dbbd72132 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -102,7 +102,7 @@ struct twl6030_usb { int irq1; int irq2; - enum omap_musb_vbus_id_status linkstat; + enum musb_vbus_id_status linkstat; u8 asleep; bool vbus_enable; const char *regulator; @@ -189,13 +189,13 @@ static ssize_t twl6030_usb_vbus_show(struct device *dev, spin_lock_irqsave(&twl->lock, flags); switch (twl->linkstat) { - case OMAP_MUSB_VBUS_VALID: + case MUSB_VBUS_VALID: ret = snprintf(buf, PAGE_SIZE, "vbus\n"); break; - case OMAP_MUSB_ID_GROUND: + case MUSB_ID_GROUND: ret = snprintf(buf, PAGE_SIZE, "id\n"); break; - case OMAP_MUSB_VBUS_OFF: + case MUSB_VBUS_OFF: ret = snprintf(buf, PAGE_SIZE, "none\n"); break; default: @@ -210,7 +210,7 @@ static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL); static irqreturn_t twl6030_usb_irq(int irq, void *_twl) { struct twl6030_usb *twl = _twl; - enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN; + enum musb_vbus_id_status status = MUSB_UNKNOWN; u8 vbus_state, hw_state; int ret; @@ -225,14 +225,14 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) dev_err(twl->dev, "Failed to enable usb3v3\n"); twl->asleep = 1; - status = OMAP_MUSB_VBUS_VALID; + status = MUSB_VBUS_VALID; twl->linkstat = status; - omap_musb_mailbox(status); + musb_mailbox(status); } else { - if (twl->linkstat != OMAP_MUSB_UNKNOWN) { - status = OMAP_MUSB_VBUS_OFF; + if (twl->linkstat != MUSB_UNKNOWN) { + status = MUSB_VBUS_OFF; twl->linkstat = status; - omap_musb_mailbox(status); + musb_mailbox(status); if (twl->asleep) { regulator_disable(twl->usb3v3); twl->asleep = 0; @@ -248,7 +248,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) { struct twl6030_usb *twl = _twl; - enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN; + enum musb_vbus_id_status status = MUSB_UNKNOWN; u8 hw_state; int ret; @@ -262,9 +262,9 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) twl->asleep = 1; twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR); twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET); - status = OMAP_MUSB_ID_GROUND; + status = MUSB_ID_GROUND; twl->linkstat = status; - omap_musb_mailbox(status); + musb_mailbox(status); } else { twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR); twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); @@ -334,7 +334,7 @@ static int twl6030_usb_probe(struct platform_device *pdev) twl->dev = &pdev->dev; twl->irq1 = platform_get_irq(pdev, 0); twl->irq2 = platform_get_irq(pdev, 1); - twl->linkstat = OMAP_MUSB_UNKNOWN; + twl->linkstat = MUSB_UNKNOWN; twl->comparator.set_vbus = twl6030_set_vbus; twl->comparator.start_srp = twl6030_start_srp; diff --git a/include/linux/usb/musb-omap.h b/include/linux/usb/musb-omap.h deleted file mode 100644 index 7774c5986f07..000000000000 --- a/include/linux/usb/musb-omap.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011-2012 by Texas Instruments - * - * The Inventra Controller Driver for Linux is free software; you - * can redistribute it and/or modify it under the terms of the GNU - * General Public License version 2 as published by the Free Software - * Foundation. - */ - -#ifndef __MUSB_OMAP_H__ -#define __MUSB_OMAP_H__ - -enum omap_musb_vbus_id_status { - OMAP_MUSB_UNKNOWN = 0, - OMAP_MUSB_ID_GROUND, - OMAP_MUSB_ID_FLOAT, - OMAP_MUSB_VBUS_VALID, - OMAP_MUSB_VBUS_OFF, -}; - -#if (defined(CONFIG_USB_MUSB_OMAP2PLUS) || \ - defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE)) -void omap_musb_mailbox(enum omap_musb_vbus_id_status status); -#else -static inline void omap_musb_mailbox(enum omap_musb_vbus_id_status status) -{ -} -#endif - -#endif /* __MUSB_OMAP_H__ */ diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h index fa6dc132bd1b..96ddfb7ab018 100644 --- a/include/linux/usb/musb.h +++ b/include/linux/usb/musb.h @@ -133,6 +133,21 @@ struct musb_hdrc_platform_data { const void *platform_ops; }; +enum musb_vbus_id_status { + MUSB_UNKNOWN = 0, + MUSB_ID_GROUND, + MUSB_ID_FLOAT, + MUSB_VBUS_VALID, + MUSB_VBUS_OFF, +}; + +#if IS_ENABLED(CONFIG_USB_MUSB_HDRC) +void musb_mailbox(enum musb_vbus_id_status status); +#else +static inline void musb_mailbox(enum musb_vbus_id_status status) +{ +} +#endif /* TUSB 6010 support */ -- cgit v1.2.3 From be99c84300950e876074916b215b511f69f83d3b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 17 Dec 2015 09:55:41 -0600 Subject: usb: of: fix build breakage on !OF If OF is disabled, we will try to define a stub for of_usb_get_dr_mode_by_phy(), however that missed a static inline annotation which made us redefine the stub over and over again. Fix that. Fixes: 98bfb3946695 ("usb: of: add an api to get dr_mode by the phy node") Signed-off-by: Felipe Balbi --- include/linux/usb/of.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux/usb') diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index 3805757dcdc2..974bce93aa28 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -17,7 +17,8 @@ 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 -enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +static inline enum usb_dr_mode +of_usb_get_dr_mode_by_phy(struct device_node *phy_np) { return USB_DR_MODE_UNKNOWN; } -- cgit v1.2.3 From 8a0859b65b06ea07461271ce4f1fe25b48d1ec55 Mon Sep 17 00:00:00 2001 From: "Du, Changbin" Date: Fri, 18 Dec 2015 15:36:40 +0800 Subject: usb: gadget: forbid queuing request to a disabled ep Queue a request to disabled ep doesn't make sense, and induce caller make mistakes. Here is a example for the android mtp gadget function driver. A mem corruption can happen on below senario. 1) On disconnect, mtp driver disable its EPs, 2) During send_file_work and receive_file_work, mtp queues a request to ep. (The mtp driver need improve its synchronization logic!) 3) mtp_function_unbind is invoked and all mtp requests are freed. 4) when udc process the request queued on step 2, will cause kernel NULL pointer dereference exception. Signed-off-by: Du, Changbin Signed-off-by: Felipe Balbi --- include/linux/usb/gadget.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux/usb') diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 92467eea76de..d82d0068872b 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -402,6 +402,9 @@ static inline void usb_ep_free_request(struct usb_ep *ep, static inline int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { + if (WARN_ON_ONCE(!ep->enabled && ep->address)) + return -ESHUTDOWN; + return ep->ops->queue(ep, req, gfp_flags); } -- cgit v1.2.3