diff options
Diffstat (limited to 'drivers/usb/gadget/s3c-hsotg.c')
-rw-r--r-- | drivers/usb/gadget/s3c-hsotg.c | 80 |
1 files changed, 58 insertions, 22 deletions
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index e20bc10..1172eae 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -30,14 +30,13 @@ #include <linux/clk.h> #include <linux/regulator/consumer.h> #include <linux/of_platform.h> +#include <linux/phy/phy.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/phy.h> #include <linux/platform_data/s3c-hsotg.h> -#include <mach/map.h> - #include "s3c-hsotg.h" static const char * const s3c_hsotg_supply_names[] = { @@ -140,11 +139,13 @@ struct s3c_hsotg_ep { * @dev: The parent device supplied to the probe function * @driver: USB gadget driver * @phy: The otg phy transceiver structure for phy control. + * @uphy: The otg phy transceiver structure for old USB phy control. * @plat: The platform specific configuration data. This can be removed once * all SoCs support usb transceiver. * @regs: The memory area mapped for accessing registers. * @irq: The IRQ number we are using * @supplies: Definition of USB power supplies + * @phyif: PHY interface width * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. * @num_of_eps: Number of available EPs (excluding EP0) * @debug_root: root directrory for debugfs. @@ -161,7 +162,8 @@ struct s3c_hsotg_ep { struct s3c_hsotg { struct device *dev; struct usb_gadget_driver *driver; - struct usb_phy *phy; + struct phy *phy; + struct usb_phy *uphy; struct s3c_hsotg_plat *plat; spinlock_t lock; @@ -172,6 +174,7 @@ struct s3c_hsotg { struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; + u32 phyif; unsigned int dedicated_fifos:1; unsigned char num_of_eps; @@ -2086,13 +2089,13 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) case DSTS_EnumSpd_FS48: hsotg->gadget.speed = USB_SPEED_FULL; ep0_mps = EP0_MPS_LIMIT; - ep_mps = 64; + ep_mps = 1023; break; case DSTS_EnumSpd_HS: hsotg->gadget.speed = USB_SPEED_HIGH; ep0_mps = EP0_MPS_LIMIT; - ep_mps = 512; + ep_mps = 1024; break; case DSTS_EnumSpd_LS: @@ -2156,6 +2159,9 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, s3c_hsotg_complete_request(hsotg, ep, req, result); } + if(hsotg->dedicated_fifos) + if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072) + s3c_hsotg_txfifo_flush(hsotg, ep->index); } #define call_gadget(_hs, _entry) \ @@ -2283,7 +2289,7 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) */ /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | + writel(hsotg->phyif | GUSBCFG_TOutCal(7) | (0x5 << 10), hsotg->regs + GUSBCFG); s3c_hsotg_init_fifo(hsotg); @@ -2908,8 +2914,11 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); - if (hsotg->phy) - usb_phy_init(hsotg->phy); + if (hsotg->phy) { + phy_init(hsotg->phy); + phy_power_on(hsotg->phy); + } else if (hsotg->uphy) + usb_phy_init(hsotg->uphy); else if (hsotg->plat->phy_init) hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); } @@ -2925,8 +2934,11 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) { struct platform_device *pdev = to_platform_device(hsotg->dev); - if (hsotg->phy) - usb_phy_shutdown(hsotg->phy); + if (hsotg->phy) { + phy_power_off(hsotg->phy); + phy_exit(hsotg->phy); + } else if (hsotg->uphy) + usb_phy_shutdown(hsotg->uphy); else if (hsotg->plat->phy_exit) hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); } @@ -3152,7 +3164,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, hs_ep->parent = hsotg; hs_ep->ep.name = hs_ep->name; - hs_ep->ep.maxpacket = epnum ? 1024 : EP0_MPS_LIMIT; + usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); hs_ep->ep.ops = &s3c_hsotg_ep_ops; /* @@ -3533,7 +3545,8 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) static int s3c_hsotg_probe(struct platform_device *pdev) { struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev); - struct usb_phy *phy; + struct phy *phy; + struct usb_phy *uphy; struct device *dev = &pdev->dev; struct s3c_hsotg_ep *eps; struct s3c_hsotg *hsotg; @@ -3548,19 +3561,26 @@ static int s3c_hsotg_probe(struct platform_device *pdev) return -ENOMEM; } - phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + /* + * Attempt to find a generic PHY, then look for an old style + * USB PHY, finally fall back to pdata + */ + phy = devm_phy_get(&pdev->dev, "usb2-phy"); if (IS_ERR(phy)) { - /* Fallback for pdata */ - plat = dev_get_platdata(&pdev->dev); - if (!plat) { - dev_err(&pdev->dev, "no platform data or transceiver defined\n"); - return -EPROBE_DEFER; - } else { + uphy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR(uphy)) { + /* Fallback for pdata */ + plat = dev_get_platdata(&pdev->dev); + if (!plat) { + dev_err(&pdev->dev, + "no platform data or transceiver defined\n"); + return -EPROBE_DEFER; + } hsotg->plat = plat; - } - } else { + } else + hsotg->uphy = uphy; + } else hsotg->phy = phy; - } hsotg->dev = dev; @@ -3627,6 +3647,19 @@ static int s3c_hsotg_probe(struct platform_device *pdev) goto err_supplies; } + /* Set default UTMI width */ + hsotg->phyif = GUSBCFG_PHYIf16; + + /* + * If using the generic PHY framework, check if the PHY bus + * width is 8-bit and set the phyif appropriately. + */ + if (hsotg->phy && (phy_get_bus_width(phy) == 8)) + hsotg->phyif = GUSBCFG_PHYIf8; + + if (hsotg->phy) + phy_init(hsotg->phy); + /* usb phy enable */ s3c_hsotg_phy_enable(hsotg); @@ -3720,6 +3753,8 @@ static int s3c_hsotg_remove(struct platform_device *pdev) } s3c_hsotg_phy_disable(hsotg); + if (hsotg->phy) + phy_exit(hsotg->phy); clk_disable_unprepare(hsotg->clk); return 0; @@ -3733,6 +3768,7 @@ static int s3c_hsotg_remove(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id s3c_hsotg_of_ids[] = { { .compatible = "samsung,s3c6400-hsotg", }, + { .compatible = "snps,dwc2", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids); |