From 687ef9817df7ed960d14575b9033dde3d04631fe Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Apr 2014 10:30:33 -0500 Subject: usb: dwc3: gadget: clear stall when disabling endpoint so it seems like DWC3 IP doesn't clear stalls automatically when we disable an endpoint, because of that, we _must_ make sure stalls are cleared before clearing the proper bit in DALEPENA register. Cc: # v3.4+ Reported-by: Johannes Stezenbach Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a740eac..f0dc0ee 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -608,6 +608,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dwc3_remove_requests(dwc, dep); + /* make sure HW endpoint isn't stalled */ + if (dep->flags & DWC3_EP_STALL) + __dwc3_gadget_ep_set_halt(dep, 0); + reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg &= ~DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); -- cgit v0.10.2 From 3c9f94aca66aa8c83d531961ea8c7b8bace9433c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Apr 2014 15:08:29 -0500 Subject: usb: dwc3: core: refactor PHY initialization our probe() routine is too large and we can easily refactor PHY-related code out to another function to make it slightly less painful to read. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d001417..38976f3 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -486,70 +486,20 @@ static void dwc3_core_exit(struct dwc3 *dwc) phy_exit(dwc->usb3_generic_phy); } -#define DWC3_ALIGN_MASK (16 - 1) - -static int dwc3_probe(struct platform_device *pdev) +static int dwc3_core_get_phy(struct dwc3 *dwc) { - struct device *dev = &pdev->dev; - struct dwc3_platform_data *pdata = dev_get_platdata(dev); + struct device *dev = dwc->dev; struct device_node *node = dev->of_node; - struct resource *res; - struct dwc3 *dwc; - - int ret = -ENOMEM; - - void __iomem *regs; - void *mem; - - mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); - if (!mem) { - dev_err(dev, "not enough memory\n"); - return -ENOMEM; - } - dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); - dwc->mem = mem; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "missing IRQ\n"); - return -ENODEV; - } - dwc->xhci_resources[1].start = res->start; - dwc->xhci_resources[1].end = res->end; - dwc->xhci_resources[1].flags = res->flags; - dwc->xhci_resources[1].name = res->name; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing memory resource\n"); - return -ENODEV; - } + int ret; if (node) { - dwc->maximum_speed = of_usb_get_maximum_speed(node); - dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); - - dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); - dwc->dr_mode = of_usb_get_dr_mode(node); - } else if (pdata) { - dwc->maximum_speed = pdata->maximum_speed; - - dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); - dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); - - dwc->needs_fifo_resize = pdata->tx_fifo_resize; - dwc->dr_mode = pdata->dr_mode; } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); } - /* default to superspeed if no maximum_speed passed */ - if (dwc->maximum_speed == USB_SPEED_UNKNOWN) - dwc->maximum_speed = USB_SPEED_SUPER; - if (IS_ERR(dwc->usb2_phy)) { ret = PTR_ERR(dwc->usb2_phy); if (ret == -ENXIO || ret == -ENODEV) { @@ -600,6 +550,69 @@ static int dwc3_probe(struct platform_device *pdev) } } + return 0; +} + +#define DWC3_ALIGN_MASK (16 - 1) + +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; + + int ret = -ENOMEM; + + void __iomem *regs; + void *mem; + + mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); + if (!mem) { + dev_err(dev, "not enough memory\n"); + return -ENOMEM; + } + dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); + dwc->mem = mem; + dwc->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "missing IRQ\n"); + return -ENODEV; + } + dwc->xhci_resources[1].start = res->start; + dwc->xhci_resources[1].end = res->end; + dwc->xhci_resources[1].flags = res->flags; + dwc->xhci_resources[1].name = res->name; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory resource\n"); + return -ENODEV; + } + + if (node) { + dwc->maximum_speed = of_usb_get_maximum_speed(node); + + dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); + dwc->dr_mode = of_usb_get_dr_mode(node); + } else if (pdata) { + dwc->maximum_speed = pdata->maximum_speed; + + dwc->needs_fifo_resize = pdata->tx_fifo_resize; + dwc->dr_mode = pdata->dr_mode; + } + + /* default to superspeed if no maximum_speed passed */ + if (dwc->maximum_speed == USB_SPEED_UNKNOWN) + dwc->maximum_speed = USB_SPEED_SUPER; + + ret = dwc3_core_get_phy(dwc); + if (ret) + return ret; + dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; @@ -621,7 +634,6 @@ static int dwc3_probe(struct platform_device *pdev) dwc->regs = regs; dwc->regs_size = resource_size(res); - dwc->dev = dev; dev->dma_mask = dev->parent->dma_mask; dev->dma_parms = dev->parent->dma_parms; -- cgit v0.10.2 From 041832565e405d2e2ea218632b7bcafa87deaece Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 17 Apr 2014 11:24:27 -0500 Subject: usb: phy: mv-u3d: switch over to writel/readl by removing the _relaxed suffix, we can build this driver in other architectures. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c index d317903..d342175 100644 --- a/drivers/usb/phy/phy-mv-u3d-usb.c +++ b/drivers/usb/phy/phy-mv-u3d-usb.c @@ -39,8 +39,8 @@ static u32 mv_u3d_phy_read(void __iomem *base, u32 reg) addr = base; data = base + 0x4; - writel_relaxed(reg, addr); - return readl_relaxed(data); + writel(reg, addr); + return readl(data); } static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value) @@ -51,10 +51,10 @@ static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value) addr = base; data = base + 0x4; - writel_relaxed(reg, addr); - tmp = readl_relaxed(data); + writel(reg, addr); + tmp = readl(data); tmp |= value; - writel_relaxed(tmp, data); + writel(tmp, data); } static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value) @@ -65,10 +65,10 @@ static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value) addr = base; data = base + 0x4; - writel_relaxed(reg, addr); - tmp = readl_relaxed(data); + writel(reg, addr); + tmp = readl(data); tmp &= ~value; - writel_relaxed(tmp, data); + writel(tmp, data); } static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value) @@ -78,8 +78,8 @@ static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value) addr = base; data = base + 0x4; - writel_relaxed(reg, addr); - writel_relaxed(value, data); + writel(reg, addr); + writel(value, data); } static void mv_u3d_phy_shutdown(struct usb_phy *phy) -- cgit v0.10.2 From 5f94adfeed97a62f31a25d14effc6ac13c847333 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Apr 2014 15:13:45 -0500 Subject: usb: dwc3: core: refactor mode initialization to its own function Move mode (Host, Peripheral, OTG) initialization to its own function in order to decrease the size of our probe() routine. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 38976f3..af8c8f6 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -553,6 +553,69 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) return 0; } +static int dwc3_core_init_mode(struct dwc3 *dwc) +{ + struct device *dev = dwc->dev; + int ret; + + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + ret = dwc3_gadget_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize gadget\n"); + return ret; + } + break; + case USB_DR_MODE_HOST: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize host\n"); + return ret; + } + break; + case USB_DR_MODE_OTG: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize host\n"); + return ret; + } + + ret = dwc3_gadget_init(dwc); + if (ret) { + dev_err(dev, "failed to initialize gadget\n"); + return ret; + } + break; + default: + dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); + return -EINVAL; + } + + return 0; +} + +static void dwc3_core_exit_mode(struct dwc3 *dwc) +{ + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_gadget_exit(dwc); + break; + case USB_DR_MODE_HOST: + dwc3_host_exit(dwc); + break; + case USB_DR_MODE_OTG: + dwc3_host_exit(dwc); + dwc3_gadget_exit(dwc); + break; + default: + /* do nothing */ + break; + } +} + #define DWC3_ALIGN_MASK (16 - 1) static int dwc3_probe(struct platform_device *pdev) @@ -682,41 +745,9 @@ static int dwc3_probe(struct platform_device *pdev) goto err_usb3phy_power; } - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); - ret = dwc3_gadget_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize gadget\n"); - goto err2; - } - break; - case USB_DR_MODE_HOST: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - goto err2; - } - break; - case USB_DR_MODE_OTG: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - goto err2; - } - - ret = dwc3_gadget_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize gadget\n"); - goto err2; - } - break; - default: - dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); + ret = dwc3_core_init_mode(dwc); + if (ret) goto err2; - } ret = dwc3_debugfs_init(dwc); if (ret) { @@ -729,21 +760,7 @@ static int dwc3_probe(struct platform_device *pdev) return 0; err3: - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_gadget_exit(dwc); - break; - case USB_DR_MODE_HOST: - dwc3_host_exit(dwc); - break; - case USB_DR_MODE_OTG: - dwc3_host_exit(dwc); - dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } + dwc3_core_exit_mode(dwc); err2: dwc3_event_buffers_cleanup(dwc); @@ -778,23 +795,7 @@ static int dwc3_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); dwc3_debugfs_exit(dwc); - - switch (dwc->dr_mode) { - case USB_DR_MODE_PERIPHERAL: - dwc3_gadget_exit(dwc); - break; - case USB_DR_MODE_HOST: - dwc3_host_exit(dwc); - break; - case USB_DR_MODE_OTG: - dwc3_host_exit(dwc); - dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } - + dwc3_core_exit_mode(dwc); dwc3_event_buffers_cleanup(dwc); dwc3_free_event_buffers(dwc); dwc3_core_exit(dwc); -- cgit v0.10.2 From 0700faaf736492bd203630d179b639a1f5bbb576 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 1 Apr 2014 13:19:32 -0500 Subject: usb: gadget: only GPL drivers in the gadget and phy framework We only support GPL drivers in the USB Gadget Framework, it sounds correct to make all exported symbols GPL too. Acked-by: Greg Kroah-Hartman Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 7d1cc01..dcead55 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1005,7 +1005,7 @@ void unregister_gadget_item(struct config_item *item) unregister_gadget(gi); } -EXPORT_SYMBOL(unregister_gadget_item); +EXPORT_SYMBOL_GPL(unregister_gadget_item); static int __init gadget_cfs_init(void) { diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 2e164dc..a01b3bd 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -190,7 +190,7 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data, /* Devices management *******************************************************/ DEFINE_MUTEX(ffs_lock); -EXPORT_SYMBOL(ffs_lock); +EXPORT_SYMBOL_GPL(ffs_lock); static struct ffs_dev *_ffs_find_dev(const char *name); static struct ffs_dev *_ffs_alloc_dev(void); @@ -2876,7 +2876,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) return ret; } -EXPORT_SYMBOL(ffs_name_dev); +EXPORT_SYMBOL_GPL(ffs_name_dev); int ffs_single_dev(struct ffs_dev *dev) { @@ -2893,7 +2893,7 @@ int ffs_single_dev(struct ffs_dev *dev) ffs_dev_unlock(); return ret; } -EXPORT_SYMBOL(ffs_single_dev); +EXPORT_SYMBOL_GPL(ffs_single_dev); /* * ffs_lock must be taken by the caller of this function diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index c11761c..139bc9c 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -834,7 +834,7 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) opts->borrowed_net = opts->bound = true; opts->net = net; } -EXPORT_SYMBOL(rndis_borrow_net); +EXPORT_SYMBOL_GPL(rndis_borrow_net); static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item) { diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index d822d82..4c36694 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -760,7 +760,7 @@ int rndis_signal_connect(int configNr) return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_CONNECT); } -EXPORT_SYMBOL(rndis_signal_connect); +EXPORT_SYMBOL_GPL(rndis_signal_connect); int rndis_signal_disconnect(int configNr) { @@ -769,7 +769,7 @@ int rndis_signal_disconnect(int configNr) return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_DISCONNECT); } -EXPORT_SYMBOL(rndis_signal_disconnect); +EXPORT_SYMBOL_GPL(rndis_signal_disconnect); void rndis_uninit(int configNr) { @@ -784,13 +784,13 @@ void rndis_uninit(int configNr) while ((buf = rndis_get_next_response(configNr, &length))) rndis_free_response(configNr, buf); } -EXPORT_SYMBOL(rndis_uninit); +EXPORT_SYMBOL_GPL(rndis_uninit); void rndis_set_host_mac(int configNr, const u8 *addr) { rndis_per_dev_params[configNr].host_mac = addr; } -EXPORT_SYMBOL(rndis_set_host_mac); +EXPORT_SYMBOL_GPL(rndis_set_host_mac); /* * Message Parser @@ -873,7 +873,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf) return -ENOTSUPP; } -EXPORT_SYMBOL(rndis_msg_parser); +EXPORT_SYMBOL_GPL(rndis_msg_parser); int rndis_register(void (*resp_avail)(void *v), void *v) { @@ -895,7 +895,7 @@ int rndis_register(void (*resp_avail)(void *v), void *v) return -ENODEV; } -EXPORT_SYMBOL(rndis_register); +EXPORT_SYMBOL_GPL(rndis_register); void rndis_deregister(int configNr) { @@ -904,7 +904,7 @@ void rndis_deregister(int configNr) if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params[configNr].used = 0; } -EXPORT_SYMBOL(rndis_deregister); +EXPORT_SYMBOL_GPL(rndis_deregister); int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) { @@ -918,7 +918,7 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) return 0; } -EXPORT_SYMBOL(rndis_set_param_dev); +EXPORT_SYMBOL_GPL(rndis_set_param_dev); int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) { @@ -931,7 +931,7 @@ int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) return 0; } -EXPORT_SYMBOL(rndis_set_param_vendor); +EXPORT_SYMBOL_GPL(rndis_set_param_vendor); int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) { @@ -943,7 +943,7 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) return 0; } -EXPORT_SYMBOL(rndis_set_param_medium); +EXPORT_SYMBOL_GPL(rndis_set_param_medium); void rndis_add_hdr(struct sk_buff *skb) { @@ -958,7 +958,7 @@ void rndis_add_hdr(struct sk_buff *skb) header->DataOffset = cpu_to_le32(36); header->DataLength = cpu_to_le32(skb->len - sizeof(*header)); } -EXPORT_SYMBOL(rndis_add_hdr); +EXPORT_SYMBOL_GPL(rndis_add_hdr); void rndis_free_response(int configNr, u8 *buf) { @@ -975,7 +975,7 @@ void rndis_free_response(int configNr, u8 *buf) } } } -EXPORT_SYMBOL(rndis_free_response); +EXPORT_SYMBOL_GPL(rndis_free_response); u8 *rndis_get_next_response(int configNr, u32 *length) { @@ -997,7 +997,7 @@ u8 *rndis_get_next_response(int configNr, u32 *length) return NULL; } -EXPORT_SYMBOL(rndis_get_next_response); +EXPORT_SYMBOL_GPL(rndis_get_next_response); static rndis_resp_t *rndis_add_response(int configNr, u32 length) { @@ -1041,7 +1041,7 @@ int rndis_rm_hdr(struct gether *port, skb_queue_tail(list, skb); return 0; } -EXPORT_SYMBOL(rndis_rm_hdr); +EXPORT_SYMBOL_GPL(rndis_rm_hdr); #ifdef CONFIG_USB_GADGET_DEBUG_FILES diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index ec20a1f..ff205a7 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -43,7 +43,7 @@ struct usb_interface_descriptor fsg_intf_desc = { .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ .iInterface = FSG_STRING_INTERFACE, }; -EXPORT_SYMBOL(fsg_intf_desc); +EXPORT_SYMBOL_GPL(fsg_intf_desc); /* * Three full-speed endpoint descriptors: bulk-in, bulk-out, and @@ -58,7 +58,7 @@ struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */ }; -EXPORT_SYMBOL(fsg_fs_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc); struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -68,7 +68,7 @@ struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */ }; -EXPORT_SYMBOL(fsg_fs_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc); struct usb_descriptor_header *fsg_fs_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, @@ -76,7 +76,7 @@ struct usb_descriptor_header *fsg_fs_function[] = { (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, NULL, }; -EXPORT_SYMBOL(fsg_fs_function); +EXPORT_SYMBOL_GPL(fsg_fs_function); /* @@ -95,7 +95,7 @@ struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }; -EXPORT_SYMBOL(fsg_hs_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc); struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -106,7 +106,7 @@ struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = { .wMaxPacketSize = cpu_to_le16(512), .bInterval = 1, /* NAK every 1 uframe */ }; -EXPORT_SYMBOL(fsg_hs_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc); struct usb_descriptor_header *fsg_hs_function[] = { @@ -115,7 +115,7 @@ struct usb_descriptor_header *fsg_hs_function[] = { (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, NULL, }; -EXPORT_SYMBOL(fsg_hs_function); +EXPORT_SYMBOL_GPL(fsg_hs_function); struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -125,7 +125,7 @@ struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; -EXPORT_SYMBOL(fsg_ss_bulk_in_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc); struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { .bLength = sizeof(fsg_ss_bulk_in_comp_desc), @@ -133,7 +133,7 @@ struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -EXPORT_SYMBOL(fsg_ss_bulk_in_comp_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc); struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -143,7 +143,7 @@ struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; -EXPORT_SYMBOL(fsg_ss_bulk_out_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc); struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { .bLength = sizeof(fsg_ss_bulk_in_comp_desc), @@ -151,7 +151,7 @@ struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { /*.bMaxBurst = DYNAMIC, */ }; -EXPORT_SYMBOL(fsg_ss_bulk_out_comp_desc); +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc); struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, @@ -161,7 +161,7 @@ struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, NULL, }; -EXPORT_SYMBOL(fsg_ss_function); +EXPORT_SYMBOL_GPL(fsg_ss_function); /*-------------------------------------------------------------------------*/ @@ -179,7 +179,7 @@ void fsg_lun_close(struct fsg_lun *curlun) curlun->filp = NULL; } } -EXPORT_SYMBOL(fsg_lun_close); +EXPORT_SYMBOL_GPL(fsg_lun_close); int fsg_lun_open(struct fsg_lun *curlun, const char *filename) { @@ -278,7 +278,7 @@ out: fput(filp); return rc; } -EXPORT_SYMBOL(fsg_lun_open); +EXPORT_SYMBOL_GPL(fsg_lun_open); /*-------------------------------------------------------------------------*/ @@ -295,7 +295,7 @@ int fsg_lun_fsync_sub(struct fsg_lun *curlun) return 0; return vfs_fsync(filp, 1); } -EXPORT_SYMBOL(fsg_lun_fsync_sub); +EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); void store_cdrom_address(u8 *dest, int msf, u32 addr) { @@ -314,7 +314,7 @@ void store_cdrom_address(u8 *dest, int msf, u32 addr) put_unaligned_be32(addr, dest); } } -EXPORT_SYMBOL(store_cdrom_address); +EXPORT_SYMBOL_GPL(store_cdrom_address); /*-------------------------------------------------------------------------*/ @@ -325,13 +325,13 @@ ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf) ? curlun->ro : curlun->initially_ro); } -EXPORT_SYMBOL(fsg_show_ro); +EXPORT_SYMBOL_GPL(fsg_show_ro); ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->nofua); } -EXPORT_SYMBOL(fsg_show_nofua); +EXPORT_SYMBOL_GPL(fsg_show_nofua); ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf) @@ -357,19 +357,19 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, up_read(filesem); return rc; } -EXPORT_SYMBOL(fsg_show_file); +EXPORT_SYMBOL_GPL(fsg_show_file); ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->cdrom); } -EXPORT_SYMBOL(fsg_show_cdrom); +EXPORT_SYMBOL_GPL(fsg_show_cdrom); ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) { return sprintf(buf, "%u\n", curlun->removable); } -EXPORT_SYMBOL(fsg_show_removable); +EXPORT_SYMBOL_GPL(fsg_show_removable); /* * The caller must hold fsg->filesem for reading when calling this function. @@ -410,7 +410,7 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, return rc; } -EXPORT_SYMBOL(fsg_store_ro); +EXPORT_SYMBOL_GPL(fsg_store_ro); ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) { @@ -429,7 +429,7 @@ ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) return count; } -EXPORT_SYMBOL(fsg_store_nofua); +EXPORT_SYMBOL_GPL(fsg_store_nofua); ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) @@ -460,7 +460,7 @@ ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, up_write(filesem); return (rc < 0 ? rc : count); } -EXPORT_SYMBOL(fsg_store_file); +EXPORT_SYMBOL_GPL(fsg_store_file); ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) @@ -483,7 +483,7 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, return ret; } -EXPORT_SYMBOL(fsg_store_cdrom); +EXPORT_SYMBOL_GPL(fsg_store_cdrom); ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count) @@ -499,6 +499,6 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, return count; } -EXPORT_SYMBOL(fsg_store_removable); +EXPORT_SYMBOL_GPL(fsg_store_removable); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 50d09c2..216bbd1 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -841,7 +841,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, return dev; } -EXPORT_SYMBOL(gether_setup_name); +EXPORT_SYMBOL_GPL(gether_setup_name); struct net_device *gether_setup_name_default(const char *netname) { @@ -879,7 +879,7 @@ struct net_device *gether_setup_name_default(const char *netname) return net; } -EXPORT_SYMBOL(gether_setup_name_default); +EXPORT_SYMBOL_GPL(gether_setup_name_default); int gether_register_netdev(struct net_device *net) { @@ -917,7 +917,7 @@ int gether_register_netdev(struct net_device *net) return status; } -EXPORT_SYMBOL(gether_register_netdev); +EXPORT_SYMBOL_GPL(gether_register_netdev); void gether_set_gadget(struct net_device *net, struct usb_gadget *g) { @@ -927,7 +927,7 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g) dev->gadget = g; SET_NETDEV_DEV(net, &g->dev); } -EXPORT_SYMBOL(gether_set_gadget); +EXPORT_SYMBOL_GPL(gether_set_gadget); int gether_set_dev_addr(struct net_device *net, const char *dev_addr) { @@ -940,7 +940,7 @@ int gether_set_dev_addr(struct net_device *net, const char *dev_addr) memcpy(dev->dev_mac, new_addr, ETH_ALEN); return 0; } -EXPORT_SYMBOL(gether_set_dev_addr); +EXPORT_SYMBOL_GPL(gether_set_dev_addr); int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) { @@ -949,7 +949,7 @@ int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) dev = netdev_priv(net); return get_ether_addr_str(dev->dev_mac, dev_addr, len); } -EXPORT_SYMBOL(gether_get_dev_addr); +EXPORT_SYMBOL_GPL(gether_get_dev_addr); int gether_set_host_addr(struct net_device *net, const char *host_addr) { @@ -962,7 +962,7 @@ int gether_set_host_addr(struct net_device *net, const char *host_addr) memcpy(dev->host_mac, new_addr, ETH_ALEN); return 0; } -EXPORT_SYMBOL(gether_set_host_addr); +EXPORT_SYMBOL_GPL(gether_set_host_addr); int gether_get_host_addr(struct net_device *net, char *host_addr, int len) { @@ -971,7 +971,7 @@ int gether_get_host_addr(struct net_device *net, char *host_addr, int len) dev = netdev_priv(net); return get_ether_addr_str(dev->host_mac, host_addr, len); } -EXPORT_SYMBOL(gether_get_host_addr); +EXPORT_SYMBOL_GPL(gether_get_host_addr); int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) { @@ -985,7 +985,7 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len) return strlen(host_addr); } -EXPORT_SYMBOL(gether_get_host_addr_cdc); +EXPORT_SYMBOL_GPL(gether_get_host_addr_cdc); void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN]) { @@ -994,7 +994,7 @@ void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN]) dev = netdev_priv(net); memcpy(host_mac, dev->host_mac, ETH_ALEN); } -EXPORT_SYMBOL(gether_get_host_addr_u8); +EXPORT_SYMBOL_GPL(gether_get_host_addr_u8); void gether_set_qmult(struct net_device *net, unsigned qmult) { @@ -1003,7 +1003,7 @@ void gether_set_qmult(struct net_device *net, unsigned qmult) dev = netdev_priv(net); dev->qmult = qmult; } -EXPORT_SYMBOL(gether_set_qmult); +EXPORT_SYMBOL_GPL(gether_set_qmult); unsigned gether_get_qmult(struct net_device *net) { @@ -1012,7 +1012,7 @@ unsigned gether_get_qmult(struct net_device *net) dev = netdev_priv(net); return dev->qmult; } -EXPORT_SYMBOL(gether_get_qmult); +EXPORT_SYMBOL_GPL(gether_get_qmult); int gether_get_ifname(struct net_device *net, char *name, int len) { @@ -1021,7 +1021,7 @@ int gether_get_ifname(struct net_device *net, char *name, int len) rtnl_unlock(); return strlen(name); } -EXPORT_SYMBOL(gether_get_ifname); +EXPORT_SYMBOL_GPL(gether_get_ifname); /** * gether_cleanup - remove Ethernet-over-USB device @@ -1038,7 +1038,7 @@ void gether_cleanup(struct eth_dev *dev) flush_work(&dev->work); free_netdev(dev->net); } -EXPORT_SYMBOL(gether_cleanup); +EXPORT_SYMBOL_GPL(gether_cleanup); /** * gether_connect - notify network layer that USB link is active @@ -1119,7 +1119,7 @@ fail0: return ERR_PTR(result); return dev->net; } -EXPORT_SYMBOL(gether_connect); +EXPORT_SYMBOL_GPL(gether_connect); /** * gether_disconnect - notify network layer that USB link is inactive @@ -1197,7 +1197,7 @@ void gether_disconnect(struct gether *link) dev->port_usb = NULL; spin_unlock(&dev->lock); } -EXPORT_SYMBOL(gether_disconnect); +EXPORT_SYMBOL_GPL(gether_disconnect); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Brownell"); diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index 63b6642..c6276f0 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -29,4 +29,4 @@ struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len) } return req; } -EXPORT_SYMBOL(alloc_ep_req); +EXPORT_SYMBOL_GPL(alloc_ep_req); diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index bb39498..95e70bc 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -54,14 +54,14 @@ void usb_nop_xceiv_register(void) return; } } -EXPORT_SYMBOL(usb_nop_xceiv_register); +EXPORT_SYMBOL_GPL(usb_nop_xceiv_register); void usb_nop_xceiv_unregister(void) { platform_device_unregister(pd); pd = NULL; } -EXPORT_SYMBOL(usb_nop_xceiv_unregister); +EXPORT_SYMBOL_GPL(usb_nop_xceiv_unregister); static int nop_set_suspend(struct usb_phy *x, int suspend) { -- cgit v0.10.2 From 4525beeb9aadbb9e1cb3e9e135f4371553f26a70 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Apr 2014 15:20:44 -0500 Subject: usb: phy: rename usb_nop_xceiv to usb_phy_generic no functional changes, just renaming the function in order to make it slightly clearer what it should be used for, also matching the driver name. Signed-off-by: Felipe Balbi diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 10855eb..ab983cd 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = { /* .init_data filled later */ }; -static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */ +static const char *nop_name = "usb_phy_generic"; /* NOP PHY driver */ static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */ /** @@ -435,7 +435,7 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) struct platform_device *pdev; char *phy_id; struct platform_device_info pdevinfo; - struct usb_phy_gen_xceiv_platform_data nop_pdata; + struct usb_phy_generic_platform_data nop_pdata; for (i = 0; i < num_phys; i++) { @@ -469,8 +469,8 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) pdevinfo.id = phy->port; pdevinfo.data = &nop_pdata; pdevinfo.size_data = - sizeof(struct usb_phy_gen_xceiv_platform_data); - scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d", + sizeof(struct usb_phy_generic_platform_data); + scnprintf(phy_id, MAX_STR, "usb_phy_generic.%d", phy->port); pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 28c8ad7..821cc59 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -38,13 +38,13 @@ struct dwc3_exynos { static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) { - struct usb_phy_gen_xceiv_platform_data pdata; + struct usb_phy_generic_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; @@ -56,7 +56,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) if (ret) goto err1; - pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO); if (!pdev) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index f393c18..8b162f0 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -40,13 +40,13 @@ struct dwc3_pci { static int dwc3_pci_register_phys(struct dwc3_pci *glue) { - struct usb_phy_gen_xceiv_platform_data pdata; + struct usb_phy_generic_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); + pdev = platform_device_alloc("usb_phy_generic", 0); if (!pdev) return -ENOMEM; @@ -58,7 +58,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue) if (ret) goto err1; - pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); + pdev = platform_device_alloc("usb_phy_generic", 1); if (!pdev) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index b3aa018..77ed664 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -360,7 +360,7 @@ static int am35x_musb_init(struct musb *musb) if (!rev) return -ENODEV; - usb_nop_xceiv_register(); + usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -402,7 +402,7 @@ static int am35x_musb_exit(struct musb *musb) data->set_phy_power(0); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); return 0; } diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 796677f..607f3ae 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -401,7 +401,7 @@ static int bfin_musb_init(struct musb *musb) } gpio_direction_output(musb->config->gpio_vrsel, 0); - usb_nop_xceiv_register(); + usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { gpio_free(musb->config->gpio_vrsel); @@ -426,7 +426,7 @@ static int bfin_musb_exit(struct musb *musb) gpio_free(musb->config->gpio_vrsel); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); return 0; } diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index e3486de..bcdce8e 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -418,7 +418,7 @@ static int da8xx_musb_init(struct musb *musb) if (!rev) goto fail; - usb_nop_xceiv_register(); + usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; @@ -453,7 +453,7 @@ static int da8xx_musb_exit(struct musb *musb) phy_off(); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); return 0; } diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index c259dac..c0e07ed 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -381,7 +381,7 @@ static int davinci_musb_init(struct musb *musb) u32 revision; int ret = -ENODEV; - usb_nop_xceiv_register(); + usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; @@ -439,7 +439,7 @@ static int davinci_musb_init(struct musb *musb) fail: usb_put_phy(musb->xceiv); unregister: - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); return ret; } @@ -487,7 +487,7 @@ static int davinci_musb_exit(struct musb *musb) phy_off(); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); return 0; } diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 4e9fb1d..0c0f5ee 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1065,7 +1065,7 @@ static int tusb_musb_init(struct musb *musb) void __iomem *sync = NULL; int ret; - usb_nop_xceiv_register(); + usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -1117,7 +1117,7 @@ done: iounmap(sync); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); } return ret; } @@ -1133,7 +1133,7 @@ static int tusb_musb_exit(struct musb *musb) iounmap(musb->sync_va); usb_put_phy(musb->xceiv); - usb_nop_xceiv_unregister(); + usb_phy_generic_unregister(); return 0; } diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 12fc346..bb866e4 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -13,7 +13,7 @@ #include "phy-generic.h" struct am335x_phy { - struct usb_phy_gen_xceiv usb_phy_gen; + struct usb_phy_generic usb_phy_gen; struct phy_control *phy_ctrl; int id; }; diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 95e70bc..e76ca4c 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -43,32 +43,32 @@ static struct platform_device *pd; -void usb_nop_xceiv_register(void) +void usb_phy_generic_register(void) { if (pd) return; - pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); + pd = platform_device_register_simple("usb_phy_generic", -1, NULL, 0); if (IS_ERR(pd)) { pr_err("Unable to register generic usb transceiver\n"); pd = NULL; return; } } -EXPORT_SYMBOL_GPL(usb_nop_xceiv_register); +EXPORT_SYMBOL_GPL(usb_phy_generic_register); -void usb_nop_xceiv_unregister(void) +void usb_phy_generic_unregister(void) { platform_device_unregister(pd); pd = NULL; } -EXPORT_SYMBOL_GPL(usb_nop_xceiv_unregister); +EXPORT_SYMBOL_GPL(usb_phy_generic_unregister); static int nop_set_suspend(struct usb_phy *x, int suspend) { return 0; } -static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted) +static void nop_reset_set(struct usb_phy_generic *nop, int asserted) { int value; @@ -87,7 +87,7 @@ static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted) int usb_gen_phy_init(struct usb_phy *phy) { - struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); + struct usb_phy_generic *nop = dev_get_drvdata(phy->dev); if (!IS_ERR(nop->vcc)) { if (regulator_enable(nop->vcc)) @@ -106,7 +106,7 @@ EXPORT_SYMBOL_GPL(usb_gen_phy_init); void usb_gen_phy_shutdown(struct usb_phy *phy) { - struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); + struct usb_phy_generic *nop = dev_get_drvdata(phy->dev); /* Assert RESET */ nop_reset_set(nop, 1); @@ -150,8 +150,8 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } -int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, - struct usb_phy_gen_xceiv_platform_data *pdata) +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, + struct usb_phy_generic_platform_data *pdata) { enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; @@ -245,10 +245,10 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, } EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); -static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) +static int usb_phy_generic_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usb_phy_gen_xceiv *nop; + struct usb_phy_generic *nop; int err; nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); @@ -274,9 +274,9 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) return 0; } -static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) +static int usb_phy_generic_remove(struct platform_device *pdev) { - struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); + struct usb_phy_generic *nop = platform_get_drvdata(pdev); usb_remove_phy(&nop->phy); @@ -290,29 +290,29 @@ static const struct of_device_id nop_xceiv_dt_ids[] = { MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); -static struct platform_driver usb_phy_gen_xceiv_driver = { - .probe = usb_phy_gen_xceiv_probe, - .remove = usb_phy_gen_xceiv_remove, +static struct platform_driver usb_phy_generic_driver = { + .probe = usb_phy_generic_probe, + .remove = usb_phy_generic_remove, .driver = { - .name = "usb_phy_gen_xceiv", + .name = "usb_phy_generic", .owner = THIS_MODULE, .of_match_table = nop_xceiv_dt_ids, }, }; -static int __init usb_phy_gen_xceiv_init(void) +static int __init usb_phy_generic_init(void) { - return platform_driver_register(&usb_phy_gen_xceiv_driver); + return platform_driver_register(&usb_phy_generic_driver); } -subsys_initcall(usb_phy_gen_xceiv_init); +subsys_initcall(usb_phy_generic_init); -static void __exit usb_phy_gen_xceiv_exit(void) +static void __exit usb_phy_generic_exit(void) { - platform_driver_unregister(&usb_phy_gen_xceiv_driver); + platform_driver_unregister(&usb_phy_generic_driver); } -module_exit(usb_phy_gen_xceiv_exit); +module_exit(usb_phy_generic_exit); -MODULE_ALIAS("platform:usb_phy_gen_xceiv"); +MODULE_ALIAS("platform:usb_phy_generic"); MODULE_AUTHOR("Texas Instruments Inc"); MODULE_DESCRIPTION("NOP USB Transceiver driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h index 38a81f3..f32450a 100644 --- a/drivers/usb/phy/phy-generic.h +++ b/drivers/usb/phy/phy-generic.h @@ -3,7 +3,7 @@ #include -struct usb_phy_gen_xceiv { +struct usb_phy_generic { struct usb_phy phy; struct device *dev; struct clk *clk; @@ -15,7 +15,7 @@ struct usb_phy_gen_xceiv { int usb_gen_phy_init(struct usb_phy *phy); void usb_gen_phy_shutdown(struct usb_phy *phy); -int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, - struct usb_phy_gen_xceiv_platform_data *pdata); +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, + struct usb_phy_generic_platform_data *pdata); #endif diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index d762003..2404c44 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -35,7 +35,7 @@ #define PHY_REF_SSP_EN BIT(29) struct keystone_usbphy { - struct usb_phy_gen_xceiv usb_phy_gen; + struct usb_phy_generic usb_phy_gen; void __iomem *phy_ctrl; }; diff --git a/include/linux/usb/usb_phy_gen_xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h index cc8d818..c00176d 100644 --- a/include/linux/usb/usb_phy_gen_xceiv.h +++ b/include/linux/usb/usb_phy_gen_xceiv.h @@ -3,7 +3,7 @@ #include -struct usb_phy_gen_xceiv_platform_data { +struct usb_phy_generic_platform_data { enum usb_phy_type type; unsigned long clk_rate; @@ -15,14 +15,14 @@ struct usb_phy_gen_xceiv_platform_data { #if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) /* sometimes transceivers are accessed only through e.g. ULPI */ -extern void usb_nop_xceiv_register(void); -extern void usb_nop_xceiv_unregister(void); +extern void usb_phy_generic_register(void); +extern void usb_phy_generic_unregister(void); #else -static inline void usb_nop_xceiv_register(void) +static inline void usb_phy_generic_register(void) { } -static inline void usb_nop_xceiv_unregister(void) +static inline void usb_phy_generic_unregister(void) { } #endif -- cgit v0.10.2 From d7078df6be6e9e5e3ac354859f5b8d60114391b4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Apr 2014 15:28:32 -0500 Subject: usb: phy: rename to now that all functions match the driver name, the only missing piece is to rename the header file itself. Signed-off-by: Felipe Balbi diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index d6ed819..660bfc5 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index ab983cd..745367c 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include "soc.h" #include "omap_device.h" diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 821cc59..ed22d72 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 8b162f0..1ed95e0 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -23,7 +23,7 @@ #include #include -#include +#include /* FIXME define these in */ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 77ed664..044cd82 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include "musb_core.h" diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 607f3ae..c9992a2 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index bcdce8e..a0dabb0 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index c0e07ed..7370354 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 3372ded..1888292 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 0c0f5ee..8d4a819 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "musb_core.h" diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index bb866e4..585e50c 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index e76ca4c..2c49cd8 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h index f32450a..d8feacc 100644 --- a/drivers/usb/phy/phy-generic.h +++ b/drivers/usb/phy/phy-generic.h @@ -1,7 +1,7 @@ #ifndef _PHY_GENERIC_H_ #define _PHY_GENERIC_H_ -#include +#include struct usb_phy_generic { struct usb_phy phy; diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index 2404c44..f4d722d 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/include/linux/usb/usb_phy_gen_xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h deleted file mode 100644 index c00176d..0000000 --- a/include/linux/usb/usb_phy_gen_xceiv.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __LINUX_USB_NOP_XCEIV_H -#define __LINUX_USB_NOP_XCEIV_H - -#include - -struct usb_phy_generic_platform_data { - enum usb_phy_type type; - unsigned long clk_rate; - - /* if set fails with -EPROBE_DEFER if can't get regulator */ - unsigned int needs_vcc:1; - unsigned int needs_reset:1; /* deprecated */ - int gpio_reset; -}; - -#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) -/* sometimes transceivers are accessed only through e.g. ULPI */ -extern void usb_phy_generic_register(void); -extern void usb_phy_generic_unregister(void); -#else -static inline void usb_phy_generic_register(void) -{ -} - -static inline void usb_phy_generic_unregister(void) -{ -} -#endif - -#endif /* __LINUX_USB_NOP_XCEIV_H */ diff --git a/include/linux/usb/usb_phy_generic.h b/include/linux/usb/usb_phy_generic.h new file mode 100644 index 0000000..c00176d --- /dev/null +++ b/include/linux/usb/usb_phy_generic.h @@ -0,0 +1,30 @@ +#ifndef __LINUX_USB_NOP_XCEIV_H +#define __LINUX_USB_NOP_XCEIV_H + +#include + +struct usb_phy_generic_platform_data { + enum usb_phy_type type; + unsigned long clk_rate; + + /* if set fails with -EPROBE_DEFER if can't get regulator */ + unsigned int needs_vcc:1; + unsigned int needs_reset:1; /* deprecated */ + int gpio_reset; +}; + +#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) +/* sometimes transceivers are accessed only through e.g. ULPI */ +extern void usb_phy_generic_register(void); +extern void usb_phy_generic_unregister(void); +#else +static inline void usb_phy_generic_register(void) +{ +} + +static inline void usb_phy_generic_unregister(void) +{ +} +#endif + +#endif /* __LINUX_USB_NOP_XCEIV_H */ -- cgit v0.10.2 From e741e637a85a802a93125dca1ecf324bc414101b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Apr 2014 16:05:17 -0500 Subject: usb: musb: move usb_phy_generic_{un,}register calls to probe()/remove() This patch is in preparation to supporting calling those functions multiple times. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 044cd82..05459b5 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -360,7 +360,6 @@ static int am35x_musb_init(struct musb *musb) if (!rev) return -ENODEV; - usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -402,7 +401,6 @@ static int am35x_musb_exit(struct musb *musb) data->set_phy_power(0); usb_put_phy(musb->xceiv); - usb_phy_generic_unregister(); return 0; } @@ -505,6 +503,7 @@ static int am35x_probe(struct platform_device *pdev) pdata->platform_ops = &am35x_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); pinfo = am35x_dev_info; @@ -547,6 +546,7 @@ static int am35x_remove(struct platform_device *pdev) struct am35x_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(); clk_disable(glue->clk); clk_disable(glue->phy_clk); clk_put(glue->clk); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index c9992a2..53acffe 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -401,7 +401,6 @@ static int bfin_musb_init(struct musb *musb) } gpio_direction_output(musb->config->gpio_vrsel, 0); - usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { gpio_free(musb->config->gpio_vrsel); @@ -424,9 +423,8 @@ static int bfin_musb_init(struct musb *musb) static int bfin_musb_exit(struct musb *musb) { gpio_free(musb->config->gpio_vrsel); - usb_put_phy(musb->xceiv); - usb_phy_generic_unregister(); + return 0; } @@ -477,6 +475,7 @@ static int bfin_probe(struct platform_device *pdev) pdata->platform_ops = &bfin_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -528,6 +527,7 @@ static int bfin_remove(struct platform_device *pdev) struct bfin_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(); kfree(glue); return 0; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index a0dabb0..024751f 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -418,7 +418,6 @@ static int da8xx_musb_init(struct musb *musb) if (!rev) goto fail; - usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; @@ -453,7 +452,6 @@ static int da8xx_musb_exit(struct musb *musb) phy_off(); usb_put_phy(musb->xceiv); - usb_phy_generic_unregister(); return 0; } @@ -512,6 +510,7 @@ static int da8xx_probe(struct platform_device *pdev) pdata->platform_ops = &da8xx_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -561,6 +560,7 @@ static int da8xx_remove(struct platform_device *pdev) struct da8xx_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 7370354..de8492b 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -381,7 +381,6 @@ static int davinci_musb_init(struct musb *musb) u32 revision; int ret = -ENODEV; - usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; @@ -487,7 +486,6 @@ static int davinci_musb_exit(struct musb *musb) phy_off(); usb_put_phy(musb->xceiv); - usb_phy_generic_unregister(); return 0; } @@ -545,6 +543,7 @@ static int davinci_probe(struct platform_device *pdev) pdata->platform_ops = &davinci_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -603,6 +602,7 @@ static int davinci_remove(struct platform_device *pdev) struct davinci_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 8d4a819..e1da199 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1065,7 +1065,6 @@ static int tusb_musb_init(struct musb *musb) void __iomem *sync = NULL; int ret; - usb_phy_generic_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) return -EPROBE_DEFER; @@ -1117,7 +1116,6 @@ done: iounmap(sync); usb_put_phy(musb->xceiv); - usb_phy_generic_unregister(); } return ret; } @@ -1133,7 +1131,6 @@ static int tusb_musb_exit(struct musb *musb) iounmap(musb->sync_va); usb_put_phy(musb->xceiv); - usb_phy_generic_unregister(); return 0; } @@ -1176,6 +1173,7 @@ static int tusb_probe(struct platform_device *pdev) pdata->platform_ops = &tusb_ops; + usb_phy_generic_register(); platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -1224,6 +1222,7 @@ static int tusb_remove(struct platform_device *pdev) struct tusb6010_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); + usb_phy_generic_unregister(); kfree(glue); return 0; -- cgit v0.10.2 From 2f36ff6915c6c00df8b9962d9c6c7992befcf8ce Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Apr 2014 16:16:33 -0500 Subject: usb: phy: generic: allow multiples calls to usb_phy_generic_register() it's now very easy to return a platform_device pointer and have the caller pass it as argument when calling usb_phy_generic_unregister(). Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 05459b5..0a34dd8 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -85,6 +85,7 @@ struct am35x_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; struct clk *phy_clk; struct clk *clk; }; @@ -503,7 +504,9 @@ static int am35x_probe(struct platform_device *pdev) pdata->platform_ops = &am35x_ops; - usb_phy_generic_register(); + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) + goto err7; platform_set_drvdata(pdev, glue); pinfo = am35x_dev_info; @@ -517,11 +520,14 @@ static int am35x_probe(struct platform_device *pdev) if (IS_ERR(musb)) { ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err7; + goto err8; } return 0; +err8: + usb_phy_generic_unregister(glue->phy); + err7: clk_disable(clk); @@ -546,7 +552,7 @@ static int am35x_remove(struct platform_device *pdev) struct am35x_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); - usb_phy_generic_unregister(); + usb_phy_generic_unregister(glue->phy); clk_disable(glue->clk); clk_disable(glue->phy_clk); clk_put(glue->clk); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 53acffe..d40d5f0 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -29,6 +29,7 @@ struct bfin_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) @@ -475,7 +476,9 @@ static int bfin_probe(struct platform_device *pdev) pdata->platform_ops = &bfin_ops; - usb_phy_generic_register(); + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) + goto err2; platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -513,6 +516,9 @@ static int bfin_probe(struct platform_device *pdev) return 0; err3: + usb_phy_generic_unregister(glue->phy); + +err2: platform_device_put(musb); err1: @@ -527,7 +533,7 @@ static int bfin_remove(struct platform_device *pdev) struct bfin_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); - usb_phy_generic_unregister(); + usb_phy_generic_unregister(glue->phy); kfree(glue); return 0; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 024751f..058775e 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -85,6 +85,7 @@ struct da8xx_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; struct clk *clk; }; @@ -510,7 +511,11 @@ static int da8xx_probe(struct platform_device *pdev) pdata->platform_ops = &da8xx_ops; - usb_phy_generic_register(); + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) { + ret = PTR_ERR(glue->phy); + goto err5; + } platform_set_drvdata(pdev, glue); memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -537,11 +542,14 @@ static int da8xx_probe(struct platform_device *pdev) if (IS_ERR(musb)) { ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err5; + goto err6; } return 0; +err6: + usb_phy_generic_unregister(glue->phy); + err5: clk_disable(clk); @@ -560,7 +568,7 @@ static int da8xx_remove(struct platform_device *pdev) struct da8xx_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); - usb_phy_generic_unregister(); + usb_phy_generic_unregister(glue->phy); clk_disable(glue->clk); clk_put(glue->clk); kfree(glue); diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index e1da199..f38a8db 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -31,6 +31,7 @@ struct tusb6010_glue { struct device *dev; struct platform_device *musb; + struct platform_device *phy; }; static void tusb_musb_set_vbus(struct musb *musb, int is_on); @@ -1222,7 +1223,7 @@ static int tusb_remove(struct platform_device *pdev) struct tusb6010_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); - usb_phy_generic_unregister(); + usb_phy_generic_unregister(glue->phy); kfree(glue); return 0; diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 2c49cd8..7594e50 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -41,25 +41,16 @@ #include "phy-generic.h" -static struct platform_device *pd; - -void usb_phy_generic_register(void) +struct platform_device *usb_phy_generic_register(void) { - if (pd) - return; - pd = platform_device_register_simple("usb_phy_generic", -1, NULL, 0); - if (IS_ERR(pd)) { - pr_err("Unable to register generic usb transceiver\n"); - pd = NULL; - return; - } + return platform_device_register_simple("usb_phy_generic", + PLATFORM_DEVID_AUTO, NULL, 0); } EXPORT_SYMBOL_GPL(usb_phy_generic_register); -void usb_phy_generic_unregister(void) +void usb_phy_generic_unregister(struct platform_device *pdev) { - platform_device_unregister(pd); - pd = NULL; + platform_device_unregister(pdev); } EXPORT_SYMBOL_GPL(usb_phy_generic_unregister); diff --git a/include/linux/usb/usb_phy_generic.h b/include/linux/usb/usb_phy_generic.h index c00176d..8346bcc 100644 --- a/include/linux/usb/usb_phy_generic.h +++ b/include/linux/usb/usb_phy_generic.h @@ -15,14 +15,15 @@ struct usb_phy_generic_platform_data { #if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) /* sometimes transceivers are accessed only through e.g. ULPI */ -extern void usb_phy_generic_register(void); -extern void usb_phy_generic_unregister(void); +extern struct platform_device *usb_phy_generic_register(void); +extern void usb_phy_generic_unregister(struct platform_device *); #else -static inline void usb_phy_generic_register(void) +static inline struct platform_device *usb_phy_generic_register(void) { + return NULL; } -static inline void usb_phy_generic_unregister(void) +static inline void usb_phy_generic_unregister(struct platform_device *pdev) { } #endif -- cgit v0.10.2 From dca769bd5a76e9e634cc36987760306846153cac Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 21 Apr 2014 10:50:35 -0500 Subject: usb: phy: generic: switch over to IS_ENABLED() when checking if our generic PHY is enabled, it's a lot easier to use IS_ENABLED() instead of manually checking for it. While at that, also remove the bogus defined(MODULE) at the end of the line. Signed-off-by: Felipe Balbi diff --git a/include/linux/usb/usb_phy_generic.h b/include/linux/usb/usb_phy_generic.h index 8346bcc..68adae8 100644 --- a/include/linux/usb/usb_phy_generic.h +++ b/include/linux/usb/usb_phy_generic.h @@ -13,7 +13,7 @@ struct usb_phy_generic_platform_data { int gpio_reset; }; -#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_NOP_USB_XCEIV) /* sometimes transceivers are accessed only through e.g. ULPI */ extern struct platform_device *usb_phy_generic_register(void); extern void usb_phy_generic_unregister(struct platform_device *); -- cgit v0.10.2 From 22876266de43ec24ae93f635490c40edabaf8278 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 27 Mar 2014 16:15:53 +0100 Subject: usb: gadget: gr_udc: improve platform_device variable name Rename struct platform_device pointers from ofdev to pdev for clarity, while at that, also use platform_set/get_drvdata() helpers. Suggested-by: Mark Rutland Signed-off-by: Andreas Larsson Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index f984ee7..ae5bebe 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -2065,9 +2065,9 @@ static int gr_udc_init(struct gr_udc *dev) return 0; } -static int gr_remove(struct platform_device *ofdev) +static int gr_remove(struct platform_device *pdev) { - struct gr_udc *dev = dev_get_drvdata(&ofdev->dev); + struct gr_udc *dev = platform_get_drvdata(pdev); if (dev->added) usb_del_gadget_udc(&dev->gadget); /* Shuts everything down */ @@ -2077,7 +2077,7 @@ static int gr_remove(struct platform_device *ofdev) gr_dfs_delete(dev); if (dev->desc_pool) dma_pool_destroy(dev->desc_pool); - dev_set_drvdata(&ofdev->dev, NULL); + platform_set_drvdata(pdev, NULL); gr_free_request(&dev->epi[0].ep, &dev->ep0reqi->req); gr_free_request(&dev->epo[0].ep, &dev->ep0reqo->req); @@ -2090,7 +2090,7 @@ static int gr_request_irq(struct gr_udc *dev, int irq) IRQF_SHARED, driver_name, dev); } -static int gr_probe(struct platform_device *ofdev) +static int gr_probe(struct platform_device *pdev) { struct gr_udc *dev; struct resource *res; @@ -2098,12 +2098,12 @@ static int gr_probe(struct platform_device *ofdev) int retval; u32 status; - dev = devm_kzalloc(&ofdev->dev, sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - dev->dev = &ofdev->dev; + dev->dev = &pdev->dev; - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev->dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); @@ -2132,7 +2132,7 @@ static int gr_probe(struct platform_device *ofdev) spin_lock_init(&dev->lock); dev->regs = regs; - dev_set_drvdata(&ofdev->dev, dev); + platform_set_drvdata(pdev, dev); /* Determine number of endpoints and data interface mode */ status = gr_read32(&dev->regs->status); @@ -2204,7 +2204,7 @@ out: spin_unlock(&dev->lock); if (retval) - gr_remove(ofdev); + gr_remove(pdev); return retval; } -- cgit v0.10.2 From d9a6ef1bb27e589ec40f792f3e742c3f54cbdb28 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 27 Mar 2014 16:15:54 +0100 Subject: usb: gadget: gr_udc: Expand devicetree documentation Provide more information on the two different interrupt cases and more information of endpoint buffer sizes. Suggested by Mark Rutland. Signed-off-by: Andreas Larsson Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/gr-udc.txt b/Documentation/devicetree/bindings/usb/gr-udc.txt index 0c5118f..e944522 100644 --- a/Documentation/devicetree/bindings/usb/gr-udc.txt +++ b/Documentation/devicetree/bindings/usb/gr-udc.txt @@ -12,17 +12,23 @@ Required properties: - reg : Address and length of the register set for the device -- interrupts : Interrupt numbers for this device +- interrupts : Interrupt numbers for this device. Either one interrupt number + for all interrupts, or one for status related interrupts, one for IN + endpoint related interrupts and one for OUT endpoint related interrupts. Optional properties: -- epobufsizes : An array of buffer sizes for OUT endpoints. If the property is - not present, or for endpoints outside of the array, 1024 is assumed by - the driver. - -- epibufsizes : An array of buffer sizes for IN endpoints. If the property is - not present, or for endpoints outside of the array, 1024 is assumed by - the driver. +- epobufsizes : Array of buffer sizes for OUT endpoints when they differ + from the default size of 1024. The array is indexed by the OUT endpoint + number. If the property is present it typically contains one entry for + each OUT endpoint of the core. Fewer entries overrides the default sizes + only for as many endpoints as the array contains. + +- epibufsizes : Array of buffer sizes for IN endpoints when they differ + from the default size of 1024. The array is indexed by the IN endpoint + number. If the property is present it typically contains one entry for + each IN endpoint of the core. Fewer entries overrides the default sizes + only for as many endpoints as the array contains. For further information look in the documentation for the GLIB IP core library: http://www.gaisler.com/products/grlib/grip.pdf -- cgit v0.10.2 From 196800da39a142e2952ad5e1cb58a84838956764 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 27 Mar 2014 16:15:55 +0100 Subject: usb: gadget: gr_udc: Use platform_get_irq instead of irq_of_parse_and_map Use platform_get_irq as no mapping needs to be done. No functional difference for SPARC which is the typical environment for the driver though. Suggested by Mark Rutland. Signed-off-by: Andreas Larsson Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index ae5bebe..7a99254 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -2108,20 +2108,22 @@ static int gr_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); - dev->irq = irq_of_parse_and_map(dev->dev->of_node, 0); - if (!dev->irq) { + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq <= 0) { dev_err(dev->dev, "No irq found\n"); return -ENODEV; } /* Some core configurations has separate irqs for IN and OUT events */ - dev->irqi = irq_of_parse_and_map(dev->dev->of_node, 1); - if (dev->irqi) { - dev->irqo = irq_of_parse_and_map(dev->dev->of_node, 2); - if (!dev->irqo) { + dev->irqi = platform_get_irq(pdev, 1); + if (dev->irqi > 0) { + dev->irqo = platform_get_irq(pdev, 2); + if (dev->irqo <= 0) { dev_err(dev->dev, "Found irqi but not irqo\n"); return -ENODEV; } + } else { + dev->irqi = 0; } dev->gadget.name = driver_name; -- cgit v0.10.2 From 73e1c093e83a421d24d54a94cb87031e7c222cd1 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 27 Mar 2014 16:15:56 +0100 Subject: usb: gadget: gr_udc: Use of_property_read_u32_index to access arrays Use an appropriate accessor function for property arrays to make the code nicer and make the code correct if it would ever run on little endian architectures. Suggested by Mark Rutland. Signed-off-by: Andreas Larsson Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index 7a99254..0f3a953 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -2020,9 +2020,7 @@ static int gr_udc_init(struct gr_udc *dev) u32 dmactrl_val; int i; int ret = 0; - u32 *bufsizes; u32 bufsize; - int len; gr_set_address(dev, 0); @@ -2033,19 +2031,17 @@ static int gr_udc_init(struct gr_udc *dev) INIT_LIST_HEAD(&dev->ep_list); gr_set_ep0state(dev, GR_EP0_DISCONNECT); - bufsizes = (u32 *)of_get_property(np, "epobufsizes", &len); - len /= sizeof(u32); for (i = 0; i < dev->nepo; i++) { - bufsize = (bufsizes && i < len) ? bufsizes[i] : 1024; + if (of_property_read_u32_index(np, "epobufsizes", i, &bufsize)) + bufsize = 1024; ret = gr_ep_init(dev, i, 0, bufsize); if (ret) return ret; } - bufsizes = (u32 *)of_get_property(np, "epibufsizes", &len); - len /= sizeof(u32); for (i = 0; i < dev->nepi; i++) { - bufsize = (bufsizes && i < len) ? bufsizes[i] : 1024; + if (of_property_read_u32_index(np, "epibufsizes", i, &bufsize)) + bufsize = 1024; ret = gr_ep_init(dev, i, 1, bufsize); if (ret) return ret; -- cgit v0.10.2 From 5bddbd72c6c02498aba8b48527c86d1398dba3f4 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 27 Mar 2014 16:15:57 +0100 Subject: usb: gadget: gr_udc: Add ep.maxpacket_limit to debugfs information Add information on ep.maxpacket_limit for each endpoint in the debugfs information. Signed-off-by: Andreas Larsson Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index 0f3a953..253e608 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -143,6 +143,7 @@ static void gr_seq_ep_show(struct seq_file *seq, struct gr_ep *ep) seq_printf(seq, " wedged = %d\n", ep->wedged); seq_printf(seq, " callback = %d\n", ep->callback); seq_printf(seq, " maxpacket = %d\n", ep->ep.maxpacket); + seq_printf(seq, " maxpacket_limit = %d\n", ep->ep.maxpacket_limit); seq_printf(seq, " bytes_per_buffer = %d\n", ep->bytes_per_buffer); if (mode == 1 || mode == 3) seq_printf(seq, " nt = %d\n", -- cgit v0.10.2 From b38d27e5527c33a2a1f5bb3aee39b755e57dea86 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 27 Mar 2014 16:15:58 +0100 Subject: usb: gadget: gr_udc: Return error code when trying to set ep.maxpacket > ep.maxpacket_limit Make gr_ep_enable fail properly when a call requests a larger ep.maxpacket than ep.maxpacket_limit. Signed-off-by: Andreas Larsson Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index 253e608..72458be 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -1542,6 +1542,10 @@ static int gr_ep_enable(struct usb_ep *_ep, } else if (max == 0) { dev_err(dev->dev, "Max payload cannot be set to 0\n"); return -EINVAL; + } else if (max > ep->ep.maxpacket_limit) { + dev_err(dev->dev, "Requested max payload %d > limit %d\n", + max, ep->ep.maxpacket_limit); + return -EINVAL; } spin_lock(&ep->dev->lock); -- cgit v0.10.2 From 8652bcbfa09ca5ba24423c7c45c28b7d8771e0a8 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Tue, 1 Apr 2014 12:15:17 +0200 Subject: usb: gadget: gr_udc: Use GFP_ATOMIC when allocating under held spinlock As gr_ep_init must be called with dev->lock held, GFP_KERNEL must not be used. Reported-by: Dan Carpenter Signed-off-by: Andreas Larsson Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index 72458be..4966971 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -1990,8 +1990,8 @@ static int gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit) INIT_LIST_HEAD(&ep->queue); if (num == 0) { - _req = gr_alloc_request(&ep->ep, GFP_KERNEL); - buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_KERNEL); + _req = gr_alloc_request(&ep->ep, GFP_ATOMIC); + buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_ATOMIC); if (!_req || !buf) { /* possible _req freed by gr_probe via gr_remove */ return -ENOMEM; -- cgit v0.10.2 From 1e42d20c88f2f56c0d81363d7b0f1d3762037f53 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 2 Apr 2014 13:58:27 +0200 Subject: usb: musb: add reset hook to platform ops Babble interrupts require us to reset the DSPS glue layer. In order to handle all other recovery tasks independently, add a new hook for platform-specific implementations of the actual reset. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 7083e82..5514e4c 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -192,6 +192,7 @@ struct musb_platform_ops { int (*set_mode)(struct musb *musb, u8 mode); void (*try_idle)(struct musb *musb, unsigned long timeout); + void (*reset)(struct musb *musb); int (*vbus_status)(struct musb *musb); void (*set_vbus)(struct musb *musb, int on); @@ -552,6 +553,12 @@ static inline void musb_platform_try_idle(struct musb *musb, musb->ops->try_idle(musb, timeout); } +static inline void musb_platform_reset(struct musb *musb) +{ + if (musb->ops->reset) + musb->ops->reset(musb); +} + static inline int musb_platform_get_vbus_status(struct musb *musb) { if (!musb->ops->vbus_status) -- cgit v0.10.2 From ca88fc2ef0d790a1da37804219102336f7622b97 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 2 Apr 2014 13:58:28 +0200 Subject: usb: musb: add a work_struct to recover from babble errors Handle BABBLE interrupt error conditions from a work struct handler. This indirection is necessary as we can't be certain that the phy functions don't sleep. Platform layer implementation may pass a babble error down to the core in order to handle it. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 0757690..61da471 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -848,6 +848,10 @@ b_host: } } + /* handle babble condition */ + if (int_usb & MUSB_INTR_BABBLE) + schedule_work(&musb->recover_work); + #if 0 /* REVISIT ... this would be for multiplexing periodic endpoints, or * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -1746,6 +1750,34 @@ static void musb_irq_work(struct work_struct *data) } } +/* Recover from babble interrupt conditions */ +static void musb_recover_work(struct work_struct *data) +{ + struct musb *musb = container_of(data, struct musb, recover_work); + int status; + + musb_platform_reset(musb); + + usb_phy_vbus_off(musb->xceiv); + udelay(100); + + usb_phy_vbus_on(musb->xceiv); + udelay(100); + + /* + * When a babble condition occurs, the musb controller removes the + * session bit and the endpoint config is lost. + */ + if (musb->dyn_fifo) + status = ep_config_from_table(musb); + else + status = ep_config_from_hw(musb); + + /* start the session again */ + if (status == 0) + musb_start(musb); +} + /* -------------------------------------------------------------------------- * Init support */ @@ -1913,6 +1945,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* Init IRQ workqueue before request_irq */ INIT_WORK(&musb->irq_work, musb_irq_work); + INIT_WORK(&musb->recover_work, musb_recover_work); INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); @@ -2008,6 +2041,7 @@ fail4: fail3: cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); if (musb->dma_controller) @@ -2073,6 +2107,7 @@ static int musb_remove(struct platform_device *pdev) dma_controller_destroy(musb->dma_controller); cancel_work_sync(&musb->irq_work); + cancel_work_sync(&musb->recover_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); musb_free(musb); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 5514e4c..47e8874 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -297,6 +297,7 @@ struct musb { irqreturn_t (*isr)(int, void *); struct work_struct irq_work; + struct work_struct recover_work; struct delayed_work deassert_reset_work; struct delayed_work finish_resume_work; u16 hwvers; -- cgit v0.10.2 From 1d57de306e1f3e73c607811a974f6662162e5df6 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 2 Apr 2014 13:58:29 +0200 Subject: usb: musb: dsps: handle babble interrupts When the dsps isr sees a babble error, pass it down to the core for fixup. Also, provide a .reset hook so the core can call us back. A babble interrupt error occured when a USB mass storage device ("CHIPSBNK v3.3.9.1", 1e3d:2093) was disconnected from a AM33xx host. Signed-off-by: Daniel Mack Reported-by: Thomas Mellenthin Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 1888292..138d1dd 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -329,9 +329,21 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * Also, DRVVBUS pulses for SRP (but not at 5V) ... */ - if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) + if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) { pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); + /* + * When a babble condition occurs, the musb controller removes + * the session and is no longer in host mode. Hence, all + * devices connected to its root hub get disconnected. + * + * Hand this error down to the musb core isr, so it can + * recover. + */ + musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; + musb->int_tx = musb->int_rx = 0; + } + if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { int drvvbus = dsps_readl(reg_base, wrp->status); void __iomem *mregs = musb->mregs; @@ -523,6 +535,16 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) return 0; } +static void dsps_musb_reset(struct musb *musb) +{ + struct device *dev = musb->controller; + struct dsps_glue *glue = dev_get_drvdata(dev->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; + + dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); + udelay(100); +} + static struct musb_platform_ops dsps_ops = { .init = dsps_musb_init, .exit = dsps_musb_exit, @@ -532,6 +554,7 @@ static struct musb_platform_ops dsps_ops = { .try_idle = dsps_musb_try_idle, .set_mode = dsps_musb_set_mode, + .reset = dsps_musb_reset, }; static u64 musb_dmamask = DMA_BIT_MASK(32); -- cgit v0.10.2 From aea8928aba7d7ee2e6245d44ba7de4c04fc90559 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 8 Apr 2014 10:42:40 +0200 Subject: usb: dwc3: add glue layer dependencies Glue layers for the DWC3 driver only make sense on specific platforms. Add dependencies so that they are not built where they aren't needed. Cc: Greg Kroah-Hartman Cc: WingMan Kwok Signed-off-by: Jean Delvare Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index e2c730f..8eb996e 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -44,7 +44,7 @@ comment "Platform Glue Driver Support" config USB_DWC3_OMAP tristate "Texas Instruments OMAP5 and similar Platforms" - depends on EXTCON + depends on EXTCON && (ARCH_OMAP2PLUS || COMPILE_TEST) default USB_DWC3 help Some platforms from Texas Instruments like OMAP5, DRA7xxx and @@ -54,6 +54,7 @@ config USB_DWC3_OMAP config USB_DWC3_EXYNOS tristate "Samsung Exynos Platform" + depends on ARCH_EXYNOS || COMPILE_TEST default USB_DWC3 help Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, @@ -72,6 +73,7 @@ config USB_DWC3_PCI config USB_DWC3_KEYSTONE tristate "Texas Instruments Keystone2 Platforms" + depends on ARCH_KEYSTONE || COMPILE_TEST default USB_DWC3 help Support of USB2/3 functionality in TI Keystone2 platforms. -- cgit v0.10.2 From 9f58fa4c919e1a33e3844f6851735ec9f724bf52 Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Fri, 11 Apr 2014 18:05:13 +0800 Subject: usb: gadget: f_subset: replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is deprecated. Do not recommend its usage anymore. Use PTR_ERR_OR_ZERO instead. Signed-off-by: Duan Jiong Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index df4a0dcb..1ea8baf 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -276,7 +276,7 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } net = gether_connect(&geth->port); - return PTR_RET(net); + return PTR_ERR_OR_ZERO(net); } static void geth_disable(struct usb_function *f) -- cgit v0.10.2 From 5b7839836109a802b144a05cfbd4f57e6564d8e5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 17 Apr 2014 10:20:32 +0200 Subject: usb: musb: dsps: compile suspend/resume only with PM_SLEEP Depending on PM is not enough, because only PM_RUNTIME could be selected. Fixes: drivers/usb/musb/musb_dsps.c:703:12: warning: 'dsps_suspend' defined but not used [-Wunused-function] drivers/usb/musb/musb_dsps.c:721:12: warning: 'dsps_resume' defined but not used [-Wunused-function] Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 138d1dd..9d9acaa 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -774,7 +774,7 @@ static const struct of_device_id musb_dsps_of_match[] = { }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int dsps_suspend(struct device *dev) { struct dsps_glue *glue = dev_get_drvdata(dev); -- cgit v0.10.2 From bd8ce544ec35ff362489a7e3c059cf496c06c68e Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Mon, 21 Apr 2014 17:46:44 +0530 Subject: usb: dwc3: exynos: Make provision for vdd regulators Facilitate getting required 3.3V and 1.0V VDD supply for DWC3 controller on Exynos. With patches for regulators' nodes merged in 3.15: c8c253f ARM: dts: Add regulator entries to smdk5420 275dcd2 ARM: dts: add max77686 pmic node for smdk5250, certain perripherals will now need to ensure that, they request VDD regulators in their drivers, and enable them so as to make them working. Signed-off-by: Vivek Gautam Cc: Anton Tikhomirov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index ed22d72..0ed8583 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -27,6 +27,7 @@ #include #include #include +#include struct dwc3_exynos { struct platform_device *usb2_phy; @@ -34,6 +35,8 @@ struct dwc3_exynos { struct device *dev; struct clk *clk; + struct regulator *vdd33; + struct regulator *vdd10; }; static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) @@ -144,20 +147,46 @@ static int dwc3_exynos_probe(struct platform_device *pdev) clk_prepare_enable(exynos->clk); + exynos->vdd33 = devm_regulator_get(dev, "vdd33"); + if (IS_ERR(exynos->vdd33)) { + ret = PTR_ERR(exynos->vdd33); + goto err2; + } + ret = regulator_enable(exynos->vdd33); + if (ret) { + dev_err(dev, "Failed to enable VDD33 supply\n"); + goto err2; + } + + exynos->vdd10 = devm_regulator_get(dev, "vdd10"); + if (IS_ERR(exynos->vdd10)) { + ret = PTR_ERR(exynos->vdd10); + goto err3; + } + ret = regulator_enable(exynos->vdd10); + if (ret) { + dev_err(dev, "Failed to enable VDD10 supply\n"); + goto err3; + } + if (node) { ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { dev_err(dev, "failed to add dwc3 core\n"); - goto err2; + goto err4; } } else { dev_err(dev, "no device node, failed to add dwc3 core\n"); ret = -ENODEV; - goto err2; + goto err4; } return 0; +err4: + regulator_disable(exynos->vdd10); +err3: + regulator_disable(exynos->vdd33); err2: clk_disable_unprepare(clk); err1: @@ -174,6 +203,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev) clk_disable_unprepare(exynos->clk); + regulator_disable(exynos->vdd33); + regulator_disable(exynos->vdd10); + return 0; } @@ -192,12 +224,27 @@ static int dwc3_exynos_suspend(struct device *dev) clk_disable(exynos->clk); + regulator_disable(exynos->vdd33); + regulator_disable(exynos->vdd10); + return 0; } static int dwc3_exynos_resume(struct device *dev) { struct dwc3_exynos *exynos = dev_get_drvdata(dev); + int ret; + + ret = regulator_enable(exynos->vdd33); + if (ret) { + dev_err(dev, "Failed to enable VDD33 supply\n"); + return ret; + } + ret = regulator_enable(exynos->vdd10); + if (ret) { + dev_err(dev, "Failed to enable VDD10 supply\n"); + return ret; + } clk_enable(exynos->clk); -- cgit v0.10.2 From 40cc57c71b27998c558d4ea23556cad2baef8a56 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 25 Apr 2014 14:10:02 -0500 Subject: usb: dwc3: gadget: print both cmd string and number That way it's easy for humans looking at dmesg and humans(?) looking at Databooks. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f0dc0ee..f5adf3f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -336,9 +336,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, u32 timeout = 500; u32 reg; - dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n", + dev_vdbg(dwc->dev, "%s: cmd '%s' [%d] params %08x %08x %08x\n", dep->name, - dwc3_gadget_ep_cmd_string(cmd), params->param0, + dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0, params->param1, params->param2); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); -- cgit v0.10.2 From e57ebc1db6ef796124b69abca044a373b9110a47 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 22 Apr 2014 13:20:12 -0500 Subject: usb: dwc3: gadget: pretty print link states this makes it slightly easier to read link state change interrupt logs. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f5adf3f..9a8ae39 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -302,6 +302,42 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) } } +static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state) +{ + switch (link_state) { + case DWC3_LINK_STATE_U0: + return "U0"; + case DWC3_LINK_STATE_U1: + return "U1"; + case DWC3_LINK_STATE_U2: + return "U2"; + case DWC3_LINK_STATE_U3: + return "U3"; + case DWC3_LINK_STATE_SS_DIS: + return "SS.Disabled"; + case DWC3_LINK_STATE_RX_DET: + return "RX.Detect"; + case DWC3_LINK_STATE_SS_INACT: + return "SS.Inactive"; + case DWC3_LINK_STATE_POLL: + return "Polling"; + case DWC3_LINK_STATE_RECOV: + return "Recovery"; + case DWC3_LINK_STATE_HRESET: + return "Hot Reset"; + case DWC3_LINK_STATE_CMPLY: + return "Compliance"; + case DWC3_LINK_STATE_LPBK: + return "Loopback"; + case DWC3_LINK_STATE_RESET: + return "Reset"; + case DWC3_LINK_STATE_RESUME: + return "Resume"; + default: + return "UNKNOWN link state\n"; + } +} + int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { u32 timeout = 500; @@ -2449,8 +2485,6 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, } } - dwc->link_state = next; - switch (next) { case DWC3_LINK_STATE_U1: if (dwc->speed == USB_SPEED_SUPER) @@ -2468,7 +2502,11 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, break; } - dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); + dev_vdbg(dwc->dev, "link change: %s [%d] -> %s [%d]\n", + dwc3_gadget_link_string(dwc->link_state), + dwc->link_state, dwc3_gadget_link_string(next), next); + + dwc->link_state = next; } static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, -- cgit v0.10.2 From 427c3df684ab97379b529188d505cc99c2a1429d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 25 Apr 2014 14:14:14 -0500 Subject: usb: dwc3: gadget: pretty print Generic CMDs this makes it slightly easier to read generic CMD logs. It also helps make sure we're sending proper parameters for each command. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9a8ae39..e0b7910 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -302,6 +302,32 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) } } +static const char *dwc3_gadget_generic_cmd_string(u8 cmd) +{ + switch (cmd) { + case DWC3_DGCMD_SET_LMP: + return "Set LMP"; + case DWC3_DGCMD_SET_PERIODIC_PAR: + return "Set Periodic Parameters"; + case DWC3_DGCMD_XMIT_FUNCTION: + return "Transmit Function Wake Device Notification"; + case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO: + return "Set Scratchpad Buffer Array Address Lo"; + case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI: + return "Set Scratchpad Buffer Array Address Hi"; + case DWC3_DGCMD_SELECTED_FIFO_FLUSH: + return "Selected FIFO Flush"; + case DWC3_DGCMD_ALL_FIFO_FLUSH: + return "All FIFO Flush"; + case DWC3_DGCMD_SET_ENDPOINT_NRDY: + return "Set Endpoint NRDY"; + case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: + return "Run SoC Bus Loopback Test"; + default: + return "UNKNOWN"; + } +} + static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state) { switch (link_state) { @@ -343,6 +369,9 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) u32 timeout = 500; u32 reg; + dev_vdbg(dwc->dev, "generic cmd '%s' [%d] param %08x\n", + dwc3_gadget_generic_cmd_string(cmd), cmd, param); + dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); -- cgit v0.10.2 From 0d092fdb8c7a1b874d5c1b56f14d97b62df13186 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:04 +0300 Subject: usb: phy: msm: Make driver selectable on ARCH_QCOM Controller could be found on APQ and MSM platforms, make configuration description more generic. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 416e0c8..0c668a3 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -171,11 +171,11 @@ config USB_ISP1301 module will be called phy-isp1301. config USB_MSM_OTG - tristate "OTG support for Qualcomm on-chip USB controller" - depends on (USB || USB_GADGET) && ARCH_MSM + tristate "Qualcomm on-chip USB OTG controller support" + depends on (USB || USB_GADGET) && (ARCH_MSM || ARCH_QCOM) select USB_PHY help - Enable this to support the USB OTG transceiver on MSM chips. It + Enable this to support the USB OTG transceiver on Qualcomm chips. It handles PHY initialization, clock management, and workarounds required after resetting the hardware and power management. This driver is required even for peripheral only or host only -- cgit v0.10.2 From 37cfdaf782590e277d9352626dba4496734e0375 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:06 +0300 Subject: usb: phy: msm: Move global regulators variables to driver state Eliminating global variables allows driver to handle multiple device instances. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 5b37b81..878f67d 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -58,47 +58,43 @@ #define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */ #define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */ -static struct regulator *hsusb_3p3; -static struct regulator *hsusb_1p8; -static struct regulator *hsusb_vddcx; - static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) { int ret = 0; if (init) { - hsusb_vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX"); - if (IS_ERR(hsusb_vddcx)) { + motg->vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX"); + if (IS_ERR(motg->vddcx)) { dev_err(motg->phy.dev, "unable to get hsusb vddcx\n"); - return PTR_ERR(hsusb_vddcx); + return PTR_ERR(motg->vddcx); } - ret = regulator_set_voltage(hsusb_vddcx, + ret = regulator_set_voltage(motg->vddcx, USB_PHY_VDD_DIG_VOL_MIN, USB_PHY_VDD_DIG_VOL_MAX); if (ret) { dev_err(motg->phy.dev, "unable to set the voltage " "for hsusb vddcx\n"); - regulator_put(hsusb_vddcx); + regulator_put(motg->vddcx); return ret; } - ret = regulator_enable(hsusb_vddcx); + ret = regulator_enable(motg->vddcx); if (ret) { dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n"); - regulator_put(hsusb_vddcx); + regulator_put(motg->vddcx); } } else { - ret = regulator_set_voltage(hsusb_vddcx, 0, + ret = regulator_set_voltage(motg->vddcx, 0, USB_PHY_VDD_DIG_VOL_MAX); if (ret) dev_err(motg->phy.dev, "unable to set the voltage " "for hsusb vddcx\n"); - ret = regulator_disable(hsusb_vddcx); + ret = regulator_disable(motg->vddcx); if (ret) dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n"); - regulator_put(hsusb_vddcx); + regulator_put(motg->vddcx); } return ret; @@ -109,38 +105,38 @@ static int msm_hsusb_ldo_init(struct msm_otg *motg, int init) int rc = 0; if (init) { - hsusb_3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3"); - if (IS_ERR(hsusb_3p3)) { + motg->v3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3"); + if (IS_ERR(motg->v3p3)) { dev_err(motg->phy.dev, "unable to get hsusb 3p3\n"); - return PTR_ERR(hsusb_3p3); + return PTR_ERR(motg->v3p3); } - rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN, + rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN, USB_PHY_3P3_VOL_MAX); if (rc) { dev_err(motg->phy.dev, "unable to set voltage level " "for hsusb 3p3\n"); goto put_3p3; } - rc = regulator_enable(hsusb_3p3); + rc = regulator_enable(motg->v3p3); if (rc) { dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n"); goto put_3p3; } - hsusb_1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8"); - if (IS_ERR(hsusb_1p8)) { + motg->v1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8"); + if (IS_ERR(motg->v1p8)) { dev_err(motg->phy.dev, "unable to get hsusb 1p8\n"); - rc = PTR_ERR(hsusb_1p8); + rc = PTR_ERR(motg->v1p8); goto disable_3p3; } - rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN, + rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN, USB_PHY_1P8_VOL_MAX); if (rc) { dev_err(motg->phy.dev, "unable to set voltage level " "for hsusb 1p8\n"); goto put_1p8; } - rc = regulator_enable(hsusb_1p8); + rc = regulator_enable(motg->v1p8); if (rc) { dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n"); goto put_1p8; @@ -149,54 +145,54 @@ static int msm_hsusb_ldo_init(struct msm_otg *motg, int init) return 0; } - regulator_disable(hsusb_1p8); + regulator_disable(motg->v1p8); put_1p8: - regulator_put(hsusb_1p8); + regulator_put(motg->v1p8); disable_3p3: - regulator_disable(hsusb_3p3); + regulator_disable(motg->v3p3); put_3p3: - regulator_put(hsusb_3p3); + regulator_put(motg->v3p3); return rc; } -static int msm_hsusb_ldo_set_mode(int on) +static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on) { int ret = 0; - if (!hsusb_1p8 || IS_ERR(hsusb_1p8)) { + if (!motg->v1p8 || IS_ERR(motg->v1p8)) { pr_err("%s: HSUSB_1p8 is not initialized\n", __func__); return -ENODEV; } - if (!hsusb_3p3 || IS_ERR(hsusb_3p3)) { + if (!motg->v3p3 || IS_ERR(motg->v3p3)) { pr_err("%s: HSUSB_3p3 is not initialized\n", __func__); return -ENODEV; } if (on) { - ret = regulator_set_optimum_mode(hsusb_1p8, + ret = regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_HPM_LOAD); if (ret < 0) { pr_err("%s: Unable to set HPM of the regulator " "HSUSB_1p8\n", __func__); return ret; } - ret = regulator_set_optimum_mode(hsusb_3p3, + ret = regulator_set_optimum_mode(motg->v3p3, USB_PHY_3P3_HPM_LOAD); if (ret < 0) { pr_err("%s: Unable to set HPM of the regulator " "HSUSB_3p3\n", __func__); - regulator_set_optimum_mode(hsusb_1p8, + regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_LPM_LOAD); return ret; } } else { - ret = regulator_set_optimum_mode(hsusb_1p8, + ret = regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_LPM_LOAD); if (ret < 0) pr_err("%s: Unable to set LPM of the regulator " "HSUSB_1p8\n", __func__); - ret = regulator_set_optimum_mode(hsusb_3p3, + ret = regulator_set_optimum_mode(motg->v3p3, USB_PHY_3P3_LPM_LOAD); if (ret < 0) pr_err("%s: Unable to set LPM of the regulator " @@ -417,7 +413,7 @@ static int msm_otg_reset(struct usb_phy *phy) #ifdef CONFIG_PM #define USB_PHY_SUSP_DIG_VOL 500000 -static int msm_hsusb_config_vddcx(int high) +static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high) { int max_vol = USB_PHY_VDD_DIG_VOL_MAX; int min_vol; @@ -428,7 +424,7 @@ static int msm_hsusb_config_vddcx(int high) else min_vol = USB_PHY_SUSP_DIG_VOL; - ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol); + ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol); if (ret) { pr_err("%s: unable to set the voltage for regulator " "HSUSB_VDDCX\n", __func__); @@ -518,8 +514,8 @@ static int msm_otg_suspend(struct msm_otg *motg) if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) { - msm_hsusb_ldo_set_mode(0); - msm_hsusb_config_vddcx(0); + msm_hsusb_ldo_set_mode(motg, 0); + msm_hsusb_config_vddcx(motg, 0); } if (device_may_wakeup(phy->dev)) @@ -555,8 +551,8 @@ static int msm_otg_resume(struct msm_otg *motg) if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) { - msm_hsusb_ldo_set_mode(1); - msm_hsusb_config_vddcx(1); + msm_hsusb_ldo_set_mode(motg, 1); + msm_hsusb_config_vddcx(motg, 1); writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL); } @@ -1521,7 +1517,7 @@ static int __init msm_otg_probe(struct platform_device *pdev) dev_err(&pdev->dev, "hsusb vreg configuration failed\n"); goto vddcx_exit; } - ret = msm_hsusb_ldo_set_mode(1); + ret = msm_hsusb_ldo_set_mode(motg, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg enable failed\n"); goto ldo_exit; diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 3275483..8705b01 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -183,6 +183,9 @@ struct msm_otg { enum usb_chg_state chg_state; enum usb_chg_type chg_type; u8 dcd_retries; + struct regulator *v3p3; + struct regulator *v1p8; + struct regulator *vddcx; }; #endif -- cgit v0.10.2 From 06a6ec445bfa539285a7f6ae3e6e447a536d5a35 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:07 +0300 Subject: usb: phy: msm: Enable deferred driver probing Using platform_driver_probe() prevent driver from requesting probe deferral. Fix this. While at that, also switch to module_platform_driver() and remove __init annotation from probe(). Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 878f67d..b7d73f2 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1402,7 +1402,7 @@ static void msm_otg_debugfs_cleanup(void) debugfs_remove(msm_otg_dbg_root); } -static int __init msm_otg_probe(struct platform_device *pdev) +static int msm_otg_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; @@ -1736,6 +1736,7 @@ static const struct dev_pm_ops msm_otg_dev_pm_ops = { }; static struct platform_driver msm_otg_driver = { + .probe = msm_otg_probe, .remove = msm_otg_remove, .driver = { .name = DRIVER_NAME, @@ -1744,7 +1745,7 @@ static struct platform_driver msm_otg_driver = { }, }; -module_platform_driver_probe(msm_otg_driver, msm_otg_probe); +module_platform_driver(msm_otg_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MSM USB transceiver driver"); -- cgit v0.10.2 From 6b99c68ec1f979ef6ea956516a87afa9bb5551ca Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:08 +0300 Subject: usb: phy: msm: Migrate to Managed Device Resource allocation Move memory, regulators, clocks and irq allocation to devm_* variants. Properly check for valid clk handles. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index b7d73f2..67705fc 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -63,27 +63,18 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) int ret = 0; if (init) { - motg->vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX"); - if (IS_ERR(motg->vddcx)) { - dev_err(motg->phy.dev, "unable to get hsusb vddcx\n"); - return PTR_ERR(motg->vddcx); - } - ret = regulator_set_voltage(motg->vddcx, USB_PHY_VDD_DIG_VOL_MIN, USB_PHY_VDD_DIG_VOL_MAX); if (ret) { dev_err(motg->phy.dev, "unable to set the voltage " "for hsusb vddcx\n"); - regulator_put(motg->vddcx); return ret; } ret = regulator_enable(motg->vddcx); - if (ret) { + if (ret) dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n"); - regulator_put(motg->vddcx); - } } else { ret = regulator_set_voltage(motg->vddcx, 0, USB_PHY_VDD_DIG_VOL_MAX); @@ -93,8 +84,6 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) ret = regulator_disable(motg->vddcx); if (ret) dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n"); - - regulator_put(motg->vddcx); } return ret; @@ -105,53 +94,38 @@ static int msm_hsusb_ldo_init(struct msm_otg *motg, int init) int rc = 0; if (init) { - motg->v3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3"); - if (IS_ERR(motg->v3p3)) { - dev_err(motg->phy.dev, "unable to get hsusb 3p3\n"); - return PTR_ERR(motg->v3p3); - } - rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN, USB_PHY_3P3_VOL_MAX); if (rc) { dev_err(motg->phy.dev, "unable to set voltage level " "for hsusb 3p3\n"); - goto put_3p3; + goto exit; } rc = regulator_enable(motg->v3p3); if (rc) { dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n"); - goto put_3p3; - } - motg->v1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8"); - if (IS_ERR(motg->v1p8)) { - dev_err(motg->phy.dev, "unable to get hsusb 1p8\n"); - rc = PTR_ERR(motg->v1p8); - goto disable_3p3; + goto exit; } rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN, USB_PHY_1P8_VOL_MAX); if (rc) { dev_err(motg->phy.dev, "unable to set voltage level " "for hsusb 1p8\n"); - goto put_1p8; + goto disable_3p3; } rc = regulator_enable(motg->v1p8); if (rc) { dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n"); - goto put_1p8; + goto disable_3p3; } return 0; } regulator_disable(motg->v1p8); -put_1p8: - regulator_put(motg->v1p8); disable_3p3: regulator_disable(motg->v3p3); -put_3p3: - regulator_put(motg->v3p3); +exit: return rc; } @@ -506,7 +480,7 @@ static int msm_otg_suspend(struct msm_otg *motg) clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); - if (motg->core_clk) + if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); if (!IS_ERR(motg->pclk_src)) @@ -546,7 +520,7 @@ static int msm_otg_resume(struct msm_otg *motg) clk_prepare_enable(motg->pclk); clk_prepare_enable(motg->clk); - if (motg->core_clk) + if (!IS_ERR(motg->core_clk)) clk_prepare_enable(motg->core_clk); if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && @@ -1404,6 +1378,7 @@ static void msm_otg_debugfs_cleanup(void) static int msm_otg_probe(struct platform_device *pdev) { + struct regulator_bulk_data regs[3]; int ret = 0; struct resource *res; struct msm_otg *motg; @@ -1415,37 +1390,34 @@ static int msm_otg_probe(struct platform_device *pdev) return -ENODEV; } - motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL); + motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL); if (!motg) { dev_err(&pdev->dev, "unable to allocate msm_otg\n"); return -ENOMEM; } - motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL); + motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), + GFP_KERNEL); if (!motg->phy.otg) { dev_err(&pdev->dev, "unable to allocate msm_otg\n"); - ret = -ENOMEM; - goto free_motg; + return -ENOMEM; } motg->pdata = dev_get_platdata(&pdev->dev); phy = &motg->phy; phy->dev = &pdev->dev; - motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk"); + motg->phy_reset_clk = devm_clk_get(&pdev->dev, "usb_phy_clk"); if (IS_ERR(motg->phy_reset_clk)) { dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); - ret = PTR_ERR(motg->phy_reset_clk); - goto free_motg; + return PTR_ERR(motg->phy_reset_clk); } - motg->clk = clk_get(&pdev->dev, "usb_hs_clk"); + motg->clk = devm_clk_get(&pdev->dev, "usb_hs_clk"); if (IS_ERR(motg->clk)) { dev_err(&pdev->dev, "failed to get usb_hs_clk\n"); - ret = PTR_ERR(motg->clk); - goto put_phy_reset_clk; + return PTR_ERR(motg->clk); } - clk_set_rate(motg->clk, 60000000); /* * If USB Core is running its protocol engine based on CORE CLK, @@ -1454,22 +1426,18 @@ static int msm_otg_probe(struct platform_device *pdev) * CORE CLK. For such USB cores, vote for maximum clk frequency * on pclk source */ + motg->pclk_src = ERR_PTR(-ENOENT); if (motg->pdata->pclk_src_name) { - motg->pclk_src = clk_get(&pdev->dev, - motg->pdata->pclk_src_name); + motg->pclk_src = devm_clk_get(&pdev->dev, + motg->pdata->pclk_src_name); if (IS_ERR(motg->pclk_src)) - goto put_clk; - clk_set_rate(motg->pclk_src, INT_MAX); - clk_prepare_enable(motg->pclk_src); - } else - motg->pclk_src = ERR_PTR(-ENOENT); - + return PTR_ERR(motg->pclk_src); + } - motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk"); + motg->pclk = devm_clk_get(&pdev->dev, "usb_hs_pclk"); if (IS_ERR(motg->pclk)) { dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); - ret = PTR_ERR(motg->pclk); - goto put_pclk_src; + return PTR_ERR(motg->pclk); } /* @@ -1477,65 +1445,72 @@ static int msm_otg_probe(struct platform_device *pdev) * clock is introduced to remove the dependency on AXI * bus frequency. */ - motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk"); - if (IS_ERR(motg->core_clk)) - motg->core_clk = NULL; + motg->core_clk = devm_clk_get(&pdev->dev, "usb_hs_core_clk"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform resource mem\n"); - ret = -ENODEV; - goto put_core_clk; - } + motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(motg->regs)) + return PTR_ERR(motg->regs); - motg->regs = ioremap(res->start, resource_size(res)); - if (!motg->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto put_core_clk; - } dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs); motg->irq = platform_get_irq(pdev, 0); if (!motg->irq) { dev_err(&pdev->dev, "platform_get_irq failed\n"); - ret = -ENODEV; - goto free_regs; + return motg->irq; + } + + regs[0].supply = "HSUSB_VDDCX"; + regs[1].supply = "HSUSB_3p3"; + regs[2].supply = "HSUSB_1p8"; + + ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); + if (ret) + return ret; + + motg->vddcx = regs[0].consumer; + motg->v3p3 = regs[1].consumer; + motg->v1p8 = regs[2].consumer; + + clk_set_rate(motg->clk, 60000000); + if (!IS_ERR(motg->pclk_src)) { + clk_set_rate(motg->pclk_src, INT_MAX); + clk_prepare_enable(motg->pclk_src); } clk_prepare_enable(motg->clk); clk_prepare_enable(motg->pclk); + if (!IS_ERR(motg->core_clk)) + clk_prepare_enable(motg->core_clk); + ret = msm_hsusb_init_vddcx(motg, 1); if (ret) { dev_err(&pdev->dev, "hsusb vddcx configuration failed\n"); - goto free_regs; + goto disable_clks; } ret = msm_hsusb_ldo_init(motg, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg configuration failed\n"); - goto vddcx_exit; + goto disable_vddcx; } ret = msm_hsusb_ldo_set_mode(motg, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg enable failed\n"); - goto ldo_exit; + goto disable_ldo; } - if (motg->core_clk) - clk_prepare_enable(motg->core_clk); - writel(0, USB_USBINTR); writel(0, USB_OTGSC); INIT_WORK(&motg->sm_work, msm_otg_sm_work); INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work); - ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED, + ret = devm_request_irq(&pdev->dev, motg->irq, msm_otg_irq, IRQF_SHARED, "msm_otg", motg); if (ret) { dev_err(&pdev->dev, "request irq failed\n"); - goto disable_clks; + goto disable_ldo; } phy->init = msm_otg_reset; @@ -1550,7 +1525,7 @@ static int msm_otg_probe(struct platform_device *pdev) ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2); if (ret) { dev_err(&pdev->dev, "usb_add_phy failed\n"); - goto free_irq; + goto disable_ldo; } platform_set_drvdata(pdev, motg); @@ -1568,33 +1543,18 @@ static int msm_otg_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); return 0; -free_irq: - free_irq(motg->irq, motg); + +disable_ldo: + msm_hsusb_ldo_init(motg, 0); +disable_vddcx: + msm_hsusb_init_vddcx(motg, 0); disable_clks: clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); -ldo_exit: - msm_hsusb_ldo_init(motg, 0); -vddcx_exit: - msm_hsusb_init_vddcx(motg, 0); -free_regs: - iounmap(motg->regs); -put_core_clk: - if (motg->core_clk) - clk_put(motg->core_clk); - clk_put(motg->pclk); -put_pclk_src: - if (!IS_ERR(motg->pclk_src)) { + if (!IS_ERR(motg->core_clk)) + clk_disable_unprepare(motg->core_clk); + if (!IS_ERR(motg->pclk_src)) clk_disable_unprepare(motg->pclk_src); - clk_put(motg->pclk_src); - } -put_clk: - clk_put(motg->clk); -put_phy_reset_clk: - clk_put(motg->phy_reset_clk); -free_motg: - kfree(motg->phy.otg); - kfree(motg); return ret; } @@ -1617,7 +1577,7 @@ static int msm_otg_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); usb_remove_phy(phy); - free_irq(motg->irq, motg); + disable_irq(motg->irq); /* * Put PHY in low power mode. @@ -1637,26 +1597,15 @@ static int msm_otg_remove(struct platform_device *pdev) clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); - if (motg->core_clk) + if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); - if (!IS_ERR(motg->pclk_src)) { + if (!IS_ERR(motg->pclk_src)) clk_disable_unprepare(motg->pclk_src); - clk_put(motg->pclk_src); - } + msm_hsusb_ldo_init(motg, 0); - iounmap(motg->regs); pm_runtime_set_suspended(&pdev->dev); - clk_put(motg->phy_reset_clk); - clk_put(motg->pclk); - clk_put(motg->clk); - if (motg->core_clk) - clk_put(motg->core_clk); - - kfree(motg->phy.otg); - kfree(motg); - return 0; } -- cgit v0.10.2 From f7ddad47421669452186678d51c09a3778ab552f Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:09 +0300 Subject: usb: phy: msm: Remove unnecessarily check for valid regulators. Whether regulators are available or not is checked at driver probe. If they are not available driver will refuse to load, so no need to check them again. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 67705fc..d7b8360 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -133,16 +133,6 @@ static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on) { int ret = 0; - if (!motg->v1p8 || IS_ERR(motg->v1p8)) { - pr_err("%s: HSUSB_1p8 is not initialized\n", __func__); - return -ENODEV; - } - - if (!motg->v3p3 || IS_ERR(motg->v3p3)) { - pr_err("%s: HSUSB_3p3 is not initialized\n", __func__); - return -ENODEV; - } - if (on) { ret = regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_HPM_LOAD); -- cgit v0.10.2 From 3aca0fa95f61918d5b78b683c0fbcbf693579f81 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:10 +0300 Subject: usb: phy: msm: Fix checkpatch.pl warnings This fixes following: WARNING: quoted string split across lines WARNING: Prefer seq_puts to seq_printf Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index d7b8360..874c51a 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -67,8 +67,7 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) USB_PHY_VDD_DIG_VOL_MIN, USB_PHY_VDD_DIG_VOL_MAX); if (ret) { - dev_err(motg->phy.dev, "unable to set the voltage " - "for hsusb vddcx\n"); + dev_err(motg->phy.dev, "Cannot set vddcx voltage\n"); return ret; } @@ -79,8 +78,7 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) ret = regulator_set_voltage(motg->vddcx, 0, USB_PHY_VDD_DIG_VOL_MAX); if (ret) - dev_err(motg->phy.dev, "unable to set the voltage " - "for hsusb vddcx\n"); + dev_err(motg->phy.dev, "Cannot set vddcx voltage\n"); ret = regulator_disable(motg->vddcx); if (ret) dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n"); @@ -97,8 +95,7 @@ static int msm_hsusb_ldo_init(struct msm_otg *motg, int init) rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN, USB_PHY_3P3_VOL_MAX); if (rc) { - dev_err(motg->phy.dev, "unable to set voltage level " - "for hsusb 3p3\n"); + dev_err(motg->phy.dev, "Cannot set v3p3 voltage\n"); goto exit; } rc = regulator_enable(motg->v3p3); @@ -109,8 +106,7 @@ static int msm_hsusb_ldo_init(struct msm_otg *motg, int init) rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN, USB_PHY_1P8_VOL_MAX); if (rc) { - dev_err(motg->phy.dev, "unable to set voltage level " - "for hsusb 1p8\n"); + dev_err(motg->phy.dev, "Cannot set v1p8 voltage\n"); goto disable_3p3; } rc = regulator_enable(motg->v1p8); @@ -137,15 +133,13 @@ static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on) ret = regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_HPM_LOAD); if (ret < 0) { - pr_err("%s: Unable to set HPM of the regulator " - "HSUSB_1p8\n", __func__); + pr_err("Could not set HPM for v1p8\n"); return ret; } ret = regulator_set_optimum_mode(motg->v3p3, USB_PHY_3P3_HPM_LOAD); if (ret < 0) { - pr_err("%s: Unable to set HPM of the regulator " - "HSUSB_3p3\n", __func__); + pr_err("Could not set HPM for v3p3\n"); regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_LPM_LOAD); return ret; @@ -154,13 +148,11 @@ static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on) ret = regulator_set_optimum_mode(motg->v1p8, USB_PHY_1P8_LPM_LOAD); if (ret < 0) - pr_err("%s: Unable to set LPM of the regulator " - "HSUSB_1p8\n", __func__); + pr_err("Could not set LPM for v1p8\n"); ret = regulator_set_optimum_mode(motg->v3p3, USB_PHY_3P3_LPM_LOAD); if (ret < 0) - pr_err("%s: Unable to set LPM of the regulator " - "HSUSB_3p3\n", __func__); + pr_err("Could not set LPM for v3p3\n"); } pr_debug("reg (%s)\n", on ? "HPM" : "LPM"); @@ -390,8 +382,7 @@ static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high) ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol); if (ret) { - pr_err("%s: unable to set the voltage for regulator " - "HSUSB_VDDCX\n", __func__); + pr_err("Cannot set vddcx voltage\n"); return ret; } @@ -546,8 +537,7 @@ static int msm_otg_resume(struct msm_otg *motg) * PHY. USB state can not be restored. Re-insertion * of USB cable is the only way to get USB working. */ - dev_err(phy->dev, "Unable to resume USB." - "Re-plugin the cable\n"); + dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n"); msm_otg_reset(phy); } @@ -1242,13 +1232,13 @@ static int msm_otg_mode_show(struct seq_file *s, void *unused) switch (otg->phy->state) { case OTG_STATE_A_HOST: - seq_printf(s, "host\n"); + seq_puts(s, "host\n"); break; case OTG_STATE_B_PERIPHERAL: - seq_printf(s, "peripheral\n"); + seq_puts(s, "peripheral\n"); break; default: - seq_printf(s, "none\n"); + seq_puts(s, "none\n"); break; } @@ -1525,8 +1515,7 @@ static int msm_otg_probe(struct platform_device *pdev) motg->pdata->otg_control == OTG_USER_CONTROL) { ret = msm_otg_debugfs_init(motg); if (ret) - dev_dbg(&pdev->dev, "mode debugfs file is" - "not available\n"); + dev_dbg(&pdev->dev, "Can not create mode change file\n"); } pm_runtime_set_active(&pdev->dev); -- cgit v0.10.2 From 971232cf7c7a71ad3cbf433f592eee3ae1a578ac Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:11 +0300 Subject: usb: phy: msm: Replace custom enum usb_mode_type with enum usb_dr_mode Use enum usb_dr_mode and drop default usb_dr_mode from platform data. USB DT bindings states: dr_mode: "...In case this attribute isn't passed via DT, USB DRD controllers should default to OTG...", so remove redundand field. Signed-off-by: Ivan T. Ivanov Acked-by: David Brown Signed-off-by: Felipe Balbi diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index 46de789..0c4c200 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -95,7 +95,7 @@ static int hsusb_phy_clk_reset(struct clk *phy_clk) static struct msm_otg_platform_data msm_otg_pdata = { .phy_init_seq = hsusb_phy_init_seq, - .mode = USB_PERIPHERAL, + .mode = USB_DR_MODE_PERIPHERAL, .otg_control = OTG_PHY_CONTROL, .link_clk_reset = hsusb_link_clk_reset, .phy_clk_reset = hsusb_phy_clk_reset, diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 9169ec3..4c74861 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -116,7 +116,7 @@ static int hsusb_phy_clk_reset(struct clk *phy_clk) static struct msm_otg_platform_data msm_otg_pdata = { .phy_init_seq = hsusb_phy_init_seq, - .mode = USB_PERIPHERAL, + .mode = USB_DR_MODE_PERIPHERAL, .otg_control = OTG_PHY_CONTROL, .link_clk_reset = hsusb_link_clk_reset, .phy_clk_reset = hsusb_phy_clk_reset, diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 874c51a..7eb2abf 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -348,10 +348,10 @@ static int msm_otg_reset(struct usb_phy *phy) if (pdata->otg_control == OTG_PHY_CONTROL) { val = readl(USB_OTGSC); - if (pdata->mode == USB_OTG) { + if (pdata->mode == USB_DR_MODE_OTG) { ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID; val |= OTGSC_IDIE | OTGSC_BSVIE; - } else if (pdata->mode == USB_PERIPHERAL) { + } else if (pdata->mode == USB_DR_MODE_PERIPHERAL) { ulpi_val = ULPI_INT_SESS_VALID; val |= OTGSC_BSVIE; } @@ -637,7 +637,7 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) * Fail host registration if this board can support * only peripheral configuration. */ - if (motg->pdata->mode == USB_PERIPHERAL) { + if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) { dev_info(otg->phy->dev, "Host mode is not supported\n"); return -ENODEV; } @@ -666,7 +666,7 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) * Kick the state machine work, if peripheral is not supported * or peripheral is already registered with us. */ - if (motg->pdata->mode == USB_HOST || otg->gadget) { + if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) { pm_runtime_get_sync(otg->phy->dev); schedule_work(&motg->sm_work); } @@ -710,7 +710,7 @@ static int msm_otg_set_peripheral(struct usb_otg *otg, * Fail peripheral registration if this board can support * only host configuration. */ - if (motg->pdata->mode == USB_HOST) { + if (motg->pdata->mode == USB_DR_MODE_HOST) { dev_info(otg->phy->dev, "Peripheral mode is not supported\n"); return -ENODEV; } @@ -735,7 +735,7 @@ static int msm_otg_set_peripheral(struct usb_otg *otg, * Kick the state machine work, if host is not supported * or host is already registered with us. */ - if (motg->pdata->mode == USB_PERIPHERAL || otg->host) { + if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) { pm_runtime_get_sync(otg->phy->dev); schedule_work(&motg->sm_work); } @@ -1056,7 +1056,7 @@ static void msm_otg_init_sm(struct msm_otg *motg) u32 otgsc = readl(USB_OTGSC); switch (pdata->mode) { - case USB_OTG: + case USB_DR_MODE_OTG: if (pdata->otg_control == OTG_PHY_CONTROL) { if (otgsc & OTGSC_ID) set_bit(ID, &motg->inputs); @@ -1068,21 +1068,14 @@ static void msm_otg_init_sm(struct msm_otg *motg) else clear_bit(B_SESS_VLD, &motg->inputs); } else if (pdata->otg_control == OTG_USER_CONTROL) { - if (pdata->default_mode == USB_HOST) { - clear_bit(ID, &motg->inputs); - } else if (pdata->default_mode == USB_PERIPHERAL) { - set_bit(ID, &motg->inputs); - set_bit(B_SESS_VLD, &motg->inputs); - } else { set_bit(ID, &motg->inputs); clear_bit(B_SESS_VLD, &motg->inputs); - } } break; - case USB_HOST: + case USB_DR_MODE_HOST: clear_bit(ID, &motg->inputs); break; - case USB_PERIPHERAL: + case USB_DR_MODE_PERIPHERAL: set_bit(ID, &motg->inputs); if (otgsc & OTGSC_BSV) set_bit(B_SESS_VLD, &motg->inputs); @@ -1258,7 +1251,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, char buf[16]; struct usb_otg *otg = motg->phy.otg; int status = count; - enum usb_mode_type req_mode; + enum usb_dr_mode req_mode; memset(buf, 0x00, sizeof(buf)); @@ -1268,18 +1261,18 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, } if (!strncmp(buf, "host", 4)) { - req_mode = USB_HOST; + req_mode = USB_DR_MODE_HOST; } else if (!strncmp(buf, "peripheral", 10)) { - req_mode = USB_PERIPHERAL; + req_mode = USB_DR_MODE_PERIPHERAL; } else if (!strncmp(buf, "none", 4)) { - req_mode = USB_NONE; + req_mode = USB_DR_MODE_UNKNOWN; } else { status = -EINVAL; goto out; } switch (req_mode) { - case USB_NONE: + case USB_DR_MODE_UNKNOWN: switch (otg->phy->state) { case OTG_STATE_A_HOST: case OTG_STATE_B_PERIPHERAL: @@ -1290,7 +1283,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, goto out; } break; - case USB_PERIPHERAL: + case USB_DR_MODE_PERIPHERAL: switch (otg->phy->state) { case OTG_STATE_B_IDLE: case OTG_STATE_A_HOST: @@ -1301,7 +1294,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, goto out; } break; - case USB_HOST: + case USB_DR_MODE_HOST: switch (otg->phy->state) { case OTG_STATE_B_IDLE: case OTG_STATE_B_PERIPHERAL: @@ -1511,7 +1504,7 @@ static int msm_otg_probe(struct platform_device *pdev) platform_set_drvdata(pdev, motg); device_init_wakeup(&pdev->dev, 1); - if (motg->pdata->mode == USB_OTG && + if (motg->pdata->mode == USB_DR_MODE_OTG && motg->pdata->otg_control == OTG_USER_CONTROL) { ret = msm_otg_debugfs_init(motg); if (ret) diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 8705b01..72c5830 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -23,21 +23,6 @@ #include /** - * Supported USB modes - * - * USB_PERIPHERAL Only peripheral mode is supported. - * USB_HOST Only host mode is supported. - * USB_OTG OTG mode is supported. - * - */ -enum usb_mode_type { - USB_NONE = 0, - USB_PERIPHERAL, - USB_HOST, - USB_OTG, -}; - -/** * OTG control * * OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host @@ -121,8 +106,6 @@ enum usb_chg_type { * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). * @mode: Supported mode (OTG/peripheral/host). * @otg_control: OTG switch controlled by user/Id pin - * @default_mode: Default operational mode. Applicable only if - * OTG switch is controller by user. * @pclk_src_name: pclk is derived from ebi1_usb_clk in case of 7x27 and 8k * dfab_usb_hs_clk in case of 8660 and 8960. */ @@ -130,9 +113,8 @@ struct msm_otg_platform_data { int *phy_init_seq; void (*vbus_power)(bool on); unsigned power_budget; - enum usb_mode_type mode; + enum usb_dr_mode mode; enum otg_control_type otg_control; - enum usb_mode_type default_mode; enum msm_usb_phy_type phy_type; void (*setup_gpio)(enum usb_otg_state state); char *pclk_src_name; -- cgit v0.10.2 From ff0e4a68c931dc34e43c081d1b6a895a9aaf8a2b Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:12 +0300 Subject: usb: phy: msm: Remove unused pclk_src_name There are no references to 'pclk_src_name' in plaform code, so it is unused. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 7eb2abf..c2361bf 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -464,9 +464,6 @@ static int msm_otg_suspend(struct msm_otg *motg) if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); - if (!IS_ERR(motg->pclk_src)) - clk_disable_unprepare(motg->pclk_src); - if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) { msm_hsusb_ldo_set_mode(motg, 0); @@ -496,9 +493,6 @@ static int msm_otg_resume(struct msm_otg *motg) if (!atomic_read(&motg->in_lpm)) return 0; - if (!IS_ERR(motg->pclk_src)) - clk_prepare_enable(motg->pclk_src); - clk_prepare_enable(motg->pclk); clk_prepare_enable(motg->clk); if (!IS_ERR(motg->core_clk)) @@ -1396,17 +1390,8 @@ static int msm_otg_probe(struct platform_device *pdev) * If USB Core is running its protocol engine based on CORE CLK, * CORE CLK must be running at >55Mhz for correct HSUSB * operation and USB core cannot tolerate frequency changes on - * CORE CLK. For such USB cores, vote for maximum clk frequency - * on pclk source + * CORE CLK. */ - motg->pclk_src = ERR_PTR(-ENOENT); - if (motg->pdata->pclk_src_name) { - motg->pclk_src = devm_clk_get(&pdev->dev, - motg->pdata->pclk_src_name); - if (IS_ERR(motg->pclk_src)) - return PTR_ERR(motg->pclk_src); - } - motg->pclk = devm_clk_get(&pdev->dev, "usb_hs_pclk"); if (IS_ERR(motg->pclk)) { dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); @@ -1446,10 +1431,6 @@ static int msm_otg_probe(struct platform_device *pdev) motg->v1p8 = regs[2].consumer; clk_set_rate(motg->clk, 60000000); - if (!IS_ERR(motg->pclk_src)) { - clk_set_rate(motg->pclk_src, INT_MAX); - clk_prepare_enable(motg->pclk_src); - } clk_prepare_enable(motg->clk); clk_prepare_enable(motg->pclk); @@ -1525,8 +1506,6 @@ disable_clks: clk_disable_unprepare(motg->clk); if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); - if (!IS_ERR(motg->pclk_src)) - clk_disable_unprepare(motg->pclk_src); return ret; } @@ -1571,9 +1550,6 @@ static int msm_otg_remove(struct platform_device *pdev) clk_disable_unprepare(motg->clk); if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); - if (!IS_ERR(motg->pclk_src)) - clk_disable_unprepare(motg->pclk_src); - msm_hsusb_ldo_init(motg, 0); pm_runtime_set_suspended(&pdev->dev); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 72c5830..262ed80 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -106,8 +106,6 @@ enum usb_chg_type { * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). * @mode: Supported mode (OTG/peripheral/host). * @otg_control: OTG switch controlled by user/Id pin - * @pclk_src_name: pclk is derived from ebi1_usb_clk in case of 7x27 and 8k - * dfab_usb_hs_clk in case of 8660 and 8960. */ struct msm_otg_platform_data { int *phy_init_seq; @@ -117,7 +115,6 @@ struct msm_otg_platform_data { enum otg_control_type otg_control; enum msm_usb_phy_type phy_type; void (*setup_gpio)(enum usb_otg_state state); - char *pclk_src_name; int (*link_clk_reset)(struct clk *link_clk, bool assert); int (*phy_clk_reset)(struct clk *phy_clk); }; @@ -129,7 +126,6 @@ struct msm_otg_platform_data { * @irq: IRQ number assigned for HSUSB controller. * @clk: clock struct of usb_hs_clk. * @pclk: clock struct of usb_hs_pclk. - * @pclk_src: pclk source for voting. * @phy_reset_clk: clock struct of usb_phy_clk. * @core_clk: clock struct of usb_hs_core_clk. * @regs: ioremapped register base address. @@ -150,7 +146,6 @@ struct msm_otg { int irq; struct clk *clk; struct clk *pclk; - struct clk *pclk_src; struct clk *phy_reset_clk; struct clk *core_clk; void __iomem *regs; -- cgit v0.10.2 From f5ef2372f608df4bb54b4fc7c9e43fb8bbef4795 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:13 +0300 Subject: usb: phy: msm: Remove HSUSB prefix from regulator names Prefix did not bring any useful information. Currently none of the MSM platforms define these regulators, so it is safe to rename them. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index c2361bf..bd9e286 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1418,9 +1418,9 @@ static int msm_otg_probe(struct platform_device *pdev) return motg->irq; } - regs[0].supply = "HSUSB_VDDCX"; - regs[1].supply = "HSUSB_3p3"; - regs[2].supply = "HSUSB_1p8"; + regs[0].supply = "vddcx"; + regs[1].supply = "v3p3"; + regs[2].supply = "v1p8"; ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); if (ret) -- cgit v0.10.2 From f60c114a3ae528dfc6750baad58cf822d0b282a2 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:14 +0300 Subject: usb: phy: msm: Properly check result from platform_get_irq() Function return negative code on error. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index bd9e286..7e968aa 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1413,7 +1413,7 @@ static int msm_otg_probe(struct platform_device *pdev) dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs); motg->irq = platform_get_irq(pdev, 0); - if (!motg->irq) { + if (motg->irq < 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); return motg->irq; } -- cgit v0.10.2 From 8364f9af237f47fa128bd4e4f7b45beef890c994 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:15 +0300 Subject: usb: phy: msm: Add device tree support and binding information Allows controller to be specified via device tree. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index 5ea26c6..ee4123d 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -15,3 +15,70 @@ Example EHCI controller device node: usb-phy = <&usb_otg>; }; +USB PHY with optional OTG: + +Required properties: +- compatible: Should contain: + "qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY + "qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY + +- regs: Offset and length of the register set in the memory map +- interrupts: interrupt-specifier for the OTG interrupt. + +- clocks: A list of phandle + clock-specifier pairs for the + clocks listed in clock-names +- clock-names: Should contain the following: + "phy" USB PHY reference clock + "core" Protocol engine clock + "iface" Interface bus clock + "alt_core" Protocol engine clock for targets with asynchronous + reset methodology. (optional) + +- vdccx-supply: phandle to the regulator for the vdd supply for + digital circuit operation. +- v1p8-supply: phandle to the regulator for the 1.8V supply +- v3p3-supply: phandle to the regulator for the 3.3V supply + +- resets: A list of phandle + reset-specifier pairs for the + resets listed in reset-names +- reset-names: Should contain the following: + "phy" USB PHY controller reset + "link" USB LINK controller reset + +- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of + 1 - PHY control + 2 - PMIC control + +Optional properties: +- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" + +- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device + Mode Eye Diagram test. Start address at which these values will be + written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as + "do not overwrite default value at this address". + For example: qcom,phy-init-sequence = < -1 0x63 >; + Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1. + +Example HSUSB OTG controller device node: + + usb@f9a55000 { + compatible = "qcom,usb-otg-snps"; + reg = <0xf9a55000 0x400>; + interrupts = <0 134 0>; + dr_mode = "peripheral"; + + clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>, + <&gcc GCC_USB_HS_AHB_CLK>; + + clock-names = "phy", "core", "iface"; + + vddcx-supply = <&pm8841_s2_corner>; + v1p8-supply = <&pm8941_l6>; + v3p3-supply = <&pm8941_l24>; + + resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>; + reset-names = "phy", "link"; + + qcom,otg-control = <1>; + qcom,phy-init-sequence = < -1 0x63 >; + }; diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 7e968aa..1bf2d4e 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -30,9 +30,12 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -217,16 +220,16 @@ static struct usb_phy_io_ops msm_otg_io_ops = { static void ulpi_init(struct msm_otg *motg) { struct msm_otg_platform_data *pdata = motg->pdata; - int *seq = pdata->phy_init_seq; + int *seq = pdata->phy_init_seq, idx; + u32 addr = ULPI_EXT_VENDOR_SPECIFIC; - if (!seq) - return; + for (idx = 0; idx < pdata->phy_init_sz; idx++) { + if (seq[idx] == -1) + continue; - while (seq[0] >= 0) { dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n", - seq[0], seq[1]); - ulpi_write(&motg->phy, seq[0], seq[1]); - seq += 2; + seq[idx], addr + idx); + ulpi_write(&motg->phy, seq[idx], addr + idx); } } @@ -1343,26 +1346,96 @@ static void msm_otg_debugfs_cleanup(void) debugfs_remove(msm_otg_dbg_root); } +static struct of_device_id msm_otg_dt_match[] = { + { + .compatible = "qcom,usb-otg-ci", + .data = (void *) CI_45NM_INTEGRATED_PHY + }, + { + .compatible = "qcom,usb-otg-snps", + .data = (void *) SNPS_28NM_INTEGRATED_PHY + }, + { } +}; +MODULE_DEVICE_TABLE(of, msm_otg_dt_match); + +static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) +{ + struct msm_otg_platform_data *pdata; + const struct of_device_id *id; + struct device_node *node = pdev->dev.of_node; + struct property *prop; + int len, ret, words; + u32 val; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + motg->pdata = pdata; + + id = of_match_device(msm_otg_dt_match, &pdev->dev); + pdata->phy_type = (int) id->data; + + pdata->mode = of_usb_get_dr_mode(node); + if (pdata->mode == USB_DR_MODE_UNKNOWN) + pdata->mode = USB_DR_MODE_OTG; + + pdata->otg_control = OTG_PHY_CONTROL; + if (!of_property_read_u32(node, "qcom,otg-control", &val)) + if (val == OTG_PMIC_CONTROL) + pdata->otg_control = val; + + prop = of_find_property(node, "qcom,phy-init-sequence", &len); + if (!prop || !len) + return 0; + + words = len / sizeof(u32); + + if (words >= ULPI_EXT_VENDOR_SPECIFIC) { + dev_warn(&pdev->dev, "Too big PHY init sequence %d\n", words); + return 0; + } + + pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); + if (!pdata->phy_init_seq) { + dev_warn(&pdev->dev, "No space for PHY init sequence\n"); + return 0; + } + + ret = of_property_read_u32_array(node, "qcom,phy-init-sequence", + pdata->phy_init_seq, words); + if (!ret) + pdata->phy_init_sz = words; + + return 0; +} + static int msm_otg_probe(struct platform_device *pdev) { struct regulator_bulk_data regs[3]; int ret = 0; + struct device_node *np = pdev->dev.of_node; + struct msm_otg_platform_data *pdata; struct resource *res; struct msm_otg *motg; struct usb_phy *phy; - dev_info(&pdev->dev, "msm_otg probe\n"); - if (!dev_get_platdata(&pdev->dev)) { - dev_err(&pdev->dev, "No platform data given. Bailing out\n"); - return -ENODEV; - } - motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL); if (!motg) { dev_err(&pdev->dev, "unable to allocate msm_otg\n"); return -ENOMEM; } + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + if (!np) + return -ENXIO; + ret = msm_otg_read_dt(pdev, motg); + if (ret) + return ret; + } + motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), GFP_KERNEL); if (!motg->phy.otg) { @@ -1370,17 +1443,17 @@ static int msm_otg_probe(struct platform_device *pdev) return -ENOMEM; } - motg->pdata = dev_get_platdata(&pdev->dev); phy = &motg->phy; phy->dev = &pdev->dev; - motg->phy_reset_clk = devm_clk_get(&pdev->dev, "usb_phy_clk"); + motg->phy_reset_clk = devm_clk_get(&pdev->dev, + np ? "phy" : "usb_phy_clk"); if (IS_ERR(motg->phy_reset_clk)) { dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); return PTR_ERR(motg->phy_reset_clk); } - motg->clk = devm_clk_get(&pdev->dev, "usb_hs_clk"); + motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk"); if (IS_ERR(motg->clk)) { dev_err(&pdev->dev, "failed to get usb_hs_clk\n"); return PTR_ERR(motg->clk); @@ -1392,7 +1465,7 @@ static int msm_otg_probe(struct platform_device *pdev) * operation and USB core cannot tolerate frequency changes on * CORE CLK. */ - motg->pclk = devm_clk_get(&pdev->dev, "usb_hs_pclk"); + motg->pclk = devm_clk_get(&pdev->dev, np ? "iface" : "usb_hs_pclk"); if (IS_ERR(motg->pclk)) { dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); return PTR_ERR(motg->pclk); @@ -1403,7 +1476,8 @@ static int msm_otg_probe(struct platform_device *pdev) * clock is introduced to remove the dependency on AXI * bus frequency. */ - motg->core_clk = devm_clk_get(&pdev->dev, "usb_hs_core_clk"); + motg->core_clk = devm_clk_get(&pdev->dev, + np ? "alt_core" : "usb_hs_core_clk"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); @@ -1486,7 +1560,7 @@ static int msm_otg_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); if (motg->pdata->mode == USB_DR_MODE_OTG && - motg->pdata->otg_control == OTG_USER_CONTROL) { + motg->pdata->otg_control == OTG_USER_CONTROL) { ret = msm_otg_debugfs_init(motg); if (ret) dev_dbg(&pdev->dev, "Can not create mode change file\n"); @@ -1639,6 +1713,7 @@ static struct platform_driver msm_otg_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .pm = &msm_otg_dev_pm_ops, + .of_match_table = msm_otg_dt_match, }, }; diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 262ed80..bd68299 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -100,8 +100,9 @@ enum usb_chg_type { /** * struct msm_otg_platform_data - platform device data * for msm_otg driver. - * @phy_init_seq: PHY configuration sequence. val, reg pairs - * terminated by -1. + * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as + * "do not overwrite default vaule at this address". + * @phy_init_sz: PHY configuration sequence size. * @vbus_power: VBUS power on/off routine. * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). * @mode: Supported mode (OTG/peripheral/host). @@ -109,6 +110,7 @@ enum usb_chg_type { */ struct msm_otg_platform_data { int *phy_init_seq; + int phy_init_sz; void (*vbus_power)(bool on); unsigned power_budget; enum usb_dr_mode mode; -- cgit v0.10.2 From a27345434134080273e0597e1d9721ff9e6ca67f Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:16 +0300 Subject: usb: phy: msm: Use reset framework for LINK and PHY resets Using reset framework eliminate need of platform specific callbacks and enable reset lines to be specified in DT files. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 1bf2d4e..a6abb1b 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -235,12 +236,15 @@ static void ulpi_init(struct msm_otg *motg) static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) { - int ret = 0; + int ret; - if (!motg->pdata->link_clk_reset) - return ret; + if (motg->pdata->link_clk_reset) + ret = motg->pdata->link_clk_reset(motg->clk, assert); + else if (assert) + ret = reset_control_assert(motg->link_rst); + else + ret = reset_control_deassert(motg->link_rst); - ret = motg->pdata->link_clk_reset(motg->clk, assert); if (ret) dev_err(motg->phy.dev, "usb link clk reset %s failed\n", assert ? "assert" : "deassert"); @@ -250,12 +254,13 @@ static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) static int msm_otg_phy_clk_reset(struct msm_otg *motg) { - int ret = 0; + int ret; - if (!motg->pdata->phy_clk_reset) - return ret; + if (motg->pdata->phy_clk_reset) + ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk); + else + ret = reset_control_reset(motg->phy_rst); - ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk); if (ret) dev_err(motg->phy.dev, "usb phy clk reset failed\n"); @@ -1377,6 +1382,14 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) id = of_match_device(msm_otg_dt_match, &pdev->dev); pdata->phy_type = (int) id->data; + motg->link_rst = devm_reset_control_get(&pdev->dev, "link"); + if (IS_ERR(motg->link_rst)) + return PTR_ERR(motg->link_rst); + + motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy"); + if (IS_ERR(motg->phy_rst)) + return PTR_ERR(motg->phy_rst); + pdata->mode = of_usb_get_dr_mode(node); if (pdata->mode == USB_DR_MODE_UNKNOWN) pdata->mode = USB_DR_MODE_OTG; diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index bd68299..4e5d916 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -165,6 +165,9 @@ struct msm_otg { struct regulator *v3p3; struct regulator *v1p8; struct regulator *vddcx; + + struct reset_control *phy_rst; + struct reset_control *link_rst; }; #endif -- cgit v0.10.2 From cfa3ff5dfe6a11ac8bc4a080416984ab00b0980c Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:17 +0300 Subject: usb: phy: msm: Add support for secondary PHY control Allow support to use 2nd HSPHY with USB2 Core. Some platforms may have configuration to allow USB controller work with any of the two HSPHYs present. By default driver configures USB core to use primary HSPHY. Add support to allow user select 2nd HSPHY using DT parameter. Signed-off-by: Ivan T. Ivanov Cc: Manu Gautam Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index ee4123d..0669667 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -59,6 +59,12 @@ Optional properties: For example: qcom,phy-init-sequence = < -1 0x63 >; Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1. +- qcom,phy-num: Select number of pyco-phy to use, can be one of + 0 - PHY one, default + 1 - Second PHY + Some platforms may have configuration to allow USB + controller work with any of the two HSPHYs present. + Example HSUSB OTG controller device node: usb@f9a55000 { diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index a6abb1b..8d57045 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -314,6 +314,9 @@ static int msm_otg_phy_reset(struct msm_otg *motg) if (!retries) return -ETIMEDOUT; + if (motg->phy_number) + writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); + dev_info(motg->phy.dev, "phy_reset: success\n"); return 0; } @@ -368,6 +371,9 @@ static int msm_otg_reset(struct usb_phy *phy) ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL); } + if (motg->phy_number) + writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); + return 0; } @@ -404,6 +410,7 @@ static int msm_otg_suspend(struct msm_otg *motg) struct usb_phy *phy = &motg->phy; struct usb_bus *bus = phy->otg->host; struct msm_otg_platform_data *pdata = motg->pdata; + void __iomem *addr; int cnt = 0; if (atomic_read(&motg->in_lpm)) @@ -463,9 +470,13 @@ static int msm_otg_suspend(struct msm_otg *motg) */ writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD); + addr = USB_PHY_CTRL; + if (motg->phy_number) + addr = USB_PHY_CTRL2; + if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) - writel(readl(USB_PHY_CTRL) | PHY_RETEN, USB_PHY_CTRL); + writel(readl(addr) | PHY_RETEN, addr); clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); @@ -495,6 +506,7 @@ static int msm_otg_resume(struct msm_otg *motg) { struct usb_phy *phy = &motg->phy; struct usb_bus *bus = phy->otg->host; + void __iomem *addr; int cnt = 0; unsigned temp; @@ -508,9 +520,14 @@ static int msm_otg_resume(struct msm_otg *motg) if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) { + + addr = USB_PHY_CTRL; + if (motg->phy_number) + addr = USB_PHY_CTRL2; + msm_hsusb_ldo_set_mode(motg, 1); msm_hsusb_config_vddcx(motg, 1); - writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL); + writel(readl(addr) & ~PHY_RETEN, addr); } temp = readl(USB_USBCMD); @@ -1399,6 +1416,9 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) if (val == OTG_PMIC_CONTROL) pdata->otg_control = val; + if (!of_property_read_u32(node, "qcom,phy-num", &val) && val < 2) + motg->phy_number = val; + prop = of_find_property(node, "qcom,phy-init-sequence", &len); if (!prop || !len) return 0; diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 4e5d916..4628f1a 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -158,6 +158,7 @@ struct msm_otg { atomic_t in_lpm; int async_int; unsigned cur_power; + int phy_number; struct delayed_work chg_work; enum usb_chg_state chg_state; enum usb_chg_type chg_type; diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h index 6e97a2d..e6d7035 100644 --- a/include/linux/usb/msm_hsusb_hw.h +++ b/include/linux/usb/msm_hsusb_hw.h @@ -25,6 +25,7 @@ #define USB_OTGSC (MSM_USB_BASE + 0x01A4) #define USB_USBMODE (MSM_USB_BASE + 0x01A8) #define USB_PHY_CTRL (MSM_USB_BASE + 0x0240) +#define USB_PHY_CTRL2 (MSM_USB_BASE + 0x0278) #define USBCMD_RESET 2 #define USB_USBINTR (MSM_USB_BASE + 0x0148) -- cgit v0.10.2 From d69c6f5df376ea40df5886468b155f515fddfbb2 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:18 +0300 Subject: usb: phy: msm: Correct USB PHY Reset sequence for newer platform On few legacy platforms, USB PHY is having dedicated reset clk. It is used to reset USB PHY after putting USB PHY into low power mode and for calibration of USB PHY. Putting USB PHY into low power mode is causing ulpi read/write timeout as expected. USB PHY reset clk is not available on newer platform. For 28nm PHY, reset USB PHY after resetting USB LINK. Also reset USB PHY using USB_PHY_PON bit with USB_OTG_HS_PHY_CTRL register after programming USB PHY Override registers as suggested with hardware programming guidelines. Signed-off-by: Ivan T. Ivanov Signed-off-by: Tim Bird Cc: Mayank Rana Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 8d57045..bb33996 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -48,6 +48,7 @@ #define DRIVER_NAME "msm_otg" #define ULPI_IO_TIMEOUT_USEC (10 * 1000) +#define LINK_RESET_TIMEOUT_USEC (250 * 1000) #define USB_PHY_3P3_VOL_MIN 3050000 /* uV */ #define USB_PHY_3P3_VOL_MAX 3300000 /* uV */ @@ -267,77 +268,35 @@ static int msm_otg_phy_clk_reset(struct msm_otg *motg) return ret; } -static int msm_otg_phy_reset(struct msm_otg *motg) +static int msm_link_reset(struct msm_otg *motg) { u32 val; int ret; - int retries; ret = msm_otg_link_clk_reset(motg, 1); if (ret) return ret; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; - ret = msm_otg_link_clk_reset(motg, 0); - if (ret) - return ret; - val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; - writel(val | PORTSC_PTS_ULPI, USB_PORTSC); - - for (retries = 3; retries > 0; retries--) { - ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM, - ULPI_CLR(ULPI_FUNC_CTRL)); - if (!ret) - break; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; - } - if (!retries) - return -ETIMEDOUT; + /* wait for 1ms delay as suggested in HPG. */ + usleep_range(1000, 1200); - /* This reset calibrates the phy, if the above write succeeded */ - ret = msm_otg_phy_clk_reset(motg); + ret = msm_otg_link_clk_reset(motg, 0); if (ret) return ret; - for (retries = 3; retries > 0; retries--) { - ret = ulpi_read(&motg->phy, ULPI_DEBUG); - if (ret != -ETIMEDOUT) - break; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; - } - if (!retries) - return -ETIMEDOUT; - if (motg->phy_number) writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); - dev_info(motg->phy.dev, "phy_reset: success\n"); + val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; + writel(val | PORTSC_PTS_ULPI, USB_PORTSC); + return 0; } -#define LINK_RESET_TIMEOUT_USEC (250 * 1000) static int msm_otg_reset(struct usb_phy *phy) { struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - struct msm_otg_platform_data *pdata = motg->pdata; int cnt = 0; - int ret; - u32 val = 0; - u32 ulpi_val = 0; - - ret = msm_otg_phy_reset(motg); - if (ret) { - dev_err(phy->dev, "phy_reset failed\n"); - return ret; - } - - ulpi_init(motg); writel(USBCMD_RESET, USB_USBCMD); while (cnt < LINK_RESET_TIMEOUT_USEC) { @@ -351,11 +310,86 @@ static int msm_otg_reset(struct usb_phy *phy) /* select ULPI phy */ writel(0x80000000, USB_PORTSC); + writel(0x0, USB_AHBBURST); + writel(0x08, USB_AHBMODE); + + if (motg->phy_number) + writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); + return 0; +} + +static void msm_phy_reset(struct msm_otg *motg) +{ + void __iomem *addr; + + if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY) { + msm_otg_phy_clk_reset(motg); + return; + } + + addr = USB_PHY_CTRL; + if (motg->phy_number) + addr = USB_PHY_CTRL2; + + /* Assert USB PHY_POR */ + writel(readl(addr) | PHY_POR_ASSERT, addr); + + /* + * wait for minimum 10 microseconds as suggested in HPG. + * Use a slightly larger value since the exact value didn't + * work 100% of the time. + */ + udelay(12); + + /* Deassert USB PHY_POR */ + writel(readl(addr) & ~PHY_POR_ASSERT, addr); +} + +static int msm_usb_reset(struct usb_phy *phy) +{ + struct msm_otg *motg = container_of(phy, struct msm_otg, phy); + int ret; + + if (!IS_ERR(motg->core_clk)) + clk_prepare_enable(motg->core_clk); + + ret = msm_link_reset(motg); + if (ret) { + dev_err(phy->dev, "phy_reset failed\n"); + return ret; + } + + ret = msm_otg_reset(&motg->phy); + if (ret) { + dev_err(phy->dev, "link reset failed\n"); + return ret; + } msleep(100); - writel(0x0, USB_AHBBURST); - writel(0x00, USB_AHBMODE); + /* Reset USB PHY after performing USB Link RESET */ + msm_phy_reset(motg); + + if (!IS_ERR(motg->core_clk)) + clk_disable_unprepare(motg->core_clk); + + return 0; +} + +static int msm_phy_init(struct usb_phy *phy) +{ + struct msm_otg *motg = container_of(phy, struct msm_otg, phy); + struct msm_otg_platform_data *pdata = motg->pdata; + u32 val, ulpi_val = 0; + + /* Program USB PHY Override registers. */ + ulpi_init(motg); + + /* + * It is recommended in HPG to reset USB PHY after programming + * USB PHY Override registers. + */ + msm_phy_reset(motg); if (pdata->otg_control == OTG_PHY_CONTROL) { val = readl(USB_OTGSC); @@ -1574,7 +1608,7 @@ static int msm_otg_probe(struct platform_device *pdev) goto disable_ldo; } - phy->init = msm_otg_reset; + phy->init = msm_phy_init; phy->set_power = msm_otg_set_power; phy->io_ops = &msm_otg_io_ops; @@ -1583,6 +1617,8 @@ static int msm_otg_probe(struct platform_device *pdev) phy->otg->set_host = msm_otg_set_host; phy->otg->set_peripheral = msm_otg_set_peripheral; + msm_usb_reset(phy); + ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2); if (ret) { dev_err(&pdev->dev, "usb_add_phy failed\n"); diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h index e6d7035..575c743 100644 --- a/include/linux/usb/msm_hsusb_hw.h +++ b/include/linux/usb/msm_hsusb_hw.h @@ -42,9 +42,14 @@ #define ULPI_DATA(n) ((n) & 255) #define ULPI_DATA_READ(n) (((n) >> 8) & 255) +/* synopsys 28nm phy registers */ +#define ULPI_PWR_CLK_MNG_REG 0x88 +#define OTG_COMP_DISABLE BIT(0) + #define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */ #define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */ #define PHY_RETEN (1 << 1) /* PHY retention enable/disable */ +#define PHY_POR_ASSERT (1 << 0) /* USB2 28nm PHY POR ASSERT */ /* OTG definitions */ #define OTGSC_INTSTS_MASK (0x7f << 16) -- cgit v0.10.2 From 9f27984b9e098ce0a35b210ec0315c76108494e4 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Mon, 28 Apr 2014 16:34:19 +0300 Subject: usb: phy: msm: Fix PTS definitions for MSM USB controller Fix the value used for Parallel Transceiver Select (PTS) for the MSM USB controller. This is a standard chipidea PORTSC definition, where a PHY_TYPE of 10b (<<30) is ULPI and 11b (<<30) is SERIAL. Fix the definitions and use them correctly in the driver code. Signed-off-by: Tim Bird Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index bb33996..db8d963 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -287,8 +287,9 @@ static int msm_link_reset(struct msm_otg *motg) if (motg->phy_number) writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); + /* put transceiver in serial mode as part of reset */ val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; - writel(val | PORTSC_PTS_ULPI, USB_PORTSC); + writel(val | PORTSC_PTS_SERIAL, USB_PORTSC); return 0; } @@ -308,8 +309,9 @@ static int msm_otg_reset(struct usb_phy *phy) if (cnt >= LINK_RESET_TIMEOUT_USEC) return -ETIMEDOUT; - /* select ULPI phy */ - writel(0x80000000, USB_PORTSC); + /* select ULPI phy and clear other status/control bits in PORTSC */ + writel(PORTSC_PTS_ULPI, USB_PORTSC); + writel(0x0, USB_AHBBURST); writel(0x08, USB_AHBMODE); diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h index 575c743..98d3dd8 100644 --- a/include/linux/usb/msm_hsusb_hw.h +++ b/include/linux/usb/msm_hsusb_hw.h @@ -31,8 +31,9 @@ #define USB_USBINTR (MSM_USB_BASE + 0x0148) #define PORTSC_PHCD (1 << 23) /* phy suspend mode */ -#define PORTSC_PTS_MASK (3 << 30) -#define PORTSC_PTS_ULPI (3 << 30) +#define PORTSC_PTS_MASK (3 << 30) +#define PORTSC_PTS_ULPI (2 << 30) +#define PORTSC_PTS_SERIAL (3 << 30) #define USB_ULPI_VIEWPORT (MSM_USB_BASE + 0x0170) #define ULPI_RUN (1 << 30) -- cgit v0.10.2 From 30bf8667cef5655ddfaedf043f13d03606844213 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Mon, 28 Apr 2014 16:34:20 +0300 Subject: usb: phy: msm: Select secondary PHY via TCSR Select the secondary PHY using the TCSR register, if phy-num=1 in the DTS (or phy_number is set in the platform data). The SOC has 2 PHYs which can be used with the OTG port, and this code allows configuring the correct one. Note: This resolves the problem I was seeing where I couldn't get the USB driver working at all on a dragonboard, from cold boot. This patch depends on patch 5/14 from Ivan's msm USB patch set. It does not use DT for the register address, as there's no evidence that this address changes between SoC versions. Signed-off-by: Tim Bird Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index db8d963..9437bcf 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1489,6 +1489,7 @@ static int msm_otg_probe(struct platform_device *pdev) struct resource *res; struct msm_otg *motg; struct usb_phy *phy; + void __iomem *phy_select; motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL); if (!motg) { @@ -1553,6 +1554,19 @@ static int msm_otg_probe(struct platform_device *pdev) if (IS_ERR(motg->regs)) return PTR_ERR(motg->regs); + /* + * NOTE: The PHYs can be multiplexed between the chipidea controller + * and the dwc3 controller, using a single bit. It is important that + * the dwc3 driver does not set this bit in an incompatible way. + */ + if (motg->phy_number) { + phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4); + if (IS_ERR(phy_select)) + return PTR_ERR(phy_select); + /* Enable second PHY with the OTG port */ + writel_relaxed(0x1, phy_select); + } + dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs); motg->irq = platform_get_irq(pdev, 0); diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h index 98d3dd8..a29f603 100644 --- a/include/linux/usb/msm_hsusb_hw.h +++ b/include/linux/usb/msm_hsusb_hw.h @@ -16,6 +16,9 @@ #ifndef __LINUX_USB_GADGET_MSM72K_UDC_H__ #define __LINUX_USB_GADGET_MSM72K_UDC_H__ +/* USB phy selector - in TCSR address range */ +#define USB2_PHY_SEL 0xfd4ab000 + #define USB_AHBBURST (MSM_USB_BASE + 0x0090) #define USB_AHBMODE (MSM_USB_BASE + 0x0098) #define USB_CAPLENGTH (MSM_USB_BASE + 0x0100) /* 8 bit */ -- cgit v0.10.2 From 349907c262ad5e698c24565658ae489fb69fee53 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:21 +0300 Subject: usb: phy: msm: Handle disconnect events Put the transceiver in non-driving mode. Otherwise host may not detect soft-disconnection. Signed-off-by: Ivan T. Ivanov Cc: Pavankumar Kondeti Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 9437bcf..366527e 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -235,6 +235,23 @@ static void ulpi_init(struct msm_otg *motg) } } +static int msm_phy_notify_disconnect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + int val; + + /* + * Put the transceiver in non-driving mode. Otherwise host + * may not detect soft-disconnection. + */ + val = ulpi_read(phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; + ulpi_write(phy, val, ULPI_FUNC_CTRL); + + return 0; +} + static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) { int ret; @@ -1626,6 +1643,7 @@ static int msm_otg_probe(struct platform_device *pdev) phy->init = msm_phy_init; phy->set_power = msm_otg_set_power; + phy->notify_disconnect = msm_phy_notify_disconnect; phy->io_ops = &msm_otg_io_ops; -- cgit v0.10.2 From 01799b622217ffebdc95e8e0aedbd4cff6a35a50 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:22 +0300 Subject: usb: phy: msm: Vote for corner of VDD CX instead of voltage of VDD CX New platform uses RBCPR hardware feature, with that voting for absolute voltage of VDD CX is not required. Hence vote for corner of VDD CX which uses nominal corner voltage on VDD CX. Signed-off-by: Ivan T. Ivanov Cc: Mayank Rana Signed-off-by: Felipe Balbi diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index 0669667..2826f2a 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -65,6 +65,10 @@ Optional properties: Some platforms may have configuration to allow USB controller work with any of the two HSPHYs present. +- qcom,vdd-levels: This property must be a list of three integer values + (no, min, max) where each value represents either a voltage + in microvolts or a value corresponding to voltage corner. + Example HSUSB OTG controller device node: usb@f9a55000 { @@ -87,4 +91,5 @@ Example HSUSB OTG controller device node: qcom,otg-control = <1>; qcom,phy-init-sequence = < -1 0x63 >; + qcom,vdd-levels = <1 5 7>; }; diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 366527e..8e7956e 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -62,6 +62,13 @@ #define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */ #define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */ +#define USB_PHY_SUSP_DIG_VOL 500000 /* uV */ + +enum vdd_levels { + VDD_LEVEL_NONE = 0, + VDD_LEVEL_MIN, + VDD_LEVEL_MAX, +}; static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) { @@ -69,8 +76,8 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) if (init) { ret = regulator_set_voltage(motg->vddcx, - USB_PHY_VDD_DIG_VOL_MIN, - USB_PHY_VDD_DIG_VOL_MAX); + motg->vdd_levels[VDD_LEVEL_MIN], + motg->vdd_levels[VDD_LEVEL_MAX]); if (ret) { dev_err(motg->phy.dev, "Cannot set vddcx voltage\n"); return ret; @@ -81,7 +88,7 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n"); } else { ret = regulator_set_voltage(motg->vddcx, 0, - USB_PHY_VDD_DIG_VOL_MAX); + motg->vdd_levels[VDD_LEVEL_MAX]); if (ret) dev_err(motg->phy.dev, "Cannot set vddcx voltage\n"); ret = regulator_disable(motg->vddcx); @@ -435,17 +442,16 @@ static int msm_phy_init(struct usb_phy *phy) #ifdef CONFIG_PM -#define USB_PHY_SUSP_DIG_VOL 500000 static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high) { - int max_vol = USB_PHY_VDD_DIG_VOL_MAX; + int max_vol = motg->vdd_levels[VDD_LEVEL_MAX]; int min_vol; int ret; if (high) - min_vol = USB_PHY_VDD_DIG_VOL_MIN; + min_vol = motg->vdd_levels[VDD_LEVEL_MIN]; else - min_vol = USB_PHY_SUSP_DIG_VOL; + min_vol = motg->vdd_levels[VDD_LEVEL_NONE]; ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol); if (ret) { @@ -1441,7 +1447,7 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) struct device_node *node = pdev->dev.of_node; struct property *prop; int len, ret, words; - u32 val; + u32 val, tmp[3]; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -1472,6 +1478,19 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) if (!of_property_read_u32(node, "qcom,phy-num", &val) && val < 2) motg->phy_number = val; + motg->vdd_levels[VDD_LEVEL_NONE] = USB_PHY_SUSP_DIG_VOL; + motg->vdd_levels[VDD_LEVEL_MIN] = USB_PHY_VDD_DIG_VOL_MIN; + motg->vdd_levels[VDD_LEVEL_MAX] = USB_PHY_VDD_DIG_VOL_MAX; + + if (of_get_property(node, "qcom,vdd-levels", &len) && + len == sizeof(tmp)) { + of_property_read_u32_array(node, "qcom,vdd-levels", + tmp, len / sizeof(*tmp)); + motg->vdd_levels[VDD_LEVEL_NONE] = tmp[VDD_LEVEL_NONE]; + motg->vdd_levels[VDD_LEVEL_MIN] = tmp[VDD_LEVEL_MIN]; + motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX]; + } + prop = of_find_property(node, "qcom,phy-init-sequence", &len); if (!prop || !len) return 0; diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 4628f1a..b0a3924 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -169,6 +169,7 @@ struct msm_otg { struct reset_control *phy_rst; struct reset_control *link_rst; + int vdd_levels[3]; }; #endif -- cgit v0.10.2 From e695abb3c8b1b758843a1db2a73c98b3d14c173a Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Mon, 28 Apr 2014 16:34:23 +0300 Subject: usb: phy: msm: Use usb_add_phy_dev() to register device There could be more than one USB2.0 PHY's on the platform. This will allow all of them to be registered successfully. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 8e7956e..9dc7918 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1663,6 +1663,7 @@ static int msm_otg_probe(struct platform_device *pdev) phy->init = msm_phy_init; phy->set_power = msm_otg_set_power; phy->notify_disconnect = msm_phy_notify_disconnect; + phy->type = USB_PHY_TYPE_USB2; phy->io_ops = &msm_otg_io_ops; @@ -1672,7 +1673,7 @@ static int msm_otg_probe(struct platform_device *pdev) msm_usb_reset(phy); - ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2); + ret = usb_add_phy_dev(&motg->phy); if (ret) { dev_err(&pdev->dev, "usb_add_phy failed\n"); goto disable_ldo; -- cgit v0.10.2 From b3025e6ada454848b6ae2d3bcd925738384517df Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 30 Apr 2014 11:33:04 -0500 Subject: usb: phy: msm: cast to enum msm_usb_phy_type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this solves the following build warning found when running compile tests. drivers/usb/phy/phy-msm-usb.c: In function ‘msm_otg_read_dt’: drivers/usb/phy/phy-msm-usb.c:1459:20: warning: cast from pointer \ to integer of different size [-Wpointer-to-int-cast] pdata->phy_type = (int) id->data; ^ Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 9dc7918..591b406 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1456,7 +1456,7 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) motg->pdata = pdata; id = of_match_device(msm_otg_dt_match, &pdev->dev); - pdata->phy_type = (int) id->data; + pdata->phy_type = (enum msm_usb_phy_type) id->data; motg->link_rst = devm_reset_control_get(&pdev->dev, "link"); if (IS_ERR(motg->link_rst)) -- cgit v0.10.2 From 245974908c2ee8cd907856e6964f59fd8807e1e1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 30 Apr 2014 11:35:22 -0500 Subject: usb: phy: msm: switch over to writel() Remove that single instance of writel_relaxed() call which is only available on ARM architecture. This will let us build test this driver on all different architectures. Reviewed-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 591b406..c522c4f 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1600,7 +1600,7 @@ static int msm_otg_probe(struct platform_device *pdev) if (IS_ERR(phy_select)) return PTR_ERR(phy_select); /* Enable second PHY with the OTG port */ - writel_relaxed(0x1, phy_select); + writel(0x1, phy_select); } dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs); -- cgit v0.10.2 From 1f7fc40876934d52278bb1ee0544191a4b4657f1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 30 Apr 2014 11:36:03 -0500 Subject: usb: phy: msm: enable build on other architectures By adding COMPILE_TEST to the list of dependencies we can build test this driver on all other architectures which is very valuable for maintainers applying patches and to find silly mistakes during development. Reviewed-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 0c668a3..fbbced8 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -172,7 +172,7 @@ config USB_ISP1301 config USB_MSM_OTG tristate "Qualcomm on-chip USB OTG controller support" - depends on (USB || USB_GADGET) && (ARCH_MSM || ARCH_QCOM) + depends on (USB || USB_GADGET) && (ARCH_MSM || ARCH_QCOM || COMPILE_TEST) select USB_PHY help Enable this to support the USB OTG transceiver on Qualcomm chips. It -- cgit v0.10.2 From 6027f3173e797bf27fc5053aa74c9f40f85538d8 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 29 Apr 2014 13:26:28 +0800 Subject: usb: gadget: set gadget state as configured Set gadget device state as configurated after set configuration has finished. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index fab9064..8060de6 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -634,6 +634,7 @@ static int set_config(struct usb_composite_dev *cdev, if (!c) goto done; + usb_gadget_set_state(gadget, USB_STATE_CONFIGURED); cdev->config = c; /* Initialize all interfaces by setting them to altsetting zero. */ diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index b5be6f03..09e2151 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1494,6 +1494,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) */ if (value == 0) { INFO (dev, "configuration #%d\n", dev->current_config); + usb_gadget_set_state(gadget, USB_STATE_CONFIGURED); if (dev->usermode_setup) { dev->setup_can_stall = 0; goto delegate; -- cgit v0.10.2 From b5fb8d0a40eb52039e8df6fadafa95ecdcdc3026 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 29 Apr 2014 13:26:29 +0800 Subject: usb: udc-core: set gadget state as not attached after unloading module Set gadget state as "not attached" after unloading gadget module, or its state will be unchanged after we unload gadget module. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 27768a7..b0d9817 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -428,6 +428,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) list_for_each_entry(udc, &udc_list, list) if (udc->driver == driver) { usb_gadget_remove_driver(udc); + usb_gadget_set_state(udc->gadget, + USB_STATE_NOTATTACHED); ret = 0; break; } -- cgit v0.10.2 From 60b6dbeffb8c253d1f80527b28611e5e236dec51 Mon Sep 17 00:00:00 2001 From: Apelete Seketeli Date: Mon, 14 Apr 2014 22:12:56 +0200 Subject: documentation: docbook: document process of writing an musb glue layer Document the process of writing an musb glue layer by taking the Ingenic JZ4740 glue layer as an example, as it seems more simple than most glue layers due to the basic feature set of the JZ4740 USB device controller. Signed-off-by: Apelete Seketeli Signed-off-by: Felipe Balbi diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index b444f2e..bec0665 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -14,7 +14,8 @@ DOCBOOKS := z8530book.xml device-drivers.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ 80211.xml debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ - tracepoint.xml drm.xml media_api.xml w1.xml + tracepoint.xml drm.xml media_api.xml w1.xml \ + writing_musb_glue_layer.xml include Documentation/DocBook/media/Makefile diff --git a/Documentation/DocBook/writing_musb_glue_layer.tmpl b/Documentation/DocBook/writing_musb_glue_layer.tmpl new file mode 100644 index 0000000..837eca7 --- /dev/null +++ b/Documentation/DocBook/writing_musb_glue_layer.tmpl @@ -0,0 +1,873 @@ + + + + + + Writing an MUSB Glue Layer + + + + Apelete + Seketeli + +
+ apelete at seketeli.net +
+
+
+
+ + + 2014 + Apelete Seketeli + + + + + This documentation is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + + + This documentation is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public License + along with this documentation; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA + + + + For more details see the file COPYING in the Linux kernel source + tree. + + +
+ + + + + Introduction + + The Linux MUSB subsystem is part of the larger Linux USB + subsystem. It provides support for embedded USB Device Controllers + (UDC) that do not use Universal Host Controller Interface (UHCI) + or Open Host Controller Interface (OHCI). + + + Instead, these embedded UDC rely on the USB On-the-Go (OTG) + specification which they implement at least partially. The silicon + reference design used in most cases is the Multipoint USB + Highspeed Dual-Role Controller (MUSB HDRC) found in the Mentor + Graphics Inventra™ design. + + + As a self-taught exercise I have written an MUSB glue layer for + the Ingenic JZ4740 SoC, modelled after the many MUSB glue layers + in the kernel source tree. This layer can be found at + drivers/usb/musb/jz4740.c. In this documentation I will walk + through the basics of the jz4740.c glue layer, explaining the + different pieces and what needs to be done in order to write your + own device glue layer. + + + + + Linux MUSB Basics + + To get started on the topic, please read USB On-the-Go Basics (see + Resources) which provides an introduction of USB OTG operation at + the hardware level. A couple of wiki pages by Texas Instruments + and Analog Devices also provide an overview of the Linux kernel + MUSB configuration, albeit focused on some specific devices + provided by these companies. Finally, getting acquainted with the + USB specification at USB home page may come in handy, with + practical instance provided through the Writing USB Device Drivers + documentation (again, see Resources). + + + Linux USB stack is a layered architecture in which the MUSB + controller hardware sits at the lowest. The MUSB controller driver + abstract the MUSB controller hardware to the Linux USB stack. + + + ------------------------ + | | <------- drivers/usb/gadget + | Linux USB Core Stack | <------- drivers/usb/host + | | <------- drivers/usb/core + ------------------------ + ⬍ + -------------------------- + | | <------ drivers/usb/musb/musb_gadget.c + | MUSB Controller driver | <------ drivers/usb/musb/musb_host.c + | | <------ drivers/usb/musb/musb_core.c + -------------------------- + ⬍ + --------------------------------- + | MUSB Platform Specific Driver | + | | <-- drivers/usb/musb/jz4740.c + | aka "Glue Layer" | + --------------------------------- + ⬍ + --------------------------------- + | MUSB Controller Hardware | + --------------------------------- + + + As outlined above, the glue layer is actually the platform + specific code sitting in between the controller driver and the + controller hardware. + + + Just like a Linux USB driver needs to register itself with the + Linux USB subsystem, the MUSB glue layer needs first to register + itself with the MUSB controller driver. This will allow the + controller driver to know about which device the glue layer + supports and which functions to call when a supported device is + detected or released; remember we are talking about an embedded + controller chip here, so no insertion or removal at run-time. + + + All of this information is passed to the MUSB controller driver + through a platform_driver structure defined in the glue layer as: + + +static struct platform_driver jz4740_driver = { + .probe = jz4740_probe, + .remove = jz4740_remove, + .driver = { + .name = "musb-jz4740", + }, +}; + + + The probe and remove function pointers are called when a matching + device is detected and, respectively, released. The name string + describes the device supported by this glue layer. In the current + case it matches a platform_device structure declared in + arch/mips/jz4740/platform.c. Note that we are not using device + tree bindings here. + + + In order to register itself to the controller driver, the glue + layer goes through a few steps, basically allocating the + controller hardware resources and initialising a couple of + circuits. To do so, it needs to keep track of the information used + throughout these steps. This is done by defining a private + jz4740_glue structure: + + +struct jz4740_glue { + struct device *dev; + struct platform_device *musb; + struct clk *clk; +}; + + + The dev and musb members are both device structure variables. The + first one holds generic information about the device, since it's + the basic device structure, and the latter holds information more + closely related to the subsystem the device is registered to. The + clk variable keeps information related to the device clock + operation. + + + Let's go through the steps of the probe function that leads the + glue layer to register itself to the controller driver. + + + N.B.: For the sake of readability each function will be split in + logical parts, each part being shown as if it was independent from + the others. + + +static int jz4740_probe(struct platform_device *pdev) +{ + struct platform_device *musb; + struct jz4740_glue *glue; + struct clk *clk; + int ret; + + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); + if (!musb) { + dev_err(&pdev->dev, "failed to allocate musb device\n"); + return -ENOMEM; + } + + clk = devm_clk_get(&pdev->dev, "udc"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(clk); + goto err_platform_device_put; + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock\n"); + goto err_platform_device_put; + } + + musb->dev.parent = &pdev->dev; + + glue->dev = &pdev->dev; + glue->musb = musb; + glue->clk = clk; + + return 0; + +err_platform_device_put: + platform_device_put(musb); + return ret; +} + + + The first few lines of the probe function allocate and assign the + glue, musb and clk variables. The GFP_KERNEL flag (line 8) allows + the allocation process to sleep and wait for memory, thus being + usable in a blocking situation. The PLATFORM_DEVID_AUTO flag (line + 12) allows automatic allocation and management of device IDs in + order to avoid device namespace collisions with explicit IDs. With + devm_clk_get() (line 18) the glue layer allocates the clock -- the + devm_ prefix indicates that clk_get() is + managed: it automatically frees the allocated clock resource data + when the device is released -- and enable it. + + + Then comes the registration steps: + + +static int jz4740_probe(struct platform_device *pdev) +{ + struct musb_hdrc_platform_data *pdata = &jz4740_musb_platform_data; + + pdata->platform_ops = &jz4740_musb_ops; + + platform_set_drvdata(pdev, glue); + + ret = platform_device_add_resources(musb, pdev->resource, + pdev->num_resources); + if (ret) { + dev_err(&pdev->dev, "failed to add resources\n"); + goto err_clk_disable; + } + + ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); + if (ret) { + dev_err(&pdev->dev, "failed to add platform_data\n"); + goto err_clk_disable; + } + + return 0; + +err_clk_disable: + clk_disable_unprepare(clk); +err_platform_device_put: + platform_device_put(musb); + return ret; +} + + + The first step is to pass the device data privately held by the + glue layer on to the controller driver through + platform_set_drvdata() (line 7). Next is passing on the device + resources information, also privately held at that point, through + platform_device_add_resources() (line 9). + + + Finally comes passing on the platform specific data to the + controller driver (line 16). Platform data will be discussed in + Chapter 4, but here + we are looking at the platform_ops function pointer (line 5) in + musb_hdrc_platform_data structure (line 3). This function + pointer allows the MUSB controller driver to know which function + to call for device operation: + + +static const struct musb_platform_ops jz4740_musb_ops = { + .init = jz4740_musb_init, + .exit = jz4740_musb_exit, +}; + + + Here we have the minimal case where only init and exit functions + are called by the controller driver when needed. Fact is the + JZ4740 MUSB controller is a basic controller, lacking some + features found in other controllers, otherwise we may also have + pointers to a few other functions like a power management function + or a function to switch between OTG and non-OTG modes, for + instance. + + + At that point of the registration process, the controller driver + actually calls the init function: + + +static int jz4740_musb_init(struct musb *musb) +{ + musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); + if (!musb->xceiv) { + pr_err("HS UDC: no transceiver configured\n"); + return -ENODEV; + } + + /* Silicon does not implement ConfigData register. + * Set dyn_fifo to avoid reading EP config from hardware. + */ + musb->dyn_fifo = true; + + musb->isr = jz4740_musb_interrupt; + + return 0; +} + + + The goal of jz4740_musb_init() is to get hold of the transceiver + driver data of the MUSB controller hardware and pass it on to the + MUSB controller driver, as usual. The transceiver is the circuitry + inside the controller hardware responsible for sending/receiving + the USB data. Since it is an implementation of the physical layer + of the OSI model, the transceiver is also referred to as PHY. + + + Getting hold of the MUSB PHY driver data is done with + usb_get_phy() which returns a pointer to the structure + containing the driver instance data. The next couple of + instructions (line 12 and 14) are used as a quirk and to setup + IRQ handling respectively. Quirks and IRQ handling will be + discussed later in Chapter + 5 and Chapter 3. + + +static int jz4740_musb_exit(struct musb *musb) +{ + usb_put_phy(musb->xceiv); + + return 0; +} + + + Acting as the counterpart of init, the exit function releases the + MUSB PHY driver when the controller hardware itself is about to be + released. + + + Again, note that init and exit are fairly simple in this case due + to the basic set of features of the JZ4740 controller hardware. + When writing an musb glue layer for a more complex controller + hardware, you might need to take care of more processing in those + two functions. + + + Returning from the init function, the MUSB controller driver jumps + back into the probe function: + + +static int jz4740_probe(struct platform_device *pdev) +{ + ret = platform_device_add(musb); + if (ret) { + dev_err(&pdev->dev, "failed to register musb device\n"); + goto err_clk_disable; + } + + return 0; + +err_clk_disable: + clk_disable_unprepare(clk); +err_platform_device_put: + platform_device_put(musb); + return ret; +} + + + This is the last part of the device registration process where the + glue layer adds the controller hardware device to Linux kernel + device hierarchy: at this stage, all known information about the + device is passed on to the Linux USB core stack. + + +static int jz4740_remove(struct platform_device *pdev) +{ + struct jz4740_glue *glue = platform_get_drvdata(pdev); + + platform_device_unregister(glue->musb); + clk_disable_unprepare(glue->clk); + + return 0; +} + + + Acting as the counterpart of probe, the remove function unregister + the MUSB controller hardware (line 5) and disable the clock (line + 6), allowing it to be gated. + + + + + Handling IRQs + + Additionally to the MUSB controller hardware basic setup and + registration, the glue layer is also responsible for handling the + IRQs: + + +static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + /* + * The controller is gadget only, the state of the host mode IRQ bits is + * undefined. Mask them to make sure that the musb driver core will + * never see them set + */ + musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME | + MUSB_INTR_RESET | MUSB_INTR_SOF; + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return retval; +} + + + Here the glue layer mostly has to read the relevant hardware + registers and pass their values on to the controller driver which + will handle the actual event that triggered the IRQ. + + + The interrupt handler critical section is protected by the + spin_lock_irqsave() and counterpart spin_unlock_irqrestore() + functions (line 7 and 24 respectively), which prevent the + interrupt handler code to be run by two different threads at the + same time. + + + Then the relevant interrupt registers are read (line 9 to 11): + + + + + MUSB_INTRUSB: indicates which USB interrupts are currently + active, + + + + + MUSB_INTRTX: indicates which of the interrupts for TX + endpoints are currently active, + + + + + MUSB_INTRRX: indicates which of the interrupts for TX + endpoints are currently active. + + + + + Note that musb_readb() is used to read 8-bit registers at most, + while musb_readw() allows us to read at most 16-bit registers. + There are other functions that can be used depending on the size + of your device registers. See musb_io.h for more information. + + + Instruction on line 18 is another quirk specific to the JZ4740 + USB device controller, which will be discussed later in Chapter 5. + + + The glue layer still needs to register the IRQ handler though. + Remember the instruction on line 14 of the init function: + + +static int jz4740_musb_init(struct musb *musb) +{ + musb->isr = jz4740_musb_interrupt; + + return 0; +} + + + This instruction sets a pointer to the glue layer IRQ handler + function, in order for the controller hardware to call the handler + back when an IRQ comes from the controller hardware. The interrupt + handler is now implemented and registered. + + + + + Device Platform Data + + In order to write an MUSB glue layer, you need to have some data + describing the hardware capabilities of your controller hardware, + which is called the platform data. + + + Platform data is specific to your hardware, though it may cover a + broad range of devices, and is generally found somewhere in the + arch/ directory, depending on your device architecture. + + + For instance, platform data for the JZ4740 SoC is found in + arch/mips/jz4740/platform.c. In the platform.c file each device of + the JZ4740 SoC is described through a set of structures. + + + Here is the part of arch/mips/jz4740/platform.c that covers the + USB Device Controller (UDC): + + +/* USB Device Controller */ +struct platform_device jz4740_udc_xceiv_device = { + .name = "usb_phy_gen_xceiv", + .id = 0, +}; + +static struct resource jz4740_udc_resources[] = { + [0] = { + .start = JZ4740_UDC_BASE_ADDR, + .end = JZ4740_UDC_BASE_ADDR + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = JZ4740_IRQ_UDC, + .end = JZ4740_IRQ_UDC, + .flags = IORESOURCE_IRQ, + .name = "mc", + }, +}; + +struct platform_device jz4740_udc_device = { + .name = "musb-jz4740", + .id = -1, + .dev = { + .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(jz4740_udc_resources), + .resource = jz4740_udc_resources, +}; + + + The jz4740_udc_xceiv_device platform device structure (line 2) + describes the UDC transceiver with a name and id number. + + + At the time of this writing, note that + "usb_phy_gen_xceiv" is the specific name to be used for + all transceivers that are either built-in with reference USB IP or + autonomous and doesn't require any PHY programming. You will need + to set CONFIG_NOP_USB_XCEIV=y in the kernel configuration to make + use of the corresponding transceiver driver. The id field could be + set to -1 (equivalent to PLATFORM_DEVID_NONE), -2 (equivalent to + PLATFORM_DEVID_AUTO) or start with 0 for the first device of this + kind if we want a specific id number. + + + The jz4740_udc_resources resource structure (line 7) defines the + UDC registers base addresses. + + + The first array (line 9 to 11) defines the UDC registers base + memory addresses: start points to the first register memory + address, end points to the last register memory address and the + flags member defines the type of resource we are dealing with. So + IORESOURCE_MEM is used to define the registers memory addresses. + The second array (line 14 to 17) defines the UDC IRQ registers + addresses. Since there is only one IRQ register available for the + JZ4740 UDC, start and end point at the same address. The + IORESOURCE_IRQ flag tells that we are dealing with IRQ resources, + and the name "mc" is in fact hard-coded in the MUSB core + in order for the controller driver to retrieve this IRQ resource + by querying it by its name. + + + Finally, the jz4740_udc_device platform device structure (line 21) + describes the UDC itself. + + + The "musb-jz4740" name (line 22) defines the MUSB + driver that is used for this device; remember this is in fact + the name that we used in the jz4740_driver platform driver + structure in Chapter + 2. The id field (line 23) is set to -1 (equivalent to + PLATFORM_DEVID_NONE) since we do not need an id for the device: + the MUSB controller driver was already set to allocate an + automatic id in Chapter + 2. In the dev field we care for DMA related information + here. The dma_mask field (line 25) defines the width of the DMA + mask that is going to be used, and coherent_dma_mask (line 26) + has the same purpose but for the alloc_coherent DMA mappings: in + both cases we are using a 32 bits mask. Then the resource field + (line 29) is simply a pointer to the resource structure defined + before, while the num_resources field (line 28) keeps track of + the number of arrays defined in the resource structure (in this + case there were two resource arrays defined before). + + + With this quick overview of the UDC platform data at the arch/ + level now done, let's get back to the MUSB glue layer specific + platform data in drivers/usb/musb/jz4740.c: + + +static struct musb_hdrc_config jz4740_musb_config = { + /* Silicon does not implement USB OTG. */ + .multipoint = 0, + /* Max EPs scanned, driver will decide which EP can be used. */ + .num_eps = 4, + /* RAMbits needed to configure EPs from table */ + .ram_bits = 9, + .fifo_cfg = jz4740_musb_fifo_cfg, + .fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg), +}; + +static struct musb_hdrc_platform_data jz4740_musb_platform_data = { + .mode = MUSB_PERIPHERAL, + .config = &jz4740_musb_config, +}; + + + First the glue layer configures some aspects of the controller + driver operation related to the controller hardware specifics. + This is done through the jz4740_musb_config musb_hdrc_config + structure. + + + Defining the OTG capability of the controller hardware, the + multipoint member (line 3) is set to 0 (equivalent to false) + since the JZ4740 UDC is not OTG compatible. Then num_eps (line + 5) defines the number of USB endpoints of the controller + hardware, including endpoint 0: here we have 3 endpoints + + endpoint 0. Next is ram_bits (line 7) which is the width of the + RAM address bus for the MUSB controller hardware. This + information is needed when the controller driver cannot + automatically configure endpoints by reading the relevant + controller hardware registers. This issue will be discussed when + we get to device quirks in Chapter + 5. Last two fields (line 8 and 9) are also about device + quirks: fifo_cfg points to the USB endpoints configuration table + and fifo_cfg_size keeps track of the size of the number of + entries in that configuration table. More on that later in Chapter 5. + + + Then this configuration is embedded inside + jz4740_musb_platform_data musb_hdrc_platform_data structure (line + 11): config is a pointer to the configuration structure itself, + and mode tells the controller driver if the controller hardware + may be used as MUSB_HOST only, MUSB_PERIPHERAL only or MUSB_OTG + which is a dual mode. + + + Remember that jz4740_musb_platform_data is then used to convey + platform data information as we have seen in the probe function + in Chapter 2 + + + + + Device Quirks + + Completing the platform data specific to your device, you may also + need to write some code in the glue layer to work around some + device specific limitations. These quirks may be due to some + hardware bugs, or simply be the result of an incomplete + implementation of the USB On-the-Go specification. + + + The JZ4740 UDC exhibits such quirks, some of which we will discuss + here for the sake of insight even though these might not be found + in the controller hardware you are working on. + + + Let's get back to the init function first: + + +static int jz4740_musb_init(struct musb *musb) +{ + musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); + if (!musb->xceiv) { + pr_err("HS UDC: no transceiver configured\n"); + return -ENODEV; + } + + /* Silicon does not implement ConfigData register. + * Set dyn_fifo to avoid reading EP config from hardware. + */ + musb->dyn_fifo = true; + + musb->isr = jz4740_musb_interrupt; + + return 0; +} + + + Instruction on line 12 helps the MUSB controller driver to work + around the fact that the controller hardware is missing registers + that are used for USB endpoints configuration. + + + Without these registers, the controller driver is unable to read + the endpoints configuration from the hardware, so we use line 12 + instruction to bypass reading the configuration from silicon, and + rely on a hard-coded table that describes the endpoints + configuration instead: + + +static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, +}; + + + Looking at the configuration table above, we see that each + endpoints is described by three fields: hw_ep_num is the endpoint + number, style is its direction (either FIFO_TX for the controller + driver to send packets in the controller hardware, or FIFO_RX to + receive packets from hardware), and maxpacket defines the maximum + size of each data packet that can be transmitted over that + endpoint. Reading from the table, the controller driver knows that + endpoint 1 can be used to send and receive USB data packets of 512 + bytes at once (this is in fact a bulk in/out endpoint), and + endpoint 2 can be used to send data packets of 64 bytes at once + (this is in fact an interrupt endpoint). + + + Note that there is no information about endpoint 0 here: that one + is implemented by default in every silicon design, with a + predefined configuration according to the USB specification. For + more examples of endpoint configuration tables, see musb_core.c. + + + Let's now get back to the interrupt handler function: + + +static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + /* + * The controller is gadget only, the state of the host mode IRQ bits is + * undefined. Mask them to make sure that the musb driver core will + * never see them set + */ + musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME | + MUSB_INTR_RESET | MUSB_INTR_SOF; + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return retval; +} + + + Instruction on line 18 above is a way for the controller driver to + work around the fact that some interrupt bits used for USB host + mode operation are missing in the MUSB_INTRUSB register, thus left + in an undefined hardware state, since this MUSB controller + hardware is used in peripheral mode only. As a consequence, the + glue layer masks these missing bits out to avoid parasite + interrupts by doing a logical AND operation between the value read + from MUSB_INTRUSB and the bits that are actually implemented in + the register. + + + These are only a couple of the quirks found in the JZ4740 USB + device controller. Some others were directly addressed in the MUSB + core since the fixes were generic enough to provide a better + handling of the issues for others controller hardware eventually. + + + + + Conclusion + + Writing a Linux MUSB glue layer should be a more accessible task, + as this documentation tries to show the ins and outs of this + exercise. + + + The JZ4740 USB device controller being fairly simple, I hope its + glue layer serves as a good example for the curious mind. Used + with the current MUSB glue layers, this documentation should + provide enough guidance to get started; should anything gets out + of hand, the linux-usb mailing list archive is another helpful + resource to browse through. + + + + + Acknowledgements + + Many thanks to Lars-Peter Clausen and Maarten ter Huurne for + answering my questions while I was writing the JZ4740 glue layer + and for helping me out getting the code in good shape. + + + I would also like to thank the Qi-Hardware community at large for + its cheerful guidance and support. + + + + + Resources + + USB Home Page: + http://www.usb.org + + + linux-usb Mailing List Archives: + http://marc.info/?l=linux-usb + + + USB On-the-Go Basics: + http://www.maximintegrated.com/app-notes/index.mvp/id/1822 + + + Writing USB Device Drivers: + https://www.kernel.org/doc/htmldocs/writing_usb_driver/index.html + + + Texas Instruments USB Configuration Wiki Page: + http://processors.wiki.ti.com/index.php/Usbgeneralpage + + + Analog Devices Blackfin MUSB Configuration: + http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:drivers:musb + + + +
-- cgit v0.10.2 From b34e08d5c7062c19a3f582d23d5f649c79ff3409 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 11 Feb 2014 11:43:03 +0100 Subject: tools: usb: aio example applications This patch adds two example applications showing usage of Asynchronous I/O API of FunctionFS. First one (aio_simple) is simple example of bidirectional data transfer. Second one (aio_multibuff) shows multi-buffer data transfer, which may to be used in high performance applications. Both examples contains userspace applications for device and for host. It needs libaio library on the device, and libusb library on host. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi diff --git a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c new file mode 100644 index 0000000..87216a0 --- /dev/null +++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c @@ -0,0 +1,349 @@ +#define _BSD_SOURCE /* for endian.h */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libaio.h" +#define IOCB_FLAG_RESFD (1 << 0) + +#include + +#define BUF_LEN 8192 +#define BUFS_MAX 128 +#define AIO_MAX (BUFS_MAX*2) + +/******************** Descriptors and Strings *******************************/ + +static const struct { + struct usb_functionfs_descs_head header; + struct { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio bulk_sink; + struct usb_endpoint_descriptor_no_audio bulk_source; + } __attribute__ ((__packed__)) fs_descs, hs_descs; +} __attribute__ ((__packed__)) descriptors = { + .header = { + .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), + .length = htole32(sizeof(descriptors)), + .fs_count = 3, + .hs_count = 3, + }, + .fs_descs = { + .intf = { + .bLength = sizeof(descriptors.fs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = 1, + }, + .bulk_sink = { + .bLength = sizeof(descriptors.fs_descs.bulk_sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + .bulk_source = { + .bLength = sizeof(descriptors.fs_descs.bulk_source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + }, + .hs_descs = { + .intf = { + .bLength = sizeof(descriptors.hs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = 1, + }, + .bulk_sink = { + .bLength = sizeof(descriptors.hs_descs.bulk_sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = htole16(512), + }, + .bulk_source = { + .bLength = sizeof(descriptors.hs_descs.bulk_source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = htole16(512), + }, + }, +}; + +#define STR_INTERFACE "AIO Test" + +static const struct { + struct usb_functionfs_strings_head header; + struct { + __le16 code; + const char str1[sizeof(STR_INTERFACE)]; + } __attribute__ ((__packed__)) lang0; +} __attribute__ ((__packed__)) strings = { + .header = { + .magic = htole32(FUNCTIONFS_STRINGS_MAGIC), + .length = htole32(sizeof(strings)), + .str_count = htole32(1), + .lang_count = htole32(1), + }, + .lang0 = { + htole16(0x0409), /* en-us */ + STR_INTERFACE, + }, +}; + +/********************** Buffer structure *******************************/ + +struct io_buffer { + struct iocb **iocb; + unsigned char **buf; + unsigned cnt; + unsigned len; + unsigned requested; +}; + +/******************** Endpoints handling *******************************/ + +static void display_event(struct usb_functionfs_event *event) +{ + static const char *const names[] = { + [FUNCTIONFS_BIND] = "BIND", + [FUNCTIONFS_UNBIND] = "UNBIND", + [FUNCTIONFS_ENABLE] = "ENABLE", + [FUNCTIONFS_DISABLE] = "DISABLE", + [FUNCTIONFS_SETUP] = "SETUP", + [FUNCTIONFS_SUSPEND] = "SUSPEND", + [FUNCTIONFS_RESUME] = "RESUME", + }; + switch (event->type) { + case FUNCTIONFS_BIND: + case FUNCTIONFS_UNBIND: + case FUNCTIONFS_ENABLE: + case FUNCTIONFS_DISABLE: + case FUNCTIONFS_SETUP: + case FUNCTIONFS_SUSPEND: + case FUNCTIONFS_RESUME: + printf("Event %s\n", names[event->type]); + } +} + +static void handle_ep0(int ep0, bool *ready) +{ + int ret; + struct usb_functionfs_event event; + + ret = read(ep0, &event, sizeof(event)); + if (!ret) { + perror("unable to read event from ep0"); + return; + } + display_event(&event); + switch (event.type) { + case FUNCTIONFS_SETUP: + if (event.u.setup.bRequestType & USB_DIR_IN) + write(ep0, NULL, 0); + else + read(ep0, NULL, 0); + break; + + case FUNCTIONFS_ENABLE: + *ready = true; + break; + + case FUNCTIONFS_DISABLE: + *ready = false; + break; + + default: + break; + } +} + +void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len) +{ + unsigned i; + iobuf->buf = malloc(n*sizeof(*iobuf->buf)); + iobuf->iocb = malloc(n*sizeof(*iobuf->iocb)); + iobuf->cnt = n; + iobuf->len = len; + iobuf->requested = 0; + for (i = 0; i < n; ++i) { + iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf)); + iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb)); + } + iobuf->cnt = n; +} + +void delete_bufs(struct io_buffer *iobuf) +{ + unsigned i; + for (i = 0; i < iobuf->cnt; ++i) { + free(iobuf->buf[i]); + free(iobuf->iocb[i]); + } + free(iobuf->buf); + free(iobuf->iocb); +} + +int main(int argc, char *argv[]) +{ + int ret; + unsigned i, j; + char *ep_path; + + int ep0, ep1; + + io_context_t ctx; + + int evfd; + fd_set rfds; + + struct io_buffer iobuf[2]; + int actual = 0; + bool ready; + + if (argc != 2) { + printf("ffs directory not specified!\n"); + return 1; + } + + ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */); + if (!ep_path) { + perror("malloc"); + return 1; + } + + /* open endpoint files */ + sprintf(ep_path, "%s/ep0", argv[1]); + ep0 = open(ep_path, O_RDWR); + if (ep0 < 0) { + perror("unable to open ep0"); + return 1; + } + if (write(ep0, &descriptors, sizeof(descriptors)) < 0) { + perror("unable do write descriptors"); + return 1; + } + if (write(ep0, &strings, sizeof(strings)) < 0) { + perror("unable to write strings"); + return 1; + } + sprintf(ep_path, "%s/ep1", argv[1]); + ep1 = open(ep_path, O_RDWR); + if (ep1 < 0) { + perror("unable to open ep1"); + return 1; + } + + free(ep_path); + + memset(&ctx, 0, sizeof(ctx)); + /* setup aio context to handle up to AIO_MAX requests */ + if (io_setup(AIO_MAX, &ctx) < 0) { + perror("unable to setup aio"); + return 1; + } + + evfd = eventfd(0, 0); + if (evfd < 0) { + perror("unable to open eventfd"); + return 1; + } + + for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) + init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN); + + while (1) { + FD_ZERO(&rfds); + FD_SET(ep0, &rfds); + FD_SET(evfd, &rfds); + + ret = select(((ep0 > evfd) ? ep0 : evfd)+1, + &rfds, NULL, NULL, NULL); + if (ret < 0) { + if (errno == EINTR) + continue; + perror("select"); + break; + } + + if (FD_ISSET(ep0, &rfds)) + handle_ep0(ep0, &ready); + + /* we are waiting for function ENABLE */ + if (!ready) + continue; + + /* + * when we're preparing new data to submit, + * second buffer being transmitted + */ + for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) { + if (iobuf[i].requested) + continue; + /* prepare requests */ + for (j = 0; j < iobuf[i].cnt; ++j) { + io_prep_pwrite(iobuf[i].iocb[j], ep1, + iobuf[i].buf[j], + iobuf[i].len, 0); + /* enable eventfd notification */ + iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD; + iobuf[i].iocb[j]->u.c.resfd = evfd; + } + /* submit table of requests */ + ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb); + if (ret >= 0) { + iobuf[i].requested = ret; + printf("submit: %d requests buf: %d\n", ret, i); + } else + perror("unable to submit reqests"); + } + + /* if event is ready to read */ + if (!FD_ISSET(evfd, &rfds)) + continue; + + uint64_t ev_cnt; + ret = read(evfd, &ev_cnt, sizeof(ev_cnt)); + if (ret < 0) { + perror("unable to read eventfd"); + break; + } + + struct io_event e[BUFS_MAX]; + /* we read aio events */ + ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL); + if (ret > 0) /* if we got events */ + iobuf[actual].requested -= ret; + + /* if all req's from iocb completed */ + if (!iobuf[actual].requested) + actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf)); + } + + /* free resources */ + + for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) + delete_bufs(&iobuf[i]); + io_destroy(ctx); + + close(ep1); + close(ep0); + + return 0; +} diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/Makefile b/tools/usb/ffs-aio-example/multibuff/host_app/Makefile new file mode 100644 index 0000000..8c4a6f0 --- /dev/null +++ b/tools/usb/ffs-aio-example/multibuff/host_app/Makefile @@ -0,0 +1,13 @@ +CC = gcc +LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0) +LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0) +WARNINGS = -Wall -Wextra +CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS) +LDFLAGS = $(LIBUSB_LIBS) + +all: test +%: %.c + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +clean: + $(RM) test diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/test.c b/tools/usb/ffs-aio-example/multibuff/host_app/test.c new file mode 100644 index 0000000..b0ad874 --- /dev/null +++ b/tools/usb/ffs-aio-example/multibuff/host_app/test.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include + +#define VENDOR 0x1d6b +#define PRODUCT 0x0105 + +/* endpoints indexes */ + +#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN) +#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT) + +#define BUF_LEN 8192 + +/* + * struct test_state - describes test program state + * @list: list of devices returned by libusb_get_device_list function + * @found: pointer to struct describing tested device + * @ctx: context, set to NULL + * @handle: handle of tested device + * @attached: indicates that device was attached to kernel, and has to be + * reattached at the end of test program + */ + +struct test_state { + libusb_device *found; + libusb_context *ctx; + libusb_device_handle *handle; + int attached; +}; + +/* + * test_init - initialize test program + */ + +int test_init(struct test_state *state) +{ + int i, ret; + ssize_t cnt; + libusb_device **list; + + state->found = NULL; + state->ctx = NULL; + state->handle = NULL; + state->attached = 0; + + ret = libusb_init(&state->ctx); + if (ret) { + printf("cannot init libusb: %s\n", libusb_error_name(ret)); + return 1; + } + + cnt = libusb_get_device_list(state->ctx, &list); + if (cnt <= 0) { + printf("no devices found\n"); + goto error1; + } + + for (i = 0; i < cnt; ++i) { + libusb_device *dev = list[i]; + struct libusb_device_descriptor desc; + ret = libusb_get_device_descriptor(dev, &desc); + if (ret) { + printf("unable to get device descriptor: %s\n", + libusb_error_name(ret)); + goto error2; + } + if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) { + state->found = dev; + break; + } + } + + if (!state->found) { + printf("no devices found\n"); + goto error2; + } + + ret = libusb_open(state->found, &state->handle); + if (ret) { + printf("cannot open device: %s\n", libusb_error_name(ret)); + goto error2; + } + + if (libusb_claim_interface(state->handle, 0)) { + ret = libusb_detach_kernel_driver(state->handle, 0); + if (ret) { + printf("unable to detach kernel driver: %s\n", + libusb_error_name(ret)); + goto error3; + } + state->attached = 1; + ret = libusb_claim_interface(state->handle, 0); + if (ret) { + printf("cannot claim interface: %s\n", + libusb_error_name(ret)); + goto error4; + } + } + + return 0; + +error4: + if (state->attached == 1) + libusb_attach_kernel_driver(state->handle, 0); + +error3: + libusb_close(state->handle); + +error2: + libusb_free_device_list(list, 1); + +error1: + libusb_exit(state->ctx); + return 1; +} + +/* + * test_exit - cleanup test program + */ + +void test_exit(struct test_state *state) +{ + libusb_release_interface(state->handle, 0); + if (state->attached == 1) + libusb_attach_kernel_driver(state->handle, 0); + libusb_close(state->handle); + libusb_exit(state->ctx); +} + +int main(void) +{ + struct test_state state; + + if (test_init(&state)) + return 1; + + while (1) { + static unsigned char buffer[BUF_LEN]; + int bytes; + libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN, + &bytes, 500); + } + test_exit(&state); +} diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c new file mode 100644 index 0000000..f558664 --- /dev/null +++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c @@ -0,0 +1,335 @@ +#define _BSD_SOURCE /* for endian.h */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libaio.h" +#define IOCB_FLAG_RESFD (1 << 0) + +#include + +#define BUF_LEN 8192 + +/******************** Descriptors and Strings *******************************/ + +static const struct { + struct usb_functionfs_descs_head header; + struct { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio bulk_sink; + struct usb_endpoint_descriptor_no_audio bulk_source; + } __attribute__ ((__packed__)) fs_descs, hs_descs; +} __attribute__ ((__packed__)) descriptors = { + .header = { + .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), + .length = htole32(sizeof(descriptors)), + .fs_count = 3, + .hs_count = 3, + }, + .fs_descs = { + .intf = { + .bLength = sizeof(descriptors.fs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = 1, + }, + .bulk_sink = { + .bLength = sizeof(descriptors.fs_descs.bulk_sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + .bulk_source = { + .bLength = sizeof(descriptors.fs_descs.bulk_source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + }, + .hs_descs = { + .intf = { + .bLength = sizeof(descriptors.hs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = 1, + }, + .bulk_sink = { + .bLength = sizeof(descriptors.hs_descs.bulk_sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + .bulk_source = { + .bLength = sizeof(descriptors.hs_descs.bulk_source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + }, +}; + +#define STR_INTERFACE "AIO Test" + +static const struct { + struct usb_functionfs_strings_head header; + struct { + __le16 code; + const char str1[sizeof(STR_INTERFACE)]; + } __attribute__ ((__packed__)) lang0; +} __attribute__ ((__packed__)) strings = { + .header = { + .magic = htole32(FUNCTIONFS_STRINGS_MAGIC), + .length = htole32(sizeof(strings)), + .str_count = htole32(1), + .lang_count = htole32(1), + }, + .lang0 = { + htole16(0x0409), /* en-us */ + STR_INTERFACE, + }, +}; + +/******************** Endpoints handling *******************************/ + +static void display_event(struct usb_functionfs_event *event) +{ + static const char *const names[] = { + [FUNCTIONFS_BIND] = "BIND", + [FUNCTIONFS_UNBIND] = "UNBIND", + [FUNCTIONFS_ENABLE] = "ENABLE", + [FUNCTIONFS_DISABLE] = "DISABLE", + [FUNCTIONFS_SETUP] = "SETUP", + [FUNCTIONFS_SUSPEND] = "SUSPEND", + [FUNCTIONFS_RESUME] = "RESUME", + }; + switch (event->type) { + case FUNCTIONFS_BIND: + case FUNCTIONFS_UNBIND: + case FUNCTIONFS_ENABLE: + case FUNCTIONFS_DISABLE: + case FUNCTIONFS_SETUP: + case FUNCTIONFS_SUSPEND: + case FUNCTIONFS_RESUME: + printf("Event %s\n", names[event->type]); + } +} + +static void handle_ep0(int ep0, bool *ready) +{ + struct usb_functionfs_event event; + int ret; + + struct pollfd pfds[1]; + pfds[0].fd = ep0; + pfds[0].events = POLLIN; + + ret = poll(pfds, 1, 0); + + if (ret && (pfds[0].revents & POLLIN)) { + ret = read(ep0, &event, sizeof(event)); + if (!ret) { + perror("unable to read event from ep0"); + return; + } + display_event(&event); + switch (event.type) { + case FUNCTIONFS_SETUP: + if (event.u.setup.bRequestType & USB_DIR_IN) + write(ep0, NULL, 0); + else + read(ep0, NULL, 0); + break; + + case FUNCTIONFS_ENABLE: + *ready = true; + break; + + case FUNCTIONFS_DISABLE: + *ready = false; + break; + + default: + break; + } + } +} + +int main(int argc, char *argv[]) +{ + int i, ret; + char *ep_path; + + int ep0; + int ep[2]; + + io_context_t ctx; + + int evfd; + fd_set rfds; + + char *buf_in, *buf_out; + struct iocb *iocb_in, *iocb_out; + int req_in = 0, req_out = 0; + bool ready; + + if (argc != 2) { + printf("ffs directory not specified!\n"); + return 1; + } + + ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */); + if (!ep_path) { + perror("malloc"); + return 1; + } + + /* open endpoint files */ + sprintf(ep_path, "%s/ep0", argv[1]); + ep0 = open(ep_path, O_RDWR); + if (ep0 < 0) { + perror("unable to open ep0"); + return 1; + } + if (write(ep0, &descriptors, sizeof(descriptors)) < 0) { + perror("unable do write descriptors"); + return 1; + } + if (write(ep0, &strings, sizeof(strings)) < 0) { + perror("unable to write strings"); + return 1; + } + for (i = 0; i < 2; ++i) { + sprintf(ep_path, "%s/ep%d", argv[1], i+1); + ep[i] = open(ep_path, O_RDWR); + if (ep[i] < 0) { + printf("unable to open ep%d: %s\n", i+1, + strerror(errno)); + return 1; + } + } + + free(ep_path); + + memset(&ctx, 0, sizeof(ctx)); + /* setup aio context to handle up to 2 requests */ + if (io_setup(2, &ctx) < 0) { + perror("unable to setup aio"); + return 1; + } + + evfd = eventfd(0, 0); + if (evfd < 0) { + perror("unable to open eventfd"); + return 1; + } + + /* alloc buffers and requests */ + buf_in = malloc(BUF_LEN); + buf_out = malloc(BUF_LEN); + iocb_in = malloc(sizeof(*iocb_in)); + iocb_out = malloc(sizeof(*iocb_out)); + + while (1) { + FD_ZERO(&rfds); + FD_SET(ep0, &rfds); + FD_SET(evfd, &rfds); + + ret = select(((ep0 > evfd) ? ep0 : evfd)+1, + &rfds, NULL, NULL, NULL); + if (ret < 0) { + if (errno == EINTR) + continue; + perror("select"); + break; + } + + if (FD_ISSET(ep0, &rfds)) + handle_ep0(ep0, &ready); + + /* we are waiting for function ENABLE */ + if (!ready) + continue; + + /* if something was submitted we wait for event */ + if (FD_ISSET(evfd, &rfds)) { + uint64_t ev_cnt; + ret = read(evfd, &ev_cnt, sizeof(ev_cnt)); + if (ret < 0) { + perror("unable to read eventfd"); + break; + } + + struct io_event e[2]; + /* we wait for one event */ + ret = io_getevents(ctx, 1, 2, e, NULL); + /* if we got event */ + for (i = 0; i < ret; ++i) { + if (e[i].obj->aio_fildes == ep[0]) { + printf("ev=in; ret=%lu\n", e[i].res); + req_in = 0; + } else if (e[i].obj->aio_fildes == ep[1]) { + printf("ev=out; ret=%lu\n", e[i].res); + req_out = 0; + } + } + } + + if (!req_in) { /* if IN transfer not requested*/ + /* prepare write request */ + io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0); + /* enable eventfd notification */ + iocb_in->u.c.flags |= IOCB_FLAG_RESFD; + iocb_in->u.c.resfd = evfd; + /* submit table of requests */ + ret = io_submit(ctx, 1, &iocb_in); + if (ret >= 0) { /* if ret > 0 request is queued */ + req_in = 1; + printf("submit: in\n"); + } else + perror("unable to submit request"); + } + if (!req_out) { /* if OUT transfer not requested */ + /* prepare read request */ + io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0); + /* enable eventfs notification */ + iocb_out->u.c.flags |= IOCB_FLAG_RESFD; + iocb_out->u.c.resfd = evfd; + /* submit table of requests */ + ret = io_submit(ctx, 1, &iocb_out); + if (ret >= 0) { /* if ret > 0 request is queued */ + req_out = 1; + printf("submit: out\n"); + } else + perror("unable to submit request"); + } + } + + /* free resources */ + + io_destroy(ctx); + + free(buf_in); + free(buf_out); + free(iocb_in); + free(iocb_out); + + for (i = 0; i < 2; ++i) + close(ep[i]); + close(ep0); + + return 0; +} diff --git a/tools/usb/ffs-aio-example/simple/host_app/Makefile b/tools/usb/ffs-aio-example/simple/host_app/Makefile new file mode 100644 index 0000000..8c4a6f0 --- /dev/null +++ b/tools/usb/ffs-aio-example/simple/host_app/Makefile @@ -0,0 +1,13 @@ +CC = gcc +LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0) +LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0) +WARNINGS = -Wall -Wextra +CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS) +LDFLAGS = $(LIBUSB_LIBS) + +all: test +%: %.c + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +clean: + $(RM) test diff --git a/tools/usb/ffs-aio-example/simple/host_app/test.c b/tools/usb/ffs-aio-example/simple/host_app/test.c new file mode 100644 index 0000000..64b6a57 --- /dev/null +++ b/tools/usb/ffs-aio-example/simple/host_app/test.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include + +#define VENDOR 0x1d6b +#define PRODUCT 0x0105 + +/* endpoints indexes */ + +#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN) +#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT) + +#define BUF_LEN 8192 + +/* + * struct test_state - describes test program state + * @list: list of devices returned by libusb_get_device_list function + * @found: pointer to struct describing tested device + * @ctx: context, set to NULL + * @handle: handle of tested device + * @attached: indicates that device was attached to kernel, and has to be + * reattached at the end of test program + */ + +struct test_state { + libusb_device *found; + libusb_context *ctx; + libusb_device_handle *handle; + int attached; +}; + +/* + * test_init - initialize test program + */ + +int test_init(struct test_state *state) +{ + int i, ret; + ssize_t cnt; + libusb_device **list; + + state->found = NULL; + state->ctx = NULL; + state->handle = NULL; + state->attached = 0; + + ret = libusb_init(&state->ctx); + if (ret) { + printf("cannot init libusb: %s\n", libusb_error_name(ret)); + return 1; + } + + cnt = libusb_get_device_list(state->ctx, &list); + if (cnt <= 0) { + printf("no devices found\n"); + goto error1; + } + + for (i = 0; i < cnt; ++i) { + libusb_device *dev = list[i]; + struct libusb_device_descriptor desc; + ret = libusb_get_device_descriptor(dev, &desc); + if (ret) { + printf("unable to get device descriptor: %s\n", + libusb_error_name(ret)); + goto error2; + } + if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) { + state->found = dev; + break; + } + } + + if (!state->found) { + printf("no devices found\n"); + goto error2; + } + + ret = libusb_open(state->found, &state->handle); + if (ret) { + printf("cannot open device: %s\n", libusb_error_name(ret)); + goto error2; + } + + if (libusb_claim_interface(state->handle, 0)) { + ret = libusb_detach_kernel_driver(state->handle, 0); + if (ret) { + printf("unable to detach kernel driver: %s\n", + libusb_error_name(ret)); + goto error3; + } + state->attached = 1; + ret = libusb_claim_interface(state->handle, 0); + if (ret) { + printf("cannot claim interface: %s\n", + libusb_error_name(ret)); + goto error4; + } + } + + return 0; + +error4: + if (state->attached == 1) + libusb_attach_kernel_driver(state->handle, 0); + +error3: + libusb_close(state->handle); + +error2: + libusb_free_device_list(list, 1); + +error1: + libusb_exit(state->ctx); + return 1; +} + +/* + * test_exit - cleanup test program + */ + +void test_exit(struct test_state *state) +{ + libusb_release_interface(state->handle, 0); + if (state->attached == 1) + libusb_attach_kernel_driver(state->handle, 0); + libusb_close(state->handle); + libusb_exit(state->ctx); +} + +int main(void) +{ + struct test_state state; + + if (test_init(&state)) + return 1; + + while (1) { + static unsigned char buffer[BUF_LEN]; + int bytes; + libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN, + &bytes, 500); + libusb_bulk_transfer(state.handle, EP_BULK_OUT, buffer, BUF_LEN, + &bytes, 500); + } + test_exit(&state); +} -- cgit v0.10.2 From 411dd19c682dd9c1c29a722bde2d172ee72707de Mon Sep 17 00:00:00 2001 From: George Cherian Date: Fri, 2 May 2014 13:41:00 +0530 Subject: usb: musb: Kconfig: Select the DMA driver if DMA mode of MUSB is enabled AM335x MUSB supports both PIO and DMA mode. When DMA mode is selected users need to explicitly enable the DMA driver. To avoid the extra configuration select the DMA driver if DMA mode is set for AM335x MUSB. Signed-off-by: George Cherian Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 8b78979..6b2a4b8 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -141,6 +141,7 @@ config USB_TI_CPPI_DMA config USB_TI_CPPI41_DMA bool 'TI CPPI 4.1 (AM335x)' depends on ARCH_OMAP + select TI_CPPI41 config USB_TUSB_OMAP_DMA bool 'TUSB 6010' -- cgit v0.10.2 From 22a825079a75560e01fa3307229713ff29cc7aa2 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 4 May 2014 10:57:30 +0200 Subject: usb: musb: tusb: remove dead code musb_in_tusb() is always set to 0, because CONFIG_USB_TUSB6010 is never set (it should have been CONFIG_USB_MUSB_TUSB6010). But musb_in_tusb() is unused anyway, so remove a few lines of dead code. Signed-off-by: Paul Bolle Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h index 35c933a..1864e24 100644 --- a/drivers/usb/musb/tusb6010.h +++ b/drivers/usb/musb/tusb6010.h @@ -14,12 +14,6 @@ extern u8 tusb_get_revision(struct musb *musb); -#ifdef CONFIG_USB_TUSB6010 -#define musb_in_tusb() 1 -#else -#define musb_in_tusb() 0 -#endif - #ifdef CONFIG_USB_TUSB_OMAP_DMA #define tusb_dma_omap() 1 #else -- cgit v0.10.2 From 4d9f872ced245ef0c712f0f04adf446d37813c57 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 5 May 2014 07:39:34 +0800 Subject: usb: gadget: configfs: fix typo %s/atleast/at least Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index dcead55..b5e965e 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -793,7 +793,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget, ret = -EINVAL; if (list_empty(&gi->cdev.configs)) { - pr_err("Need atleast one configuration in %s.\n", + pr_err("Need at least one configuration in %s.\n", gi->composite.name); goto err_comp_cleanup; } @@ -804,7 +804,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget, cfg = container_of(c, struct config_usb_cfg, c); if (list_empty(&cfg->func_list)) { - pr_err("Config %s/%d of %s needs atleast one function.\n", + pr_err("Config %s/%d of %s needs at least one function.\n", c->label, c->bConfigurationValue, gi->composite.name); goto err_comp_cleanup; -- cgit v0.10.2 From bcdbc084ebab447f6eb1add7b953f125b0c8174b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 6 May 2014 17:16:07 +0200 Subject: usb: gadget: atmel_usba: always test udc->driver Found using smatch: drivers/usb/gadget/atmel_usba_udc.c:1689 usba_udc_irq() error: we previously assumed 'udc->driver' could be null (see line 1636) Always test udc->driver before using its members. Acked-by: Nicolas Ferre Signed-off-by: Alexandre Belloni Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 9f65324..76023ce 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1686,7 +1686,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) reset_all_endpoints(udc); if (udc->gadget.speed != USB_SPEED_UNKNOWN - && udc->driver->disconnect) { + && udc->driver && udc->driver->disconnect) { udc->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock(&udc->lock); udc->driver->disconnect(&udc->gadget); -- cgit v0.10.2 From d48d41f18a762c765df87d14b554485e52c393cd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 15:41:16 +0900 Subject: usb: gadget: f_uac2: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index bc23040..c024d27 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -974,8 +974,6 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); if (!prm->rbuf) { prm->max_psize = 0; - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); goto err; } @@ -984,8 +982,6 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); if (!prm->rbuf) { prm->max_psize = 0; - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); goto err; } @@ -1298,10 +1294,8 @@ static int audio_bind_config(struct usb_configuration *cfg) int res; agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL); - if (agdev_g == NULL) { - printk(KERN_ERR "Unable to allocate audio gadget\n"); + if (agdev_g == NULL) return -ENOMEM; - } res = usb_string_ids_tab(cfg->cdev, strings_fn); if (res) -- cgit v0.10.2 From 0351c329f72a41ca712310587d3f7ca82fd8015f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 15:42:21 +0900 Subject: usb: gadget: fotg210-udc: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/fotg210-udc.c b/drivers/usb/gadget/fotg210-udc.c index 2d03052..e143d69 100644 --- a/drivers/usb/gadget/fotg210-udc.c +++ b/drivers/usb/gadget/fotg210-udc.c @@ -1112,17 +1112,13 @@ static int fotg210_udc_probe(struct platform_device *pdev) /* initialize udc */ fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL); - if (fotg210 == NULL) { - pr_err("kzalloc error\n"); + if (fotg210 == NULL) goto err_alloc; - } for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); - if (_ep[i] == NULL) { - pr_err("_ep kzalloc error\n"); + if (_ep[i] == NULL) goto err_alloc; - } fotg210->ep[i] = _ep[i]; } -- cgit v0.10.2 From 8a67ab7d1d2d267ffad3e22b5e4e4d46230e925a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 15:43:57 +0900 Subject: usb: gadget: fsl_udc_core: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 15960af..68843f0 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2252,10 +2252,8 @@ static int __init struct_udc_setup(struct fsl_udc *udc, udc->phy_mode = pdata->phy_mode; udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); - if (!udc->eps) { - ERR("malloc fsl_ep failed\n"); + if (!udc->eps) return -1; - } /* initialized QHs, take care of alignment */ size = udc->max_ep * sizeof(struct ep_queue_head); @@ -2338,10 +2336,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev) u32 dccparams; udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); - if (udc_controller == NULL) { - ERR("malloc udc failed\n"); + if (udc_controller == NULL) return -ENOMEM; - } pdata = dev_get_platdata(&pdev->dev); udc_controller->pdata = pdata; -- cgit v0.10.2 From 8a24bb403974760b420777a76637b2e9f87ffa3f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 15:44:59 +0900 Subject: usb: gadget: fusb300_udc: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 6423f18..3deb4e9 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1400,17 +1400,13 @@ static int __init fusb300_probe(struct platform_device *pdev) /* initialize udc */ fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL); - if (fusb300 == NULL) { - pr_err("kzalloc error\n"); + if (fusb300 == NULL) goto clean_up; - } for (i = 0; i < FUSB300_MAX_NUM_EP; i++) { _ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL); - if (_ep[i] == NULL) { - pr_err("_ep kzalloc error\n"); + if (_ep[i] == NULL) goto clean_up; - } fusb300->ep[i] = _ep[i]; } -- cgit v0.10.2 From c797f7fd5c64c8947900be03f0cd229879a708e6 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 15:46:23 +0900 Subject: usb: gadget: m66592-udc: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 8cae01d..0d17174 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1594,7 +1594,6 @@ static int __init m66592_probe(struct platform_device *pdev) m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); if (m66592 == NULL) { ret = -ENOMEM; - pr_err("kzalloc error\n"); goto clean_up; } -- cgit v0.10.2 From f3772c2b4974241a0ee9d2a35b626fff7c2b7b8d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 15:48:13 +0900 Subject: usb: gadget: mv_u3d_core: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index d2ca59e..1624871 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -297,10 +297,8 @@ static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req, u3d = req->ep->u3d; trb = kzalloc(sizeof(*trb), GFP_ATOMIC); - if (!trb) { - dev_err(u3d->dev, "%s, trb alloc fail\n", __func__); + if (!trb) return NULL; - } /* * Be careful that no _GFP_HIGHMEM is set, @@ -446,17 +444,12 @@ static int mv_u3d_req_to_trb(struct mv_u3d_req *req) trb_num++; trb = kcalloc(trb_num, sizeof(*trb), GFP_ATOMIC); - if (!trb) { - dev_err(u3d->dev, - "%s, trb alloc fail\n", __func__); + if (!trb) return -ENOMEM; - } trb_hw = kcalloc(trb_num, sizeof(*trb_hw), GFP_ATOMIC); if (!trb_hw) { kfree(trb); - dev_err(u3d->dev, - "%s, trb_hw alloc fail\n", __func__); return -ENOMEM; } @@ -1811,7 +1804,6 @@ static int mv_u3d_probe(struct platform_device *dev) u3d = kzalloc(sizeof(*u3d), GFP_KERNEL); if (!u3d) { - dev_err(&dev->dev, "failed to allocate memory for u3d\n"); retval = -ENOMEM; goto err_alloc_private; } @@ -1905,7 +1897,6 @@ static int mv_u3d_probe(struct platform_device *dev) size = u3d->max_eps * sizeof(struct mv_u3d_ep) * 2; u3d->eps = kzalloc(size, GFP_KERNEL); if (!u3d->eps) { - dev_err(&dev->dev, "allocate ep memory failed\n"); retval = -ENOMEM; goto err_alloc_eps; } @@ -1913,7 +1904,6 @@ static int mv_u3d_probe(struct platform_device *dev) /* initialize ep0 status request structure */ u3d->status_req = kzalloc(sizeof(struct mv_u3d_req) + 8, GFP_KERNEL); if (!u3d->status_req) { - dev_err(&dev->dev, "allocate status_req memory failed\n"); retval = -ENOMEM; goto err_alloc_status_req; } -- cgit v0.10.2 From e5f06f909fd3a6901814da79e1ebb8a04887c889 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 15:49:10 +0900 Subject: usb: gadget: r8a66597-udc: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index aff0a67..b698a49 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1904,7 +1904,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); if (r8a66597 == NULL) { ret = -ENOMEM; - dev_err(&pdev->dev, "kzalloc error\n"); goto clean_up; } -- cgit v0.10.2 From f06d186dbd294e9d436096747f34918b70b4f8f1 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 15:50:27 +0900 Subject: usb: gadget: tcm_usb_gadget: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index f058c03..49481e0 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1383,10 +1383,8 @@ static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) struct usbg_nacl *nacl; nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); - if (!nacl) { - printk(KERN_ERR "Unable to allocate struct usbg_nacl\n"); + if (!nacl) return NULL; - } return &nacl->se_node_acl; } @@ -1561,10 +1559,8 @@ static struct se_portal_group *usbg_make_tpg( } tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL); - if (!tpg) { - printk(KERN_ERR "Unable to allocate struct usbg_tpg"); + if (!tpg) return ERR_PTR(-ENOMEM); - } mutex_init(&tpg->tpg_mutex); atomic_set(&tpg->tpg_port_count, 0); tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1); @@ -1613,10 +1609,8 @@ static struct se_wwn *usbg_make_tport( return ERR_PTR(-EINVAL); tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL); - if (!(tport)) { - printk(KERN_ERR "Unable to allocate struct usbg_tport"); + if (!(tport)) return ERR_PTR(-ENOMEM); - } tport->tport_wwpn = wwpn; snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name); return &tport->tport_wwn; @@ -1727,10 +1721,8 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) ret = -ENOMEM; tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL); - if (!tv_nexus) { - pr_err("Unable to allocate struct tcm_vhost_nexus\n"); + if (!tv_nexus) goto err_unlock; - } tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); if (IS_ERR(tv_nexus->tvn_se_sess)) goto err_free; -- cgit v0.10.2 From 966036fde60e6d96708815e0d495692ac352acf9 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Thu, 8 May 2014 00:26:52 +0400 Subject: usb: gadget: gr_udc: unconditionally use GFP_ATOMIC in gr_queue_ext() As far as gr_queue() is called with spinlock held, we have to pass GFP_ATOMIC regardless of gfp argument. Found by Linux Driver Verification project (linuxtesting.org). Acked-by: Andreas Larsson Signed-off-by: Alexey Khoroshilov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index 4966971..99a37ed 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -1684,7 +1684,7 @@ static int gr_queue_ext(struct usb_ep *_ep, struct usb_request *_req, if (ep->is_in) gr_dbgprint_request("EXTERN", ep, req); - ret = gr_queue(ep, req, gfp_flags); + ret = gr_queue(ep, req, GFP_ATOMIC); spin_unlock(&ep->dev->lock); -- cgit v0.10.2 From 64890edb8536618ee856fbca699fe930fcef1573 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 8 May 2014 15:52:14 +0200 Subject: usb: gadget: s3c2410_udc: don't use pr_debug return value pr_debug() may be defined as "do { } while (0)" in some configurations, which means one cannot rely on the return value to be available. In the dprintk function in this driver, we can work around the resulting build error trivially by returning the length that this function already knows and ignoring the return value of pr_debug. Signed-off-by: Arnd Bergmann Cc: Ben Dooks Cc: Kukjin Kim Cc: linux-samsung-soc@vger.kernel.org Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index dd9678f..7987aa0 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -117,7 +117,8 @@ static int dprintk(int level, const char *fmt, ...) sizeof(printk_buf)-len, fmt, args); va_end(args); - return pr_debug("%s", printk_buf); + pr_debug("%s", printk_buf); + return len; } #else static int dprintk(int level, const char *fmt, ...) -- cgit v0.10.2 From 70c1ff4b3c865a36f00aa2498eab3eadd818e4ab Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 8 May 2014 15:52:15 +0200 Subject: usb: musb: tusb-dma can't be built-in if tusb is not A configuration with CONFIG_USB_MUSB_HDRC=y, CONFIG_USB_TUSB_OMAP_DMA=y and CONFIG_USB_MUSB_TUSB6010=m causes a link failure because of the dependency on the tusb_get_revision symbol: (.text+0x154ce8): undefined reference to `tusb_get_revision' This patch ensures that either MUSB_HDRC and MUSB_TUSB6010 are both modules or both built-in, which are the valid configurations. Signed-off-by: Arnd Bergmann Cc: linux-omap@vger.kernel.org Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 6b2a4b8..e0fba75 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -145,7 +145,7 @@ config USB_TI_CPPI41_DMA config USB_TUSB_OMAP_DMA bool 'TUSB 6010' - depends on USB_MUSB_TUSB6010 + depends on USB_MUSB_TUSB6010 = USB_MUSB_HDRC # both built-in or both modules depends on ARCH_OMAP help Enable DMA transfers on TUSB 6010 when OMAP DMA is available. -- cgit v0.10.2 From a8d191c8bb2f11a8f381e7cb98f978b7288c1401 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 8 May 2014 15:52:16 +0200 Subject: usb: musb: omap2plus bus glue needs USB host support The musb/omap2430.c bus glue driver calls usb_hcd_poll_rh_status, which is only available if CONFIG_USB is also set, i.e. we are building USB host mode and not just endpoint mode. Signed-off-by: Arnd Bergmann Cc: linux-omap@vger.kernel.org Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index e0fba75..06cc5d6 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -76,7 +76,7 @@ config USB_MUSB_TUSB6010 config USB_MUSB_OMAP2PLUS tristate "OMAP2430 and onwards" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS && USB select GENERIC_PHY config USB_MUSB_AM35X -- cgit v0.10.2 From c5ab571f81905568a59dce306df0181f33e00932 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 May 2014 21:46:52 +0200 Subject: usb: phy: msm: reset controller is mandatory now Commit a27345434134 "usb: phy: msm: Use reset framework for LINK and PHY resets" introduced a mandatory call to reset_control_get into the msm usb phy driver, which means we have to add a Kconfig dependency on the API to avoid this build error: phy/phy-msm-usb.c: In function 'msm_otg_read_dt': phy/phy-msm-usb.c:1461:2: error: implicit declaration of function 'devm_reset_control_get' [-Werror=implicit-function-declaration] motg->link_rst = devm_reset_control_get(&pdev->dev, "link"); ^ Since the usb-ehci-msm driver currently selects the OTG driver, we could still get a broken dependency here. To solve that, this patch also removes the 'select', which turns out to be unnecessary. Reviewed-by: Ivan T. Ivanov Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3d9e540..7a39ae8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -170,7 +170,6 @@ config USB_EHCI_MSM tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller" depends on ARCH_MSM select USB_EHCI_ROOT_HUB_TT - select USB_MSM_OTG ---help--- Enables support for the USB Host controller present on the Qualcomm chipsets. Root Hub has inbuilt TT. diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index fbbced8..ec531a4 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -173,6 +173,7 @@ config USB_ISP1301 config USB_MSM_OTG tristate "Qualcomm on-chip USB OTG controller support" depends on (USB || USB_GADGET) && (ARCH_MSM || ARCH_QCOM || COMPILE_TEST) + depends on RESET_CONTROLLER select USB_PHY help Enable this to support the USB OTG transceiver on Qualcomm chips. It -- cgit v0.10.2 From 10f0577aa5cb03c81cf6ddc2ff7de1b6d6152d0b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 May 2014 16:54:47 +0300 Subject: usb: phy: msm: change devm_ioremap() to devm_ioremap_resource() There are several issues here: 1) platform_get_resource() can return NULL and that wasn't handled. 2) We should request the memory before we remap it, and devm_ioremap_resource() does that. 3) devm_ioremap() returns a NULL but we were checking for IS_ERR(). Fixes: 6b99c68ec1f9 ('usb: phy: msm: Migrate to Managed Device Resource allocation') Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index c522c4f..4f88174 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1586,7 +1586,7 @@ static int msm_otg_probe(struct platform_device *pdev) np ? "alt_core" : "usb_hs_core_clk"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + motg->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(motg->regs)) return PTR_ERR(motg->regs); -- cgit v0.10.2 From 74d484669784836c83f23f80ee21a44e9fbf4d59 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 8 May 2014 14:06:21 +0200 Subject: usb: gadget: FunctionFS: share VLA macros with all usb gadget files Variable Length Array macros allow portable (compilable with both gcc and clang) way of allocating a number of structures using a single memory chunk. They can be useful for files other than f_fs.c, so move them to a header file. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index a01b3bd..38641ea 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -33,36 +33,11 @@ #include #include "u_fs.h" +#include "u_f.h" #include "configfs.h" #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ -/* Variable Length Array Macros **********************************************/ -#define vla_group(groupname) size_t groupname##__next = 0 -#define vla_group_size(groupname) groupname##__next - -#define vla_item(groupname, type, name, n) \ - size_t groupname##_##name##__offset = ({ \ - size_t align_mask = __alignof__(type) - 1; \ - size_t offset = (groupname##__next + align_mask) & ~align_mask;\ - size_t size = (n) * sizeof(type); \ - groupname##__next = offset + size; \ - offset; \ - }) - -#define vla_item_with_sz(groupname, type, name, n) \ - size_t groupname##_##name##__sz = (n) * sizeof(type); \ - size_t groupname##_##name##__offset = ({ \ - size_t align_mask = __alignof__(type) - 1; \ - size_t offset = (groupname##__next + align_mask) & ~align_mask;\ - size_t size = groupname##_##name##__sz; \ - groupname##__next = offset + size; \ - offset; \ - }) - -#define vla_ptr(ptr, groupname, name) \ - ((void *) ((char *)ptr + groupname##_##name##__offset)) - /* Reference counter handling */ static void ffs_data_get(struct ffs_data *ffs); static void ffs_data_put(struct ffs_data *ffs); diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 71034c0..1d5f0eb 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -16,6 +16,32 @@ #ifndef __U_F_H__ #define __U_F_H__ +/* Variable Length Array Macros **********************************************/ +#define vla_group(groupname) size_t groupname##__next = 0 +#define vla_group_size(groupname) groupname##__next + +#define vla_item(groupname, type, name, n) \ + size_t groupname##_##name##__offset = ({ \ + size_t align_mask = __alignof__(type) - 1; \ + size_t offset = (groupname##__next + align_mask) & ~align_mask;\ + size_t size = (n) * sizeof(type); \ + groupname##__next = offset + size; \ + offset; \ + }) + +#define vla_item_with_sz(groupname, type, name, n) \ + size_t groupname##_##name##__sz = (n) * sizeof(type); \ + size_t groupname##_##name##__offset = ({ \ + size_t align_mask = __alignof__(type) - 1; \ + size_t offset = (groupname##__next + align_mask) & ~align_mask;\ + size_t size = groupname##_##name##__sz; \ + groupname##__next = offset + size; \ + offset; \ + }) + +#define vla_ptr(ptr, groupname, name) \ + ((void *) ((char *)ptr + groupname##_##name##__offset)) + struct usb_ep; struct usb_request; -- cgit v0.10.2 From 19824d5eeecedfb46639961da1b7a21ba3179930 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 8 May 2014 14:06:22 +0200 Subject: usb: gadget: OS String support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a custom (non-USB IF) extension to the USB standard: http://msdn.microsoft.com/library/windows/hardware/gg463182 They grant permission to use the specification - there is "Microsoft OS Descriptor Specification License Agreement" under the link mentioned above, and its Section 2 "Grant of License", letter (b) reads: "Patent license. Microsoft hereby grants to You a nonexclusive, royalty-free, nontransferable, worldwide license under Microsoft’s patents embodied solely within the Specification and that are owned or licensable by Microsoft to make, use, import, offer to sell, sell and distribute directly or indirectly to Your Licensees Your Implementation. You may sublicense this patent license to Your Licensees under the same terms and conditions." The said extension is maintained by Microsoft for Microsoft. Yet it is fairly common for various devices to use it, and a popular proprietary operating system expects devices to provide "OS descriptors", so Linux-based USB gadgets whishing to be able to talk to a variety of operating systems should be able to provide the "OS descriptors". This patch adds optional support for gadgets whishing to expose the so called "OS String" under index 0xEE of language 0. The contents of the string is generated based on the qw_sign array and b_vendor_code. Interested gadgets need to set the cdev->use_os_string flag, fill cdev->qw_sign with appropriate values and fill cdev->b_vendor_code with a value of their choice. This patch does not however implement responding to any vendor-specific USB requests. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 8060de6..2f87b16 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -21,6 +21,22 @@ #include #include +/** + * struct usb_os_string - represents OS String to be reported by a gadget + * @bLength: total length of the entire descritor, always 0x12 + * @bDescriptorType: USB_DT_STRING + * @qwSignature: the OS String proper + * @bMS_VendorCode: code used by the host for subsequent requests + * @bPad: not used, must be zero + */ +struct usb_os_string { + __u8 bLength; + __u8 bDescriptorType; + __u8 qwSignature[OS_STRING_QW_SIGN_LEN]; + __u8 bMS_VendorCode; + __u8 bPad; +} __packed; + /* * The code in this file is utility code, used to build a gadget driver * from one or more "function" drivers, one or more "configuration" @@ -961,6 +977,19 @@ static int get_string(struct usb_composite_dev *cdev, return s->bLength; } + if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) { + struct usb_os_string *b = buf; + b->bLength = sizeof(*b); + b->bDescriptorType = USB_DT_STRING; + compiletime_assert( + sizeof(b->qwSignature) == sizeof(cdev->qw_sign), + "qwSignature size must be equal to qw_sign"); + memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature)); + b->bMS_VendorCode = cdev->b_vendor_code; + b->bPad = 0; + return sizeof(*b); + } + list_for_each_entry(uc, &cdev->gstrings, list) { struct usb_gadget_strings **sp; diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index d3ca3b5..7d29ee9 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -335,11 +335,17 @@ static inline struct usb_composite_driver *to_cdriver( return container_of(gdrv, struct usb_composite_driver, gadget_driver); } +#define OS_STRING_QW_SIGN_LEN 14 +#define OS_STRING_IDX 0xEE + /** * struct usb_composite_device - represents one composite usb gadget * @gadget: read-only, abstracts the gadget's usb peripheral controller * @req: used for control responses; buffer is pre-allocated * @config: the currently active configuration + * @qw_sign: qwSignature part of the OS string + * @b_vendor_code: bMS_VendorCode part of the OS string + * @use_os_string: false by default, interested gadgets set it * * One of these devices is allocated and initialized before the * associated device driver's bind() is called. @@ -372,6 +378,11 @@ struct usb_composite_dev { struct usb_configuration *config; + /* OS String is a custom (yet popular) extension to the USB standard. */ + u8 qw_sign[OS_STRING_QW_SIGN_LEN]; + u8 b_vendor_code; + unsigned int use_os_string:1; + /* private: */ /* internals */ unsigned int suspended:1; -- cgit v0.10.2 From 37a3a533429ef9b3cc9f15a656c19623f0e88df7 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 8 May 2014 14:06:23 +0200 Subject: usb: gadget: OS Feature Descriptors support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a custom (non-USB IF) extension to the USB standard: http://msdn.microsoft.com/library/windows/hardware/gg463182 They grant permission to use the specification - there is "Microsoft OS Descriptor Specification License Agreement" under the link mentioned above, and its Section 2 "Grant of License", letter (b) reads: "Patent license. Microsoft hereby grants to You a nonexclusive, royalty-free, nontransferable, worldwide license under Microsoft’s patents embodied solely within the Specification and that are owned or licensable by Microsoft to make, use, import, offer to sell, sell and distribute directly or indirectly to Your Licensees Your Implementation. You may sublicense this patent license to Your Licensees under the same terms and conditions." The said extension is maintained by Microsoft for Microsoft. Yet it is fairly common for various devices to use it, and a popular proprietary operating system expects devices to provide "OS descriptors", so Linux-based USB gadgets whishing to be able to talk to a variety of operating systems should be able to provide the "OS descriptors". This patch adds optional support for gadgets whishing to expose the so called "OS Feature Descriptors", that is "Extended Compatibility ID" and "Extended Properties". Hosts which do request "OS descriptors" from gadgets do so during the enumeration phase and before the configuration is set with SET_CONFIGURATION. What is more, those hosts never ask for configurations at indices other than 0. Therefore, gadgets whishing to provide "OS descriptors" must designate one configuration to be used with this kind of hosts - this is what os_desc_config is added for in struct usb_composite_dev. There is an additional advantage to it: if a gadget provides "OS descriptors" and designates one configuration to be used with such non-USB-compliant hosts it can invoke "usb_add_config" in any order because the designated configuration will be reported to be at index 0 anyway. This patch also adds handling vendor-specific requests addressed at device or interface and related to handling "OS descriptors". Signed-off-by: Andrzej Pietrasiewicz Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 2f87b16..042c66b 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -21,6 +21,8 @@ #include #include +#include "u_os_desc.h" + /** * struct usb_os_string - represents OS String to be reported by a gadget * @bLength: total length of the entire descritor, always 0x12 @@ -438,6 +440,7 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) { struct usb_gadget *gadget = cdev->gadget; struct usb_configuration *c; + struct list_head *pos; u8 type = w_value >> 8; enum usb_device_speed speed = USB_SPEED_UNKNOWN; @@ -456,7 +459,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) /* This is a lookup by config *INDEX* */ w_value &= 0xff; - list_for_each_entry(c, &cdev->configs, list) { + + pos = &cdev->configs; + c = cdev->os_desc_config; + if (c) + goto check_config; + + while ((pos = pos->next) != &cdev->configs) { + c = list_entry(pos, typeof(*c), list); + + /* skip OS Descriptors config which is handled separately */ + if (c == cdev->os_desc_config) + continue; + +check_config: /* ignore configs that won't work at this speed */ switch (speed) { case USB_SPEED_SUPER: @@ -1236,6 +1252,158 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) req->status, req->actual, req->length); } +static int count_ext_compat(struct usb_configuration *c) +{ + int i, res; + + res = 0; + for (i = 0; i < c->next_interface_id; ++i) { + struct usb_function *f; + int j; + + f = c->interface[i]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (i != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) + ++res; + } + } + BUG_ON(res > 255); + return res; +} + +static void fill_ext_compat(struct usb_configuration *c, u8 *buf) +{ + int i, count; + + count = 16; + for (i = 0; i < c->next_interface_id; ++i) { + struct usb_function *f; + int j; + + f = c->interface[i]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (i != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) { + *buf++ = i; + *buf++ = 0x01; + memcpy(buf, d->ext_compat_id, 16); + buf += 22; + } else { + ++buf; + *buf = 0x01; + buf += 23; + } + count += 24; + if (count >= 4096) + return; + } + } +} + +static int count_ext_prop(struct usb_configuration *c, int interface) +{ + struct usb_function *f; + int j, res; + + res = 0; + + f = c->interface[interface]; + for (j = 0; j < f->os_desc_n; ++j) { + struct usb_os_desc *d; + + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d && d->ext_compat_id) + return d->ext_prop_count; + } + return res; +} + +static int len_ext_prop(struct usb_configuration *c, int interface) +{ + struct usb_function *f; + struct usb_os_desc *d; + int j, res; + + res = 10; /* header length */ + f = c->interface[interface]; + for (j = 0; j < f->os_desc_n; ++j) { + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d) + return min(res + d->ext_prop_len, 4096); + } + return res; +} + +static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) +{ + struct usb_function *f; + struct usb_os_desc *d; + struct usb_os_desc_ext_prop *ext_prop; + int j, count, n, ret; + u8 *start = buf; + + f = c->interface[interface]; + for (j = 0; j < f->os_desc_n; ++j) { + if (interface != f->os_desc_table[j].if_id) + continue; + d = f->os_desc_table[j].os_desc; + if (d) + list_for_each_entry(ext_prop, &d->ext_prop, entry) { + /* 4kB minus header length */ + n = buf - start; + if (n >= 4086) + return 0; + + count = ext_prop->data_len + + ext_prop->name_len + 14; + if (count > 4086 - n) + return -EINVAL; + usb_ext_prop_put_size(buf, count); + usb_ext_prop_put_type(buf, ext_prop->type); + ret = usb_ext_prop_put_name(buf, ext_prop->name, + ext_prop->name_len); + if (ret < 0) + return ret; + switch (ext_prop->type) { + case USB_EXT_PROP_UNICODE: + case USB_EXT_PROP_UNICODE_ENV: + case USB_EXT_PROP_UNICODE_LINK: + usb_ext_prop_put_unicode(buf, ret, + ext_prop->data, + ext_prop->data_len); + break; + case USB_EXT_PROP_BINARY: + usb_ext_prop_put_binary(buf, ret, + ext_prop->data, + ext_prop->data_len); + break; + case USB_EXT_PROP_LE32: + /* not implemented */ + case USB_EXT_PROP_BE32: + /* not implemented */ + default: + return -EINVAL; + } + buf += count; + } + } + + return 0; +} + /* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver(like @@ -1445,6 +1613,91 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; default: unknown: + /* + * OS descriptors handling + */ + if (cdev->use_os_string && cdev->os_desc_config && + (ctrl->bRequest & USB_TYPE_VENDOR) && + ctrl->bRequest == cdev->b_vendor_code) { + struct usb_request *req; + struct usb_configuration *os_desc_cfg; + u8 *buf; + int interface; + int count = 0; + + req = cdev->os_desc_req; + req->complete = composite_setup_complete; + buf = req->buf; + os_desc_cfg = cdev->os_desc_config; + memset(buf, 0, w_length); + buf[5] = 0x01; + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + if (w_index != 0x4 || (w_value >> 8)) + break; + buf[6] = w_index; + if (w_length == 0x10) { + /* Number of ext compat interfaces */ + count = count_ext_compat(os_desc_cfg); + buf[8] = count; + count *= 24; /* 24 B/ext compat desc */ + count += 16; /* header */ + put_unaligned_le32(count, buf); + value = w_length; + } else { + /* "extended compatibility ID"s */ + count = count_ext_compat(os_desc_cfg); + buf[8] = count; + count *= 24; /* 24 B/ext compat desc */ + count += 16; /* header */ + put_unaligned_le32(count, buf); + buf += 16; + fill_ext_compat(os_desc_cfg, buf); + value = w_length; + } + break; + case USB_RECIP_INTERFACE: + if (w_index != 0x5 || (w_value >> 8)) + break; + interface = w_value & 0xFF; + buf[6] = w_index; + if (w_length == 0x0A) { + count = count_ext_prop(os_desc_cfg, + interface); + put_unaligned_le16(count, buf + 8); + count = len_ext_prop(os_desc_cfg, + interface); + put_unaligned_le32(count, buf); + + value = w_length; + } else { + count = count_ext_prop(os_desc_cfg, + interface); + put_unaligned_le16(count, buf + 8); + count = len_ext_prop(os_desc_cfg, + interface); + put_unaligned_le32(count, buf); + buf += 10; + value = fill_ext_prop(os_desc_cfg, + interface, buf); + if (value < 0) + return value; + + value = w_length; + } + break; + } + req->length = value; + req->zero = value < w_length; + value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DBG(cdev, "ep_queue --> %d\n", value); + req->status = 0; + composite_setup_complete(gadget->ep0, req); + } + return value; + } + VDBG(cdev, "non-core control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, @@ -1668,6 +1921,29 @@ fail: return ret; } +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, + struct usb_ep *ep0) +{ + int ret = 0; + + cdev->os_desc_req = usb_ep_alloc_request(ep0, GFP_KERNEL); + if (!cdev->os_desc_req) { + ret = PTR_ERR(cdev->os_desc_req); + goto end; + } + + /* OS feature descriptor length <= 4kB */ + cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL); + if (!cdev->os_desc_req->buf) { + ret = PTR_ERR(cdev->os_desc_req->buf); + kfree(cdev->os_desc_req); + goto end; + } + cdev->os_desc_req->complete = composite_setup_complete; +end: + return ret; +} + void composite_dev_cleanup(struct usb_composite_dev *cdev) { struct usb_gadget_string_container *uc, *tmp; @@ -1676,6 +1952,10 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev) list_del(&uc->list); kfree(uc); } + if (cdev->os_desc_req) { + kfree(cdev->os_desc_req->buf); + usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req); + } if (cdev->req) { kfree(cdev->req->buf); usb_ep_free_request(cdev->gadget->ep0, cdev->req); @@ -1713,6 +1993,12 @@ static int composite_bind(struct usb_gadget *gadget, if (status < 0) goto fail; + if (cdev->use_os_string) { + status = composite_os_desc_req_prepare(cdev, gadget->ep0); + if (status) + goto fail; + } + update_unchanged_dev_desc(&cdev->desc, composite->dev); /* has userspace failed to provide a serial number? */ diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h new file mode 100644 index 0000000..ea5cf8c --- /dev/null +++ b/drivers/usb/gadget/u_os_desc.h @@ -0,0 +1,90 @@ +/* + * u_os_desc.h + * + * Utility definitions for "OS Descriptors" support + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __U_OS_DESC_H__ +#define __U_OS_DESC_H__ + +#include +#include + +#define USB_EXT_PROP_DW_SIZE 0 +#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE 4 +#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH 8 +#define USB_EXT_PROP_B_PROPERTY_NAME 10 +#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH 10 +#define USB_EXT_PROP_B_PROPERTY_DATA 14 + +#define USB_EXT_PROP_RESERVED 0 +#define USB_EXT_PROP_UNICODE 1 +#define USB_EXT_PROP_UNICODE_ENV 2 +#define USB_EXT_PROP_BINARY 3 +#define USB_EXT_PROP_LE32 4 +#define USB_EXT_PROP_BE32 5 +#define USB_EXT_PROP_UNICODE_LINK 6 +#define USB_EXT_PROP_UNICODE_MULTI 7 + +static inline void usb_ext_prop_put_size(u8 *buf, int dw_size) +{ + put_unaligned_le32(dw_size, &buf[USB_EXT_PROP_DW_SIZE]); +} + +static inline void usb_ext_prop_put_type(u8 *buf, int type) +{ + put_unaligned_le32(type, &buf[USB_EXT_PROP_DW_PROPERTY_DATA_TYPE]); +} + +static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl) +{ + int result; + + put_unaligned_le16(pnl, &buf[USB_EXT_PROP_W_PROPERTY_NAME_LENGTH]); + result = utf8s_to_utf16s(name, strlen(name), UTF16_LITTLE_ENDIAN, + (wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_NAME], pnl - 2); + if (result < 0) + return result; + + put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl]); + + return pnl; +} + +static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const u8 *data, + int data_len) +{ + put_unaligned_le32(data_len, + &buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); + memcpy(&buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], data, data_len); +} + +static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string, + int data_len) +{ + int result; + put_unaligned_le32(data_len, + &buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); + + result = utf8s_to_utf16s(string, data_len >> 1, UTF16_LITTLE_ENDIAN, + (wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], + data_len - 2); + if (result < 0) + return result; + + put_unaligned_le16(0, + &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len]); + + return data_len; +} + +#endif /* __U_OS_DESC_H__ */ diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 7d29ee9..549f538 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -57,6 +57,53 @@ struct usb_configuration; /** + * struct usb_os_desc_ext_prop - describes one "Extended Property" + * @entry: used to keep a list of extended properties + * @type: Extended Property type + * @name_len: Extended Property unicode name length, including terminating '\0' + * @name: Extended Property name + * @data_len: Length of Extended Property blob (for unicode store double len) + * @data: Extended Property blob + */ +struct usb_os_desc_ext_prop { + struct list_head entry; + u8 type; + int name_len; + char *name; + int data_len; + char *data; +}; + +/** + * struct usb_os_desc - describes OS descriptors associated with one interface + * @ext_compat_id: 16 bytes of "Compatible ID" and "Subcompatible ID" + * @ext_prop: Extended Properties list + * @ext_prop_len: Total length of Extended Properties blobs + * @ext_prop_count: Number of Extended Properties + */ +struct usb_os_desc { + char *ext_compat_id; + struct list_head ext_prop; + int ext_prop_len; + int ext_prop_count; +}; + +/** + * struct usb_os_desc_table - describes OS descriptors associated with one + * interface of a usb_function + * @if_id: Interface id + * @os_desc: "Extended Compatibility ID" and "Extended Properties" of the + * interface + * + * Each interface can have at most one "Extended Compatibility ID" and a + * number of "Extended Properties". + */ +struct usb_os_desc_table { + int if_id; + struct usb_os_desc *os_desc; +}; + +/** * struct usb_function - describes one function of a configuration * @name: For diagnostics, identifies the function. * @strings: tables of strings, keyed by identifiers assigned during bind() @@ -73,6 +120,10 @@ struct usb_configuration; * be available at super speed. * @config: assigned when @usb_add_function() is called; this is the * configuration with which this function is associated. + * @os_desc_table: Table of (interface id, os descriptors) pairs. The function + * can expose more than one interface. If an interface is a member of + * an IAD, only the first interface of IAD has its entry in the table. + * @os_desc_n: Number of entries in os_desc_table * @bind: Before the gadget can register, all of its functions bind() to the * available resources including string and interface identifiers used * in interface or class descriptors; endpoints; I/O buffers; and so on. @@ -129,6 +180,9 @@ struct usb_function { struct usb_configuration *config; + struct usb_os_desc_table *os_desc_table; + unsigned os_desc_n; + /* REVISIT: bind() functions can be marked __init, which * makes trouble for section mismatch analysis. See if * we can't restructure things to avoid mismatching. @@ -342,10 +396,12 @@ static inline struct usb_composite_driver *to_cdriver( * struct usb_composite_device - represents one composite usb gadget * @gadget: read-only, abstracts the gadget's usb peripheral controller * @req: used for control responses; buffer is pre-allocated + * @os_desc_req: used for OS descriptors responses; buffer is pre-allocated * @config: the currently active configuration * @qw_sign: qwSignature part of the OS string * @b_vendor_code: bMS_VendorCode part of the OS string * @use_os_string: false by default, interested gadgets set it + * @os_desc_config: the configuration to be used with OS descriptors * * One of these devices is allocated and initialized before the * associated device driver's bind() is called. @@ -375,12 +431,14 @@ static inline struct usb_composite_driver *to_cdriver( struct usb_composite_dev { struct usb_gadget *gadget; struct usb_request *req; + struct usb_request *os_desc_req; struct usb_configuration *config; /* OS String is a custom (yet popular) extension to the USB standard. */ u8 qw_sign[OS_STRING_QW_SIGN_LEN]; u8 b_vendor_code; + struct usb_configuration *os_desc_config; unsigned int use_os_string:1; /* private: */ -- cgit v0.10.2 From de7a8d2d534fb3c35c29762b8a7d14e5b1937d6f Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 8 May 2014 14:06:24 +0200 Subject: usb: gadget: f_rndis: OS descriptors support In order for usb functions to expose OS descriptors they need to be made aware of OS descriptors. This involves extending the "options" structure and setting up appropriate associations. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 139bc9c..28d1891 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -682,6 +682,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); + if (cdev->use_os_string) { + f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), + GFP_KERNEL); + if (!f->os_desc_table) + return PTR_ERR(f->os_desc_table); + f->os_desc_n = 1; + f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; + } + /* * in drivers/usb/gadget/configfs.c:configfs_composite_bind() * configurations are bound in sequence with list_for_each_entry, @@ -693,14 +702,16 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) gether_set_gadget(rndis_opts->net, cdev->gadget); status = gether_register_netdev(rndis_opts->net); if (status) - return status; + goto fail; rndis_opts->bound = true; } us = usb_gstrings_attach(cdev, rndis_strings, ARRAY_SIZE(rndis_string_defs)); - if (IS_ERR(us)) - return PTR_ERR(us); + if (IS_ERR(us)) { + status = PTR_ERR(us); + goto fail; + } rndis_control_intf.iInterface = us[0].id; rndis_data_intf.iInterface = us[1].id; rndis_iad_descriptor.iFunction = us[2].id; @@ -802,6 +813,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: + kfree(f->os_desc_table); + f->os_desc_n = 0; usb_free_all_descriptors(f); if (rndis->notify_req) { @@ -892,6 +905,8 @@ static struct usb_function_instance *rndis_alloc_inst(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); + opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; + mutex_init(&opts->lock); opts->func_inst.free_func_inst = rndis_free_inst; opts->net = gether_setup_default(); @@ -900,6 +915,7 @@ static struct usb_function_instance *rndis_alloc_inst(void) kfree(opts); return ERR_CAST(net); } + INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); config_group_init_type_name(&opts->func_inst.group, "", &rndis_func_type); @@ -925,6 +941,8 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); + kfree(f->os_desc_table); + f->os_desc_n = 0; usb_free_all_descriptors(f); kfree(rndis->notify_req->buf); diff --git a/drivers/usb/gadget/u_rndis.h b/drivers/usb/gadget/u_rndis.h index 7291b15..e902aa4 100644 --- a/drivers/usb/gadget/u_rndis.h +++ b/drivers/usb/gadget/u_rndis.h @@ -26,6 +26,9 @@ struct f_rndis_opts { bool bound; bool borrowed_net; + struct usb_os_desc rndis_os_desc; + char rndis_ext_compat_id[16]; + /* * Read/write access to configfs attributes is handled by configfs. * -- cgit v0.10.2 From 87213d388e927aaa88b21d5ff7e1f75ca2288da1 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 8 May 2014 14:06:25 +0200 Subject: usb: gadget: configfs: OS String support Add handling of OS String extension from the configfs interface. A directory "os_desc" is added at the top level of a gadget's directories hierarchy. In the "os_desc" directory there are three attributes: "use", "b_vendor_code" and "qw_sign". If "use" contains "0" the OS string is not reported to the host. "b_vendor_code" contains a one-byte value which is used for custom per-device and per-interface requests. "qw_sign" contains an identifier to be reported as the "OS String" proper. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget index 37559a0..0e7b786 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget +++ b/Documentation/ABI/testing/configfs-usb-gadget @@ -79,3 +79,14 @@ Description: product - gadget's product description manufacturer - gadget's manufacturer description +What: /config/usb-gadget/gadget/os_desc +Date: May 2014 +KernelVersion: 3.16 +Description: + This group contains "OS String" extension handling attributes. + + use - flag turning "OS Desctiptors" support on/off + b_vendor_code - one-byte value used for custom per-device and + per-interface requests + qw_sign - an identifier to be reported as "OS String" + proper diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index b5e965e..8b9e038 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include "configfs.h" @@ -43,7 +44,8 @@ struct gadget_info { struct config_group functions_group; struct config_group configs_group; struct config_group strings_group; - struct config_group *default_groups[4]; + struct config_group os_desc_group; + struct config_group *default_groups[5]; struct mutex lock; struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; @@ -56,6 +58,9 @@ struct gadget_info { #endif struct usb_composite_driver composite; struct usb_composite_dev cdev; + bool use_os_desc; + char b_vendor_code; + char qw_sign[OS_STRING_QW_SIGN_LEN]; }; struct config_usb_cfg { @@ -79,6 +84,10 @@ struct gadget_strings { struct list_head list; }; +struct os_desc { + struct config_group group; +}; + struct gadget_config_name { struct usb_gadget_strings stringtab_dev; struct usb_string strings; @@ -736,6 +745,145 @@ static void gadget_strings_attr_release(struct config_item *item) USB_CONFIG_STRING_RW_OPS(gadget_strings); USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info); +static inline struct os_desc *to_os_desc(struct config_item *item) +{ + return container_of(to_config_group(item), struct os_desc, group); +} + +CONFIGFS_ATTR_STRUCT(os_desc); +CONFIGFS_ATTR_OPS(os_desc); + +static ssize_t os_desc_use_show(struct os_desc *os_desc, char *page) +{ + struct gadget_info *gi; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + return sprintf(page, "%d", gi->use_os_desc); +} + +static ssize_t os_desc_use_store(struct os_desc *os_desc, const char *page, + size_t len) +{ + struct gadget_info *gi; + int ret; + bool use; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + mutex_lock(&gi->lock); + ret = strtobool(page, &use); + if (!ret) { + gi->use_os_desc = use; + ret = len; + } + mutex_unlock(&gi->lock); + + return ret; +} + +static struct os_desc_attribute os_desc_use = + __CONFIGFS_ATTR(use, S_IRUGO | S_IWUSR, + os_desc_use_show, + os_desc_use_store); + +static ssize_t os_desc_b_vendor_code_show(struct os_desc *os_desc, char *page) +{ + struct gadget_info *gi; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + return sprintf(page, "%d", gi->b_vendor_code); +} + +static ssize_t os_desc_b_vendor_code_store(struct os_desc *os_desc, + const char *page, size_t len) +{ + struct gadget_info *gi; + int ret; + u8 b_vendor_code; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + mutex_lock(&gi->lock); + ret = kstrtou8(page, 0, &b_vendor_code); + if (!ret) { + gi->b_vendor_code = b_vendor_code; + ret = len; + } + mutex_unlock(&gi->lock); + + return ret; +} + +static struct os_desc_attribute os_desc_b_vendor_code = + __CONFIGFS_ATTR(b_vendor_code, S_IRUGO | S_IWUSR, + os_desc_b_vendor_code_show, + os_desc_b_vendor_code_store); + +static ssize_t os_desc_qw_sign_show(struct os_desc *os_desc, char *page) +{ + struct gadget_info *gi; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + + memcpy(page, gi->qw_sign, OS_STRING_QW_SIGN_LEN); + + return OS_STRING_QW_SIGN_LEN; +} + +static ssize_t os_desc_qw_sign_store(struct os_desc *os_desc, const char *page, + size_t len) +{ + struct gadget_info *gi; + int res, l; + + gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1); + if (page[l - 1] == '\n') + --l; + + mutex_lock(&gi->lock); + res = utf8s_to_utf16s(page, l, + UTF16_LITTLE_ENDIAN, (wchar_t *) gi->qw_sign, + OS_STRING_QW_SIGN_LEN); + if (res > 0) + res = len; + mutex_unlock(&gi->lock); + + return res; +} + +static struct os_desc_attribute os_desc_qw_sign = + __CONFIGFS_ATTR(qw_sign, S_IRUGO | S_IWUSR, + os_desc_qw_sign_show, + os_desc_qw_sign_store); + +static struct configfs_attribute *os_desc_attrs[] = { + &os_desc_use.attr, + &os_desc_b_vendor_code.attr, + &os_desc_qw_sign.attr, + NULL, +}; + +static void os_desc_attr_release(struct config_item *item) +{ + struct os_desc *os_desc = to_os_desc(item); + kfree(os_desc); +} + +static struct configfs_item_operations os_desc_ops = { + .release = os_desc_attr_release, + .show_attribute = os_desc_attr_show, + .store_attribute = os_desc_attr_store, +}; + +static struct config_item_type os_desc_type = { + .ct_item_ops = &os_desc_ops, + .ct_attrs = os_desc_attrs, + .ct_owner = THIS_MODULE, +}; + static int configfs_do_nothing(struct usb_composite_dev *cdev) { WARN_ON(1); @@ -839,6 +987,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget, gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id; } + if (gi->use_os_desc) { + cdev->use_os_string = true; + cdev->b_vendor_code = gi->b_vendor_code; + memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); + } + /* Go through all configs, attach all functions */ list_for_each_entry(c, &gi->cdev.configs, list) { struct config_usb_cfg *cfg; @@ -929,6 +1083,7 @@ static struct config_group *gadgets_make( gi->group.default_groups[0] = &gi->functions_group; gi->group.default_groups[1] = &gi->configs_group; gi->group.default_groups[2] = &gi->strings_group; + gi->group.default_groups[3] = &gi->os_desc_group; config_group_init_type_name(&gi->functions_group, "functions", &functions_type); @@ -936,6 +1091,8 @@ static struct config_group *gadgets_make( &config_desc_type); config_group_init_type_name(&gi->strings_group, "strings", &gadget_strings_strings_type); + config_group_init_type_name(&gi->os_desc_group, "os_desc", + &os_desc_type); gi->composite.bind = configfs_do_nothing; gi->composite.unbind = configfs_do_nothing; -- cgit v0.10.2 From da4243145fb197622425d4c2feff5d6422f2391e Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 8 May 2014 14:06:26 +0200 Subject: usb: gadget: configfs: OS Extended Compatibility descriptors support Add handling of OS Extended Compatibility descriptors from configfs interface. Hosts which expect the "OS Descriptors" ask only for configurations @ index 0, but linux-based USB devices can provide more than one configuration. This patch adds marking one of gadget's configurations the configuration to be reported at index 0, regardless of the actual sequence of usb_add_config invocations used for adding the configurations. The configuration is selected by creating a symbolic link pointing to it from the "os_desc" directory located at the top of a gadget's directory hierarchy. One kind of "OS Descriptors" are "Extended Compatibility Descriptors", which need to be specified per interface. This patch adds interface. directory in function's configfs directory to represent each interface defined by the function. Each interface's directory contains two attributes: "compatible_id" and "sub_compatible_id", which represent 8-byte strings to be reported to the host as the "Compatible ID" and "Sub Compatible ID". Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget index 0e7b786..5c0b3e6 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget +++ b/Documentation/ABI/testing/configfs-usb-gadget @@ -62,6 +62,19 @@ KernelVersion: 3.11 Description: This group contains functions available to this USB gadget. +What: /config/usb-gadget/gadget/functions/./interface. +Date: May 2014 +KernelVersion: 3.16 +Description: + This group contains "Feature Descriptors" specific for one + gadget's USB interface or one interface group described + by an IAD. + + The attributes: + + compatible_id - 8-byte string for "Compatible ID" + sub_compatible_id - 8-byte string for "Sub Compatible ID" + What: /config/usb-gadget/gadget/strings Date: Jun 2013 KernelVersion: 3.11 diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 8b9e038..fa6cb06 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -6,6 +6,7 @@ #include #include #include "configfs.h" +#include "u_f.h" int check_user_usb_string(const char *name, struct usb_gadget_strings *stringtab_dev) @@ -872,10 +873,63 @@ static void os_desc_attr_release(struct config_item *item) kfree(os_desc); } +static int os_desc_link(struct config_item *os_desc_ci, + struct config_item *usb_cfg_ci) +{ + struct gadget_info *gi = container_of(to_config_group(os_desc_ci), + struct gadget_info, os_desc_group); + struct usb_composite_dev *cdev = &gi->cdev; + struct config_usb_cfg *c_target = + container_of(to_config_group(usb_cfg_ci), + struct config_usb_cfg, group); + struct usb_configuration *c; + int ret; + + mutex_lock(&gi->lock); + list_for_each_entry(c, &cdev->configs, list) { + if (c == &c_target->c) + break; + } + if (c != &c_target->c) { + ret = -EINVAL; + goto out; + } + + if (cdev->os_desc_config) { + ret = -EBUSY; + goto out; + } + + cdev->os_desc_config = &c_target->c; + ret = 0; + +out: + mutex_unlock(&gi->lock); + return ret; +} + +static int os_desc_unlink(struct config_item *os_desc_ci, + struct config_item *usb_cfg_ci) +{ + struct gadget_info *gi = container_of(to_config_group(os_desc_ci), + struct gadget_info, os_desc_group); + struct usb_composite_dev *cdev = &gi->cdev; + + mutex_lock(&gi->lock); + if (gi->udc_name) + unregister_gadget(gi); + cdev->os_desc_config = NULL; + WARN_ON(gi->udc_name); + mutex_unlock(&gi->lock); + return 0; +} + static struct configfs_item_operations os_desc_ops = { .release = os_desc_attr_release, .show_attribute = os_desc_attr_show, .store_attribute = os_desc_attr_store, + .allow_link = os_desc_link, + .drop_link = os_desc_unlink, }; static struct config_item_type os_desc_type = { @@ -884,6 +938,133 @@ static struct config_item_type os_desc_type = { .ct_owner = THIS_MODULE, }; +CONFIGFS_ATTR_STRUCT(usb_os_desc); +CONFIGFS_ATTR_OPS(usb_os_desc); + +static struct configfs_item_operations interf_item_ops = { + .show_attribute = usb_os_desc_attr_show, + .store_attribute = usb_os_desc_attr_store, +}; + +static ssize_t rndis_grp_compatible_id_show(struct usb_os_desc *desc, + char *page) +{ + memcpy(page, desc->ext_compat_id, 8); + return 8; +} + +static ssize_t rndis_grp_compatible_id_store(struct usb_os_desc *desc, + const char *page, size_t len) +{ + int l; + + l = min_t(int, 8, len); + if (page[l - 1] == '\n') + --l; + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + memcpy(desc->ext_compat_id, page, l); + desc->ext_compat_id[l] = '\0'; + + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + + return len; +} + +static struct usb_os_desc_attribute rndis_grp_attr_compatible_id = + __CONFIGFS_ATTR(compatible_id, S_IRUGO | S_IWUSR, + rndis_grp_compatible_id_show, + rndis_grp_compatible_id_store); + +static ssize_t rndis_grp_sub_compatible_id_show(struct usb_os_desc *desc, + char *page) +{ + memcpy(page, desc->ext_compat_id + 8, 8); + return 8; +} + +static ssize_t rndis_grp_sub_compatible_id_store(struct usb_os_desc *desc, + const char *page, size_t len) +{ + int l; + + l = min_t(int, 8, len); + if (page[l - 1] == '\n') + --l; + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + memcpy(desc->ext_compat_id + 8, page, l); + desc->ext_compat_id[l + 8] = '\0'; + + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + + return len; +} + +static struct usb_os_desc_attribute rndis_grp_attr_sub_compatible_id = + __CONFIGFS_ATTR(sub_compatible_id, S_IRUGO | S_IWUSR, + rndis_grp_sub_compatible_id_show, + rndis_grp_sub_compatible_id_store); + +static struct configfs_attribute *interf_grp_attrs[] = { + &rndis_grp_attr_compatible_id.attr, + &rndis_grp_attr_sub_compatible_id.attr, + NULL +}; + +int usb_os_desc_prepare_interf_dir(struct config_group *parent, + int n_interf, + struct usb_os_desc **desc, + struct module *owner) +{ + struct config_group **f_default_groups, *os_desc_group, + **interface_groups; + struct config_item_type *os_desc_type, *interface_type; + + vla_group(data_chunk); + vla_item(data_chunk, struct config_group *, f_default_groups, 2); + vla_item(data_chunk, struct config_group, os_desc_group, 1); + vla_item(data_chunk, struct config_group *, interface_groups, + n_interf + 1); + vla_item(data_chunk, struct config_item_type, os_desc_type, 1); + vla_item(data_chunk, struct config_item_type, interface_type, 1); + + char *vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL); + if (!vlabuf) + return -ENOMEM; + + f_default_groups = vla_ptr(vlabuf, data_chunk, f_default_groups); + os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group); + os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type); + interface_groups = vla_ptr(vlabuf, data_chunk, interface_groups); + interface_type = vla_ptr(vlabuf, data_chunk, interface_type); + + parent->default_groups = f_default_groups; + os_desc_type->ct_owner = owner; + config_group_init_type_name(os_desc_group, "os_desc", os_desc_type); + f_default_groups[0] = os_desc_group; + + os_desc_group->default_groups = interface_groups; + interface_type->ct_item_ops = &interf_item_ops; + interface_type->ct_attrs = interf_grp_attrs; + interface_type->ct_owner = owner; + + while (n_interf--) { + struct usb_os_desc *d; + + d = desc[n_interf]; + config_group_init_type_name(&d->group, "", interface_type); + config_item_set_name(&d->group.cg_item, "interface.%d", + n_interf); + interface_groups[n_interf] = &d->group; + } + + return 0; +} +EXPORT_SYMBOL(usb_os_desc_prepare_interf_dir); + static int configfs_do_nothing(struct usb_composite_dev *cdev) { WARN_ON(1); @@ -893,6 +1074,9 @@ static int configfs_do_nothing(struct usb_composite_dev *cdev) int composite_dev_prepare(struct usb_composite_driver *composite, struct usb_composite_dev *dev); +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, + struct usb_ep *ep0); + static void purge_configs_funcs(struct gadget_info *gi) { struct usb_configuration *c; @@ -1028,6 +1212,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget, } usb_ep_autoconfig_reset(cdev->gadget); } + if (cdev->use_os_string) { + ret = composite_os_desc_req_prepare(cdev, gadget->ep0); + if (ret) + goto err_purge_funcs; + } + usb_ep_autoconfig_reset(cdev->gadget); return 0; diff --git a/drivers/usb/gadget/configfs.h b/drivers/usb/gadget/configfs.h index a7b564a..a14ac79 100644 --- a/drivers/usb/gadget/configfs.h +++ b/drivers/usb/gadget/configfs.h @@ -1,6 +1,18 @@ #ifndef USB__GADGET__CONFIGFS__H #define USB__GADGET__CONFIGFS__H +#include + void unregister_gadget_item(struct config_item *item); +int usb_os_desc_prepare_interf_dir(struct config_group *parent, + int n_interf, + struct usb_os_desc **desc, + struct module *owner); + +static inline struct usb_os_desc *to_usb_os_desc(struct config_item *item) +{ + return container_of(to_config_group(item), struct usb_os_desc, group); +} + #endif /* USB__GADGET__CONFIGFS__H */ diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 549f538..9c3903d 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -80,12 +80,16 @@ struct usb_os_desc_ext_prop { * @ext_prop: Extended Properties list * @ext_prop_len: Total length of Extended Properties blobs * @ext_prop_count: Number of Extended Properties + * @opts_mutex: Optional mutex protecting config data of a usb_function_instance + * @group: Represents OS descriptors associated with an interface in configfs */ struct usb_os_desc { char *ext_compat_id; struct list_head ext_prop; int ext_prop_len; int ext_prop_count; + struct mutex *opts_mutex; + struct config_group group; }; /** @@ -381,6 +385,8 @@ extern void usb_composite_unregister(struct usb_composite_driver *driver); extern void usb_composite_setup_continue(struct usb_composite_dev *cdev); extern int composite_dev_prepare(struct usb_composite_driver *composite, struct usb_composite_dev *cdev); +extern int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, + struct usb_ep *ep0); void composite_dev_cleanup(struct usb_composite_dev *cdev); static inline struct usb_composite_driver *to_cdriver( -- cgit v0.10.2 From a747b0958b5ead2d4ba46dc1f77d46e693a06efa Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 8 May 2014 14:06:27 +0200 Subject: usb: gadget: f_rndis: OS Descriptors configfs support Added handling of OS Descriptors support for f_rndis. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 28d1891..f1bf576 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -27,6 +27,7 @@ #include "u_ether_configfs.h" #include "u_rndis.h" #include "rndis.h" +#include "configfs.h" /* * This function is an RNDIS Ethernet port -- a Microsoft protocol that's @@ -895,12 +896,15 @@ static void rndis_free_inst(struct usb_function_instance *f) else free_netdev(opts->net); } + + kfree(opts->rndis_os_desc.group.default_groups); /* single VLA chunk */ kfree(opts); } static struct usb_function_instance *rndis_alloc_inst(void) { struct f_rndis_opts *opts; + struct usb_os_desc *descs[1]; opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) @@ -917,6 +921,9 @@ static struct usb_function_instance *rndis_alloc_inst(void) } INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); + descs[0] = &opts->rndis_os_desc; + usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, + THIS_MODULE); config_group_init_type_name(&opts->func_inst.group, "", &rndis_func_type); -- cgit v0.10.2 From 7419485f197c436d41535df78ddea1085042d271 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 8 May 2014 14:06:28 +0200 Subject: usb: gadget: configfs: OS Extended Properties descriptors support Add handling of OS Extended Properties descriptors from configfs interface. One kind of "OS Descriptors" are "Extended Properties" descriptors, which need to be specified per interface or per group of interfaces described by an IAD. This patch adds support for creating subdirectories in interface. directory located in the function's directory. Names of subdirectories created become names of properties. Each property contains two attributes: "type" and "data". The type can be a numeric value 1..7 while data is a blob interpreted depending on the type specified. The types are: 1 - unicode string 2 - unicode string with environment variables 3 - binary 4 - little-endian 32-bit 5 - big-endian 32-bit 6 - unicode string with a symbolic link 7 - multiple unicode strings Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget index 5c0b3e6..95a3658 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget +++ b/Documentation/ABI/testing/configfs-usb-gadget @@ -75,6 +75,27 @@ Description: compatible_id - 8-byte string for "Compatible ID" sub_compatible_id - 8-byte string for "Sub Compatible ID" +What: /config/usb-gadget/gadget/functions/./interface./ +Date: May 2014 +KernelVersion: 3.16 +Description: + This group contains "Extended Property Descriptors" specific for one + gadget's USB interface or one interface group described + by an IAD. + + The attributes: + + type - value 1..7 for interpreting the data + 1: unicode string + 2: unicode string with environment variable + 3: binary + 4: little-endian 32-bit + 5: big-endian 32-bit + 6: unicode string with a symbolic link + 7: multiple unicode strings + data - blob of data to be interpreted depending on + type + What: /config/usb-gadget/gadget/strings Date: Jun 2013 KernelVersion: 3.11 diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index fa6cb06..2ddcd63 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -7,6 +7,7 @@ #include #include "configfs.h" #include "u_f.h" +#include "u_os_desc.h" int check_user_usb_string(const char *name, struct usb_gadget_strings *stringtab_dev) @@ -941,6 +942,204 @@ static struct config_item_type os_desc_type = { CONFIGFS_ATTR_STRUCT(usb_os_desc); CONFIGFS_ATTR_OPS(usb_os_desc); + +static inline struct usb_os_desc_ext_prop +*to_usb_os_desc_ext_prop(struct config_item *item) +{ + return container_of(item, struct usb_os_desc_ext_prop, item); +} + +CONFIGFS_ATTR_STRUCT(usb_os_desc_ext_prop); +CONFIGFS_ATTR_OPS(usb_os_desc_ext_prop); + +static ssize_t ext_prop_type_show(struct usb_os_desc_ext_prop *ext_prop, + char *page) +{ + return sprintf(page, "%d", ext_prop->type); +} + +static ssize_t ext_prop_type_store(struct usb_os_desc_ext_prop *ext_prop, + const char *page, size_t len) +{ + struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); + u8 type; + int ret; + + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + ret = kstrtou8(page, 0, &type); + if (ret) + goto end; + if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI) { + ret = -EINVAL; + goto end; + } + + if ((ext_prop->type == USB_EXT_PROP_BINARY || + ext_prop->type == USB_EXT_PROP_LE32 || + ext_prop->type == USB_EXT_PROP_BE32) && + (type == USB_EXT_PROP_UNICODE || + type == USB_EXT_PROP_UNICODE_ENV || + type == USB_EXT_PROP_UNICODE_LINK)) + ext_prop->data_len <<= 1; + else if ((ext_prop->type == USB_EXT_PROP_UNICODE || + ext_prop->type == USB_EXT_PROP_UNICODE_ENV || + ext_prop->type == USB_EXT_PROP_UNICODE_LINK) && + (type == USB_EXT_PROP_BINARY || + type == USB_EXT_PROP_LE32 || + type == USB_EXT_PROP_BE32)) + ext_prop->data_len >>= 1; + ext_prop->type = type; + ret = len; + +end: + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + return ret; +} + +static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop, + char *page) +{ + int len = ext_prop->data_len; + + if (ext_prop->type == USB_EXT_PROP_UNICODE || + ext_prop->type == USB_EXT_PROP_UNICODE_ENV || + ext_prop->type == USB_EXT_PROP_UNICODE_LINK) + len >>= 1; + memcpy(page, ext_prop->data, len); + + return len; +} + +static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop, + const char *page, size_t len) +{ + struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); + char *new_data; + size_t ret_len = len; + + if (page[len - 1] == '\n' || page[len - 1] == '\0') + --len; + new_data = kzalloc(len, GFP_KERNEL); + if (!new_data) + return -ENOMEM; + + memcpy(new_data, page, len); + + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + kfree(ext_prop->data); + ext_prop->data = new_data; + desc->ext_prop_len -= ext_prop->data_len; + ext_prop->data_len = len; + desc->ext_prop_len += ext_prop->data_len; + if (ext_prop->type == USB_EXT_PROP_UNICODE || + ext_prop->type == USB_EXT_PROP_UNICODE_ENV || + ext_prop->type == USB_EXT_PROP_UNICODE_LINK) { + desc->ext_prop_len -= ext_prop->data_len; + ext_prop->data_len <<= 1; + ext_prop->data_len += 2; + desc->ext_prop_len += ext_prop->data_len; + } + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + return ret_len; +} + +static struct usb_os_desc_ext_prop_attribute ext_prop_type = + __CONFIGFS_ATTR(type, S_IRUGO | S_IWUSR, + ext_prop_type_show, ext_prop_type_store); + +static struct usb_os_desc_ext_prop_attribute ext_prop_data = + __CONFIGFS_ATTR(data, S_IRUGO | S_IWUSR, + ext_prop_data_show, ext_prop_data_store); + +static struct configfs_attribute *ext_prop_attrs[] = { + &ext_prop_type.attr, + &ext_prop_data.attr, + NULL, +}; + +static void usb_os_desc_ext_prop_release(struct config_item *item) +{ + struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); + + kfree(ext_prop); /* frees a whole chunk */ +} + +static struct configfs_item_operations ext_prop_ops = { + .release = usb_os_desc_ext_prop_release, + .show_attribute = usb_os_desc_ext_prop_attr_show, + .store_attribute = usb_os_desc_ext_prop_attr_store, +}; + +static struct config_item *ext_prop_make( + struct config_group *group, + const char *name) +{ + struct usb_os_desc_ext_prop *ext_prop; + struct config_item_type *ext_prop_type; + struct usb_os_desc *desc; + char *vlabuf; + + vla_group(data_chunk); + vla_item(data_chunk, struct usb_os_desc_ext_prop, ext_prop, 1); + vla_item(data_chunk, struct config_item_type, ext_prop_type, 1); + + vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL); + if (!vlabuf) + return ERR_PTR(-ENOMEM); + + ext_prop = vla_ptr(vlabuf, data_chunk, ext_prop); + ext_prop_type = vla_ptr(vlabuf, data_chunk, ext_prop_type); + + desc = container_of(group, struct usb_os_desc, group); + ext_prop_type->ct_item_ops = &ext_prop_ops; + ext_prop_type->ct_attrs = ext_prop_attrs; + ext_prop_type->ct_owner = desc->owner; + + config_item_init_type_name(&ext_prop->item, name, ext_prop_type); + + ext_prop->name = kstrdup(name, GFP_KERNEL); + if (!ext_prop->name) { + kfree(vlabuf); + return ERR_PTR(-ENOMEM); + } + desc->ext_prop_len += 14; + ext_prop->name_len = 2 * strlen(ext_prop->name) + 2; + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + desc->ext_prop_len += ext_prop->name_len; + list_add_tail(&ext_prop->entry, &desc->ext_prop); + ++desc->ext_prop_count; + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + + return &ext_prop->item; +} + +static void ext_prop_drop(struct config_group *group, struct config_item *item) +{ + struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); + struct usb_os_desc *desc = to_usb_os_desc(&group->cg_item); + + if (desc->opts_mutex) + mutex_lock(desc->opts_mutex); + list_del(&ext_prop->entry); + --desc->ext_prop_count; + kfree(ext_prop->name); + desc->ext_prop_len -= (ext_prop->name_len + ext_prop->data_len + 14); + if (desc->opts_mutex) + mutex_unlock(desc->opts_mutex); + config_item_put(item); +} + +static struct configfs_group_operations interf_grp_ops = { + .make_item = &ext_prop_make, + .drop_item = &ext_prop_drop, +}; + static struct configfs_item_operations interf_item_ops = { .show_attribute = usb_os_desc_attr_show, .store_attribute = usb_os_desc_attr_store, @@ -1048,6 +1247,7 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent, os_desc_group->default_groups = interface_groups; interface_type->ct_item_ops = &interf_item_ops; + interface_type->ct_group_ops = &interf_grp_ops; interface_type->ct_attrs = interf_grp_attrs; interface_type->ct_owner = owner; @@ -1055,6 +1255,7 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent, struct usb_os_desc *d; d = desc[n_interf]; + d->owner = owner; config_group_init_type_name(&d->group, "", interface_type); config_item_set_name(&d->group.cg_item, "interface.%d", n_interf); diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 9c3903d..7373203 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -64,6 +64,7 @@ struct usb_configuration; * @name: Extended Property name * @data_len: Length of Extended Property blob (for unicode store double len) * @data: Extended Property blob + * @item: Represents this Extended Property in configfs */ struct usb_os_desc_ext_prop { struct list_head entry; @@ -72,6 +73,7 @@ struct usb_os_desc_ext_prop { char *name; int data_len; char *data; + struct config_item item; }; /** @@ -82,6 +84,7 @@ struct usb_os_desc_ext_prop { * @ext_prop_count: Number of Extended Properties * @opts_mutex: Optional mutex protecting config data of a usb_function_instance * @group: Represents OS descriptors associated with an interface in configfs + * @owner: Module associated with this OS descriptor */ struct usb_os_desc { char *ext_compat_id; @@ -90,6 +93,7 @@ struct usb_os_desc { int ext_prop_count; struct mutex *opts_mutex; struct config_group group; + struct module *owner; }; /** -- cgit v0.10.2 From b09e99ee7c2b7ee80cca128b93b07fb830e6ecad Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 May 2014 15:53:32 +0300 Subject: usb: dwc3: no need to initialize ret variable First usage of ret variable will re-write initial value. Thus, there is no need to initialize it. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index af8c8f6..3f59c12 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -626,7 +626,7 @@ static int dwc3_probe(struct platform_device *pdev) struct resource *res; struct dwc3 *dwc; - int ret = -ENOMEM; + int ret; void __iomem *regs; void *mem; diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 0ed8583..f9fb8ad 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -110,12 +110,12 @@ static int dwc3_exynos_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - int ret = -ENOMEM; + int ret; exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); if (!exynos) { dev_err(dev, "not enough memory\n"); - goto err1; + return -ENOMEM; } /* @@ -125,21 +125,20 @@ static int dwc3_exynos_probe(struct platform_device *pdev) */ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (ret) - goto err1; + return ret; platform_set_drvdata(pdev, exynos); ret = dwc3_exynos_register_phys(exynos); if (ret) { dev_err(dev, "couldn't register PHYs\n"); - goto err1; + return ret; } clk = devm_clk_get(dev, "usbdrd30"); if (IS_ERR(clk)) { dev_err(dev, "couldn't get clock\n"); - ret = -EINVAL; - goto err1; + return -EINVAL; } exynos->dev = dev; @@ -189,7 +188,6 @@ err3: regulator_disable(exynos->vdd33); err2: clk_disable_unprepare(clk); -err1: return ret; } diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 1160ff4..4af4c35 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -393,7 +393,7 @@ static int dwc3_omap_probe(struct platform_device *pdev) struct extcon_dev *edev; struct regulator *vbus_reg = NULL; - int ret = -ENOMEM; + int ret; int irq; int utmi_mode = 0; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 1ed95e0..e76d1ca 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -99,7 +99,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, struct resource res[2]; struct platform_device *dwc3; struct dwc3_pci *glue; - int ret = -ENOMEM; + int ret; struct device *dev = &pci->dev; glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e0b7910..696b472 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -584,7 +584,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, { struct dwc3 *dwc = dep->dwc; u32 reg; - int ret = -ENOMEM; + int ret; dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); -- cgit v0.10.2 From f1c7e7108109bfa12ad4544dce5cdcbf3c6f0a0a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 May 2014 15:53:33 +0300 Subject: usb: dwc3: convert to pcim_enable_device() This fixes a bug when dwc3_pci_register_phys() fails and leaves device enabled. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index e76d1ca..a60bab7 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -110,7 +110,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, glue->dev = dev; - ret = pci_enable_device(pci); + ret = pcim_enable_device(pci); if (ret) { dev_err(dev, "failed to enable pci device\n"); return -ENODEV; @@ -127,8 +127,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); if (!dwc3) { dev_err(dev, "couldn't allocate dwc3 device\n"); - ret = -ENOMEM; - goto err1; + return -ENOMEM; } memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); @@ -145,7 +144,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); if (ret) { dev_err(dev, "couldn't add resources to dwc3 device\n"); - goto err1; + return ret; } pci_set_drvdata(pci, glue); @@ -167,9 +166,6 @@ static int dwc3_pci_probe(struct pci_dev *pci, err3: platform_device_put(dwc3); -err1: - pci_disable_device(pci); - return ret; } @@ -180,7 +176,6 @@ static void dwc3_pci_remove(struct pci_dev *pci) platform_device_unregister(glue->dwc3); platform_device_unregister(glue->usb2_phy); platform_device_unregister(glue->usb3_phy); - pci_disable_device(pci); } static const struct pci_device_id dwc3_pci_id_table[] = { -- cgit v0.10.2 From 1ade5d7e179170e3cf4780ba578ebb8cc7aa15ef Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 15 May 2014 13:43:50 +0200 Subject: usb: gadget: f_uac2: don't queue new requests when shutting down In some circumstances when g_audio is being unloaded there happens an endless loop in udc driver. It has happend on a board with s3c-hsotg. If there are requests in endpoint's queue, they are completed in a loop. But completing them might cause appending new requests to the queue. This patch causes agdev_iso_complete() to return immediately if request's status is -ESHUTDOWN. If it does not return immediately, then although the current request is removed from the queue, a new one is appended to the queue, so the above mentioned loop cannot end. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index c024d27..6261db4a 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -196,7 +196,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req) struct snd_uac2_chip *uac2 = prm->uac2; /* i/f shutting down */ - if (!prm->ep_enabled) + if (!prm->ep_enabled || req->status == -ESHUTDOWN) return; /* -- cgit v0.10.2 From 79cb5b533aa9dbb05123b3b7d170e686da558a35 Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Wed, 14 May 2014 21:32:39 +0100 Subject: usb: phy: Add SMSC USB334x PHY ID adding new device id for SMSC USB334x devices. Signed-off-by: Liviu Dudau Signed-off-by: Ryan Harkin Signed-off-by: Mark Brown Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-ulpi.c b/drivers/usb/phy/phy-ulpi.c index 17ea3f2..4e3877c 100644 --- a/drivers/usb/phy/phy-ulpi.c +++ b/drivers/usb/phy/phy-ulpi.c @@ -48,6 +48,7 @@ static struct ulpi_info ulpi_ids[] = { ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"), ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"), ULPI_INFO(ULPI_ID(0x0424, 0x0007), "SMSC USB3320"), + ULPI_INFO(ULPI_ID(0x0424, 0x0009), "SMSC USB334x"), ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"), }; -- cgit v0.10.2 From 16bf900f50ec7fd2f45dc3a297d7936075cdae55 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 23 Mar 2014 16:25:09 +0100 Subject: usb: gadget: uvc: Switch to monotonic clock for buffer timestamps The wall time clock isn't useful for applications as it can jump around due to time adjustement. Switch to the monotonic clock. Signed-off-by: Laurent Pinchart Reviewed-by: Hans Verkuil Acked-by: Felipe Balbi Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index 0bb5d50..9ac4ffe1 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "uvc.h" @@ -379,14 +380,8 @@ static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, else nextbuf = NULL; - /* - * FIXME: with videobuf2, the sequence number or timestamp fields - * are valid only for video capture devices and the UVC gadget usually - * is a video output device. Keeping these until the specs are clear on - * this aspect. - */ buf->buf.v4l2_buf.sequence = queue->sequence++; - do_gettimeofday(&buf->buf.v4l2_buf.timestamp); + v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp); vb2_set_plane_payload(&buf->buf, 0, buf->bytesused); vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); -- cgit v0.10.2 From f17388cc29090a94268256f1a17445e715bc5d94 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 23 Mar 2014 16:25:09 +0100 Subject: usb: gadget: uvc: Set the V4L2 buffer field to V4L2_FIELD_NONE The UVC gadget driver doesn't support interlaced video but left the buffer field uninitialized. Set it to V4L2_FIELD_NONE. Signed-off-by: Laurent Pinchart Reviewed-by: Hans Verkuil Acked-by: Felipe Balbi Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index 9ac4ffe1..305eb49 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -380,6 +380,7 @@ static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, else nextbuf = NULL; + buf->buf.v4l2_buf.field = V4L2_FIELD_NONE; buf->buf.v4l2_buf.sequence = queue->sequence++; v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp); -- cgit v0.10.2 From c9e44b5354000386ef1324d200bf99b597756594 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 23 Mar 2014 16:19:50 +0100 Subject: usb: gadget: uvc: Set the vb2 queue timestamp flags The vb2 queue timestamp_flags field must be set by drivers, as enforced by a WARN_ON in vb2_queue_init. The UVC gadget driver failed to do so. This resulted in the following warning. [ 2.104371] g_webcam gadget: uvc_function_bind [ 2.105567] ------------[ cut here ]------------ [ 2.105567] ------------[ cut here ]------------ [ 2.106779] WARNING: CPU: 0 PID: 1 at drivers/media/v4l2-core/videobuf2-core.c:2207 vb2_queue_init+0xa3/0x113() Fix it. Reported-by: Fengguang Wu Signed-off-by: Laurent Pinchart Reviewed-by: Hans Verkuil Acked-by: Felipe Balbi Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index 305eb49..1c29bc9 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -137,6 +137,8 @@ static int uvc_queue_init(struct uvc_video_queue *queue, queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; + queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; ret = vb2_queue_init(&queue->queue); if (ret) return ret; -- cgit v0.10.2 From 84237bfb0b112a18a7c5d4d35a0663c97bdd14c6 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Thu, 15 May 2014 14:28:45 +0200 Subject: usb: gadget: net2280: Fix NULL pointer dereference When DEBUG is enabled driver->driver.name is accessed, but driver can be NULL [ 174.411689] BUG: unable to handle kernel NULL pointer dereference at 0000000000000040 [ 174.429043] RIP: 0010:[] [] net2280_stop+0xa3/0x100 [net2280] [ 174.457910] Call Trace: [ 174.459503] [] usb_gadget_remove_driver+0x5a/0xb0 [udc_core] [ 174.462693] [] usb_del_gadget_udc+0xb4/0x110 [udc_core] [ 174.464316] [] net2280_remove+0x2f/0x1c0 [net2280] Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 43e5e2f..300b3a7 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1972,7 +1972,9 @@ static int net2280_stop(struct usb_gadget *_gadget, device_remove_file (&dev->pdev->dev, &dev_attr_function); device_remove_file (&dev->pdev->dev, &dev_attr_queues); - DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name); + DEBUG(dev, "unregistered driver '%s'\n", + driver ? driver->driver.name : ""); + return 0; } -- cgit v0.10.2 From 8c240dc17d900cc6453b48bdd513f4243a9ec97d Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Fri, 16 May 2014 18:19:54 +0400 Subject: usb: musb: tusb6010: Add tusb_revision to struct musb to store the revision. Add field to store tusb6010 revision value. Read the revision at the startup and store to the variable. Signed-off-by: Matwey V. Kornilov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 47e8874..d155a15 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -339,6 +339,7 @@ struct musb { dma_addr_t async; dma_addr_t sync; void __iomem *sync_va; + u8 tusb_revision; #endif /* passed down from chip/board specific irq handlers */ diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index f38a8db..8a74642 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1012,6 +1012,7 @@ static int tusb_musb_start(struct musb *musb) goto err; } + musb->tusb_revision = tusb_get_revision(musb); ret = tusb_print_revision(musb); if (ret < 2) { printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n", -- cgit v0.10.2 From 7751b6fb05869bcb318e74420148c06577adf894 Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Fri, 16 May 2014 18:20:52 +0400 Subject: usb: musb: tusb6010: Use musb->tusb_revision instead of tusb_get_revision call. The value of the revision is stored in musb->tusb_revision, so don't re-read it every time. Exporting tusb_get_revision is not needed anymore, so the dependency loop between tusb6010 and tusb6010_omap is resolved. Signed-off-by: Matwey V. Kornilov Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 8a74642..159ef4b 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -43,7 +43,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on); * Checks the revision. We need to use the DMA register as 3.0 does not * have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV. */ -u8 tusb_get_revision(struct musb *musb) +static u8 tusb_get_revision(struct musb *musb) { void __iomem *tbase = musb->ctrl_base; u32 die_id; @@ -59,14 +59,13 @@ u8 tusb_get_revision(struct musb *musb) return rev; } -EXPORT_SYMBOL_GPL(tusb_get_revision); -static int tusb_print_revision(struct musb *musb) +static void tusb_print_revision(struct musb *musb) { void __iomem *tbase = musb->ctrl_base; u8 rev; - rev = tusb_get_revision(musb); + rev = musb->tusb_revision; pr_info("tusb: %s%i.%i %s%i.%i %s%i.%i %s%i.%i %s%i %s%i.%i\n", "prcm", @@ -85,8 +84,6 @@ static int tusb_print_revision(struct musb *musb) TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase, TUSB_DIDR1_HI)), "rev", TUSB_REV_MAJOR(rev), TUSB_REV_MINOR(rev)); - - return tusb_get_revision(musb); } #define WBUS_QUIRK_MASK (TUSB_PHY_OTG_CTRL_TESTM2 | TUSB_PHY_OTG_CTRL_TESTM1 \ @@ -350,7 +347,7 @@ static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables) u32 reg; if ((wakeup_enables & TUSB_PRCM_WBUS) - && (tusb_get_revision(musb) == TUSB_REV_30)) + && (musb->tusb_revision == TUSB_REV_30)) tusb_wbus_quirk(musb, 1); tusb_set_clock_source(musb, 0); @@ -798,7 +795,7 @@ static irqreturn_t tusb_musb_interrupt(int irq, void *__hci) u32 reg; u32 i; - if (tusb_get_revision(musb) == TUSB_REV_30) + if (musb->tusb_revision == TUSB_REV_30) tusb_wbus_quirk(musb, 0); /* there are issues re-locking the PLL on wakeup ... */ @@ -1013,10 +1010,10 @@ static int tusb_musb_start(struct musb *musb) } musb->tusb_revision = tusb_get_revision(musb); - ret = tusb_print_revision(musb); - if (ret < 2) { + tusb_print_revision(musb); + if (musb->tusb_revision < 2) { printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n", - ret); + musb->tusb_revision); goto err; } diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h index 1864e24..aec86c8 100644 --- a/drivers/usb/musb/tusb6010.h +++ b/drivers/usb/musb/tusb6010.h @@ -12,8 +12,6 @@ #ifndef __TUSB6010_H__ #define __TUSB6010_H__ -extern u8 tusb_get_revision(struct musb *musb); - #ifdef CONFIG_USB_TUSB_OMAP_DMA #define tusb_dma_omap() 1 #else diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index e33b6b2..3ce152c 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -677,7 +677,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba tusb_dma->controller.channel_program = tusb_omap_dma_program; tusb_dma->controller.channel_abort = tusb_omap_dma_abort; - if (tusb_get_revision(musb) >= TUSB_REV_30) + if (musb->tusb_revision >= TUSB_REV_30) tusb_dma->multichannel = 1; for (i = 0; i < MAX_DMAREQ; i++) { -- cgit v0.10.2