From 591fc116f3302da915bb57d4474a61a5e8884cec Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Thu, 9 Apr 2015 11:34:22 +0300 Subject: usb: phy: msm: Use extcon framework for VBUS and ID detection On recent Qualcomm platforms VBUS and ID lines are not routed to USB PHY LINK controller. Use extcon framework to receive connect and disconnect ID and VBUS notification. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi --- include/linux/usb/msm_hsusb.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'include') diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 7dbecf9a4656..c4d956e50d09 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -18,6 +18,7 @@ #ifndef __ASM_ARCH_MSM_HSUSB_H #define __ASM_ARCH_MSM_HSUSB_H +#include #include #include #include @@ -119,6 +120,17 @@ struct msm_otg_platform_data { void (*setup_gpio)(enum usb_otg_state state); }; +/** + * struct msm_usb_cable - structure for exteternal connector cable + * state tracking + * @nb: hold event notification callback + * @conn: used for notification registration + */ +struct msm_usb_cable { + struct notifier_block nb; + struct extcon_specific_cable_nb conn; +}; + /** * struct msm_otg: OTG driver data. Shared by HCD and DCD. * @otg: USB OTG Transceiver structure. @@ -138,6 +150,8 @@ struct msm_otg_platform_data { * @chg_type: The type of charger attached. * @dcd_retires: The retry count used to track Data contact * detection process. + * @vbus: VBUS signal state trakining, using extcon framework + * @id: ID signal state trakining, using extcon framework */ struct msm_otg { struct usb_phy phy; @@ -166,6 +180,9 @@ struct msm_otg { struct reset_control *phy_rst; struct reset_control *link_rst; int vdd_levels[3]; + + struct msm_usb_cable vbus; + struct msm_usb_cable id; }; #endif -- cgit v1.2.3 From 44e42ae3a398b559c768b9b3c324d72b0b0b4479 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Thu, 9 Apr 2015 11:34:33 +0300 Subject: usb: phy: msm: Manual PHY and LINK controller VBUS change notification VBUS is not routed to USB PHY on recent Qualcomm platforms. USB controller must see VBUS in order to pull-up DP when setting RS bit. Henc configure USB PHY and LINK registers sense VBUS and enable manual pullup on D+ line. Cc: Vamsi Krishna Cc: Mayank Rana Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/msm-hsusb.txt | 4 ++++ drivers/usb/phy/phy-msm-usb.c | 26 ++++++++++++++++++++++ include/linux/usb/msm_hsusb.h | 5 +++++ include/linux/usb/msm_hsusb_hw.h | 9 ++++++++ 4 files changed, 44 insertions(+) (limited to 'include') diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index f26bcfac3d8f..bd8d9e753029 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -69,6 +69,10 @@ Optional properties: (no, min, max) where each value represents either a voltage in microvolts or a value corresponding to voltage corner. +- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy + and controller driver therefore enables pull-up explicitly + before starting controller using usbcmd run/stop bit. + - extcon: phandles to external connector devices. First phandle should point to external connector, which provide "USB" cable events, the second should point to external connector diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index ad66c67ce9a5..00c49bb1bd29 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -240,8 +240,14 @@ static void ulpi_init(struct msm_otg *motg) static int msm_phy_notify_disconnect(struct usb_phy *phy, enum usb_device_speed speed) { + struct msm_otg *motg = container_of(phy, struct msm_otg, phy); int val; + if (motg->manual_pullup) { + val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL; + usb_phy_io_write(phy, val, ULPI_CLR(ULPI_MISC_A)); + } + /* * Put the transceiver in non-driving mode. Otherwise host * may not detect soft-disconnection. @@ -422,6 +428,24 @@ static int msm_phy_init(struct usb_phy *phy) ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL); } + if (motg->manual_pullup) { + val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT; + ulpi_write(phy, val, ULPI_SET(ULPI_MISC_A)); + + val = readl(USB_GENCONFIG_2); + val |= GENCONFIG_2_SESS_VLD_CTRL_EN; + writel(val, USB_GENCONFIG_2); + + val = readl(USB_USBCMD); + val |= USBCMD_SESS_VLD_CTRL; + writel(val, USB_USBCMD); + + val = ulpi_read(phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NORMAL; + ulpi_write(phy, val, ULPI_FUNC_CTRL); + } + if (motg->phy_number) writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); @@ -1520,6 +1544,8 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX]; } + motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup"); + ext_id = ERR_PTR(-ENODEV); ext_vbus = ERR_PTR(-ENODEV); if (of_property_read_bool(node, "extcon")) { diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index c4d956e50d09..e55a1504266e 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -150,6 +150,9 @@ struct msm_usb_cable { * @chg_type: The type of charger attached. * @dcd_retires: The retry count used to track Data contact * detection process. + * @manual_pullup: true if VBUS is not routed to USB controller/phy + * and controller driver therefore enables pull-up explicitly before + * starting controller using usbcmd run/stop bit. * @vbus: VBUS signal state trakining, using extcon framework * @id: ID signal state trakining, using extcon framework */ @@ -181,6 +184,8 @@ struct msm_otg { struct reset_control *link_rst; int vdd_levels[3]; + bool manual_pullup; + struct msm_usb_cable vbus; struct msm_usb_cable id; }; diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h index a29f6030afb1..e159b39f67a2 100644 --- a/include/linux/usb/msm_hsusb_hw.h +++ b/include/linux/usb/msm_hsusb_hw.h @@ -21,6 +21,8 @@ #define USB_AHBBURST (MSM_USB_BASE + 0x0090) #define USB_AHBMODE (MSM_USB_BASE + 0x0098) +#define USB_GENCONFIG_2 (MSM_USB_BASE + 0x00a0) + #define USB_CAPLENGTH (MSM_USB_BASE + 0x0100) /* 8 bit */ #define USB_USBCMD (MSM_USB_BASE + 0x0140) @@ -30,6 +32,9 @@ #define USB_PHY_CTRL (MSM_USB_BASE + 0x0240) #define USB_PHY_CTRL2 (MSM_USB_BASE + 0x0278) +#define GENCONFIG_2_SESS_VLD_CTRL_EN BIT(7) +#define USBCMD_SESS_VLD_CTRL BIT(25) + #define USBCMD_RESET 2 #define USB_USBINTR (MSM_USB_BASE + 0x0148) @@ -50,6 +55,10 @@ #define ULPI_PWR_CLK_MNG_REG 0x88 #define OTG_COMP_DISABLE BIT(0) +#define ULPI_MISC_A 0x96 +#define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1) +#define ULPI_MISC_A_VBUSVLDEXT 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 */ -- cgit v1.2.3 From b189a2117223edbe40e0a187ae5c606cbdd6447c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Apr 2015 14:04:07 +0200 Subject: usb: phy: Remove the phy-rcar-gen2-usb driver The phy-rcar-gen2-usb driver, which supports legacy platform data only, is no longer used since commit a483dcbfa21f919c ("ARM: shmobile: lager: Remove legacy board support"). This driver was superseded by the DT-only phy-rcar-gen2 driver, which was introduced in commit 1233f59f745b237d ("phy: Renesas R-Car Gen2 PHY driver"). Signed-off-by: Geert Uytterhoeven Signed-off-by: Felipe Balbi --- drivers/usb/phy/Kconfig | 13 -- drivers/usb/phy/Makefile | 1 - drivers/usb/phy/phy-rcar-gen2-usb.c | 246 ------------------------ include/linux/platform_data/usb-rcar-gen2-phy.h | 22 --- 4 files changed, 282 deletions(-) delete mode 100644 drivers/usb/phy/phy-rcar-gen2-usb.c delete mode 100644 include/linux/platform_data/usb-rcar-gen2-phy.h (limited to 'include') diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 811f331892d7..173a5b5d8bc1 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -187,19 +187,6 @@ config USB_RCAR_PHY To compile this driver as a module, choose M here: the module will be called phy-rcar-usb. -config USB_RCAR_GEN2_PHY - tristate "Renesas R-Car Gen2 USB PHY support" - depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST - select USB_PHY - help - Say Y here to add support for the Renesas R-Car Gen2 USB PHY driver. - It is typically used to control internal USB PHY for USBHS, - and to configure shared USB channels 0 and 2. - This driver supports R8A7790 and R8A7791. - - To compile this driver as a module, choose M here: the - module will be called phy-rcar-gen2-usb. - config USB_ULPI bool "Generic ULPI Transceiver Driver" depends on ARM || ARM64 diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 75f2bba58c84..e36ab1d46d8b 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o -obj-$(CONFIG_USB_RCAR_GEN2_PHY) += phy-rcar-gen2-usb.o obj-$(CONFIG_USB_ULPI) += phy-ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c deleted file mode 100644 index f81800b6562a..000000000000 --- a/drivers/usb/phy/phy-rcar-gen2-usb.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Renesas R-Car Gen2 USB phy driver - * - * Copyright (C) 2013 Renesas Solutions Corp. - * Copyright (C) 2013 Cogent Embedded, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct rcar_gen2_usb_phy_priv { - struct usb_phy phy; - void __iomem *base; - struct clk *clk; - spinlock_t lock; - int usecount; - u32 ugctrl2; -}; - -#define usb_phy_to_priv(p) container_of(p, struct rcar_gen2_usb_phy_priv, phy) - -/* Low Power Status register */ -#define USBHS_LPSTS_REG 0x02 -#define USBHS_LPSTS_SUSPM (1 << 14) - -/* USB General control register */ -#define USBHS_UGCTRL_REG 0x80 -#define USBHS_UGCTRL_CONNECT (1 << 2) -#define USBHS_UGCTRL_PLLRESET (1 << 0) - -/* USB General control register 2 */ -#define USBHS_UGCTRL2_REG 0x84 -#define USBHS_UGCTRL2_USB0_PCI (1 << 4) -#define USBHS_UGCTRL2_USB0_HS (3 << 4) -#define USBHS_UGCTRL2_USB2_PCI (0 << 31) -#define USBHS_UGCTRL2_USB2_SS (1 << 31) - -/* USB General status register */ -#define USBHS_UGSTS_REG 0x88 -#define USBHS_UGSTS_LOCK (1 << 8) - -/* Enable USBHS internal phy */ -static int __rcar_gen2_usbhs_phy_enable(void __iomem *base) -{ - u32 val; - int i; - - /* USBHS PHY power on */ - val = ioread32(base + USBHS_UGCTRL_REG); - val &= ~USBHS_UGCTRL_PLLRESET; - iowrite32(val, base + USBHS_UGCTRL_REG); - - val = ioread16(base + USBHS_LPSTS_REG); - val |= USBHS_LPSTS_SUSPM; - iowrite16(val, base + USBHS_LPSTS_REG); - - for (i = 0; i < 20; i++) { - val = ioread32(base + USBHS_UGSTS_REG); - if ((val & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) { - val = ioread32(base + USBHS_UGCTRL_REG); - val |= USBHS_UGCTRL_CONNECT; - iowrite32(val, base + USBHS_UGCTRL_REG); - return 0; - } - udelay(1); - } - - /* Timed out waiting for the PLL lock */ - return -ETIMEDOUT; -} - -/* Disable USBHS internal phy */ -static int __rcar_gen2_usbhs_phy_disable(void __iomem *base) -{ - u32 val; - - /* USBHS PHY power off */ - val = ioread32(base + USBHS_UGCTRL_REG); - val &= ~USBHS_UGCTRL_CONNECT; - iowrite32(val, base + USBHS_UGCTRL_REG); - - val = ioread16(base + USBHS_LPSTS_REG); - val &= ~USBHS_LPSTS_SUSPM; - iowrite16(val, base + USBHS_LPSTS_REG); - - val = ioread32(base + USBHS_UGCTRL_REG); - val |= USBHS_UGCTRL_PLLRESET; - iowrite32(val, base + USBHS_UGCTRL_REG); - return 0; -} - -/* Setup USB channels */ -static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv) -{ - u32 val; - - clk_prepare_enable(priv->clk); - - /* Set USB channels in the USBHS UGCTRL2 register */ - val = ioread32(priv->base + USBHS_UGCTRL2_REG); - val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS); - val |= priv->ugctrl2; - iowrite32(val, priv->base + USBHS_UGCTRL2_REG); -} - -/* Shutdown USB channels */ -static void __rcar_gen2_usb_phy_shutdown(struct rcar_gen2_usb_phy_priv *priv) -{ - __rcar_gen2_usbhs_phy_disable(priv->base); - clk_disable_unprepare(priv->clk); -} - -static int rcar_gen2_usb_phy_set_suspend(struct usb_phy *phy, int suspend) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - int retval; - - spin_lock_irqsave(&priv->lock, flags); - retval = suspend ? __rcar_gen2_usbhs_phy_disable(priv->base) : - __rcar_gen2_usbhs_phy_enable(priv->base); - spin_unlock_irqrestore(&priv->lock, flags); - return retval; -} - -static int rcar_gen2_usb_phy_init(struct usb_phy *phy) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - /* - * Enable the clock and setup USB channels - * if it's the first user - */ - if (!priv->usecount++) - __rcar_gen2_usb_phy_init(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; -} - -static void rcar_gen2_usb_phy_shutdown(struct usb_phy *phy) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!priv->usecount) { - dev_warn(phy->dev, "Trying to disable phy with 0 usecount\n"); - goto out; - } - - /* Disable everything if it's the last user */ - if (!--priv->usecount) - __rcar_gen2_usb_phy_shutdown(priv); -out: - spin_unlock_irqrestore(&priv->lock, flags); -} - -static int rcar_gen2_usb_phy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct rcar_gen2_phy_platform_data *pdata; - struct rcar_gen2_usb_phy_priv *priv; - struct resource *res; - void __iomem *base; - struct clk *clk; - int retval; - - pdata = dev_get_platdata(dev); - if (!pdata) { - dev_err(dev, "No platform data\n"); - return -EINVAL; - } - - clk = devm_clk_get(dev, "usbhs"); - if (IS_ERR(clk)) { - dev_err(dev, "Can't get the clock\n"); - return PTR_ERR(clk); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - spin_lock_init(&priv->lock); - priv->clk = clk; - priv->base = base; - priv->ugctrl2 = pdata->chan0_pci ? - USBHS_UGCTRL2_USB0_PCI : USBHS_UGCTRL2_USB0_HS; - priv->ugctrl2 |= pdata->chan2_pci ? - USBHS_UGCTRL2_USB2_PCI : USBHS_UGCTRL2_USB2_SS; - priv->phy.dev = dev; - priv->phy.label = dev_name(dev); - priv->phy.init = rcar_gen2_usb_phy_init; - priv->phy.shutdown = rcar_gen2_usb_phy_shutdown; - priv->phy.set_suspend = rcar_gen2_usb_phy_set_suspend; - - retval = usb_add_phy_dev(&priv->phy); - if (retval < 0) { - dev_err(dev, "Failed to add USB phy\n"); - return retval; - } - - platform_set_drvdata(pdev, priv); - - return retval; -} - -static int rcar_gen2_usb_phy_remove(struct platform_device *pdev) -{ - struct rcar_gen2_usb_phy_priv *priv = platform_get_drvdata(pdev); - - usb_remove_phy(&priv->phy); - - return 0; -} - -static struct platform_driver rcar_gen2_usb_phy_driver = { - .driver = { - .name = "usb_phy_rcar_gen2", - }, - .probe = rcar_gen2_usb_phy_probe, - .remove = rcar_gen2_usb_phy_remove, -}; - -module_platform_driver(rcar_gen2_usb_phy_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Renesas R-Car Gen2 USB phy"); -MODULE_AUTHOR("Valentine Barshak "); diff --git a/include/linux/platform_data/usb-rcar-gen2-phy.h b/include/linux/platform_data/usb-rcar-gen2-phy.h deleted file mode 100644 index dd3ba46c0d90..000000000000 --- a/include/linux/platform_data/usb-rcar-gen2-phy.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2013 Renesas Solutions Corp. - * Copyright (C) 2013 Cogent Embedded, Inc. - * - * 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 __USB_RCAR_GEN2_PHY_H -#define __USB_RCAR_GEN2_PHY_H - -#include - -struct rcar_gen2_phy_platform_data { - /* USB channel 0 configuration */ - bool chan0_pci:1; /* true: PCI USB host 0, false: USBHS */ - /* USB channel 2 configuration */ - bool chan2_pci:1; /* true: PCI USB host 2, false: USBSS */ -}; - -#endif -- cgit v1.2.3 From 34ef33f7da6b00900d3a896d33522a035a930245 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Apr 2015 14:04:07 +0200 Subject: usb: phy: Remove the phy-rcar-gen2-usb driver The phy-rcar-gen2-usb driver, which supports legacy platform data only, is no longer used since commit a483dcbfa21f919c ("ARM: shmobile: lager: Remove legacy board support"). This driver was superseded by the DT-only phy-rcar-gen2 driver, which was introduced in commit 1233f59f745b237d ("phy: Renesas R-Car Gen2 PHY driver"). Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/Kconfig | 13 -- drivers/usb/phy/Makefile | 1 - drivers/usb/phy/phy-rcar-gen2-usb.c | 246 ------------------------ include/linux/platform_data/usb-rcar-gen2-phy.h | 22 --- 4 files changed, 282 deletions(-) delete mode 100644 drivers/usb/phy/phy-rcar-gen2-usb.c delete mode 100644 include/linux/platform_data/usb-rcar-gen2-phy.h (limited to 'include') diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 2175678e674e..3cd3bee54ca6 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -186,19 +186,6 @@ config USB_RCAR_PHY To compile this driver as a module, choose M here: the module will be called phy-rcar-usb. -config USB_RCAR_GEN2_PHY - tristate "Renesas R-Car Gen2 USB PHY support" - depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST - select USB_PHY - help - Say Y here to add support for the Renesas R-Car Gen2 USB PHY driver. - It is typically used to control internal USB PHY for USBHS, - and to configure shared USB channels 0 and 2. - This driver supports R8A7790 and R8A7791. - - To compile this driver as a module, choose M here: the - module will be called phy-rcar-gen2-usb. - config USB_ULPI bool "Generic ULPI Transceiver Driver" depends on ARM || ARM64 diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 75f2bba58c84..e36ab1d46d8b 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o -obj-$(CONFIG_USB_RCAR_GEN2_PHY) += phy-rcar-gen2-usb.o obj-$(CONFIG_USB_ULPI) += phy-ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c deleted file mode 100644 index f81800b6562a..000000000000 --- a/drivers/usb/phy/phy-rcar-gen2-usb.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Renesas R-Car Gen2 USB phy driver - * - * Copyright (C) 2013 Renesas Solutions Corp. - * Copyright (C) 2013 Cogent Embedded, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct rcar_gen2_usb_phy_priv { - struct usb_phy phy; - void __iomem *base; - struct clk *clk; - spinlock_t lock; - int usecount; - u32 ugctrl2; -}; - -#define usb_phy_to_priv(p) container_of(p, struct rcar_gen2_usb_phy_priv, phy) - -/* Low Power Status register */ -#define USBHS_LPSTS_REG 0x02 -#define USBHS_LPSTS_SUSPM (1 << 14) - -/* USB General control register */ -#define USBHS_UGCTRL_REG 0x80 -#define USBHS_UGCTRL_CONNECT (1 << 2) -#define USBHS_UGCTRL_PLLRESET (1 << 0) - -/* USB General control register 2 */ -#define USBHS_UGCTRL2_REG 0x84 -#define USBHS_UGCTRL2_USB0_PCI (1 << 4) -#define USBHS_UGCTRL2_USB0_HS (3 << 4) -#define USBHS_UGCTRL2_USB2_PCI (0 << 31) -#define USBHS_UGCTRL2_USB2_SS (1 << 31) - -/* USB General status register */ -#define USBHS_UGSTS_REG 0x88 -#define USBHS_UGSTS_LOCK (1 << 8) - -/* Enable USBHS internal phy */ -static int __rcar_gen2_usbhs_phy_enable(void __iomem *base) -{ - u32 val; - int i; - - /* USBHS PHY power on */ - val = ioread32(base + USBHS_UGCTRL_REG); - val &= ~USBHS_UGCTRL_PLLRESET; - iowrite32(val, base + USBHS_UGCTRL_REG); - - val = ioread16(base + USBHS_LPSTS_REG); - val |= USBHS_LPSTS_SUSPM; - iowrite16(val, base + USBHS_LPSTS_REG); - - for (i = 0; i < 20; i++) { - val = ioread32(base + USBHS_UGSTS_REG); - if ((val & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) { - val = ioread32(base + USBHS_UGCTRL_REG); - val |= USBHS_UGCTRL_CONNECT; - iowrite32(val, base + USBHS_UGCTRL_REG); - return 0; - } - udelay(1); - } - - /* Timed out waiting for the PLL lock */ - return -ETIMEDOUT; -} - -/* Disable USBHS internal phy */ -static int __rcar_gen2_usbhs_phy_disable(void __iomem *base) -{ - u32 val; - - /* USBHS PHY power off */ - val = ioread32(base + USBHS_UGCTRL_REG); - val &= ~USBHS_UGCTRL_CONNECT; - iowrite32(val, base + USBHS_UGCTRL_REG); - - val = ioread16(base + USBHS_LPSTS_REG); - val &= ~USBHS_LPSTS_SUSPM; - iowrite16(val, base + USBHS_LPSTS_REG); - - val = ioread32(base + USBHS_UGCTRL_REG); - val |= USBHS_UGCTRL_PLLRESET; - iowrite32(val, base + USBHS_UGCTRL_REG); - return 0; -} - -/* Setup USB channels */ -static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv) -{ - u32 val; - - clk_prepare_enable(priv->clk); - - /* Set USB channels in the USBHS UGCTRL2 register */ - val = ioread32(priv->base + USBHS_UGCTRL2_REG); - val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS); - val |= priv->ugctrl2; - iowrite32(val, priv->base + USBHS_UGCTRL2_REG); -} - -/* Shutdown USB channels */ -static void __rcar_gen2_usb_phy_shutdown(struct rcar_gen2_usb_phy_priv *priv) -{ - __rcar_gen2_usbhs_phy_disable(priv->base); - clk_disable_unprepare(priv->clk); -} - -static int rcar_gen2_usb_phy_set_suspend(struct usb_phy *phy, int suspend) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - int retval; - - spin_lock_irqsave(&priv->lock, flags); - retval = suspend ? __rcar_gen2_usbhs_phy_disable(priv->base) : - __rcar_gen2_usbhs_phy_enable(priv->base); - spin_unlock_irqrestore(&priv->lock, flags); - return retval; -} - -static int rcar_gen2_usb_phy_init(struct usb_phy *phy) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - /* - * Enable the clock and setup USB channels - * if it's the first user - */ - if (!priv->usecount++) - __rcar_gen2_usb_phy_init(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return 0; -} - -static void rcar_gen2_usb_phy_shutdown(struct usb_phy *phy) -{ - struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!priv->usecount) { - dev_warn(phy->dev, "Trying to disable phy with 0 usecount\n"); - goto out; - } - - /* Disable everything if it's the last user */ - if (!--priv->usecount) - __rcar_gen2_usb_phy_shutdown(priv); -out: - spin_unlock_irqrestore(&priv->lock, flags); -} - -static int rcar_gen2_usb_phy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct rcar_gen2_phy_platform_data *pdata; - struct rcar_gen2_usb_phy_priv *priv; - struct resource *res; - void __iomem *base; - struct clk *clk; - int retval; - - pdata = dev_get_platdata(dev); - if (!pdata) { - dev_err(dev, "No platform data\n"); - return -EINVAL; - } - - clk = devm_clk_get(dev, "usbhs"); - if (IS_ERR(clk)) { - dev_err(dev, "Can't get the clock\n"); - return PTR_ERR(clk); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - spin_lock_init(&priv->lock); - priv->clk = clk; - priv->base = base; - priv->ugctrl2 = pdata->chan0_pci ? - USBHS_UGCTRL2_USB0_PCI : USBHS_UGCTRL2_USB0_HS; - priv->ugctrl2 |= pdata->chan2_pci ? - USBHS_UGCTRL2_USB2_PCI : USBHS_UGCTRL2_USB2_SS; - priv->phy.dev = dev; - priv->phy.label = dev_name(dev); - priv->phy.init = rcar_gen2_usb_phy_init; - priv->phy.shutdown = rcar_gen2_usb_phy_shutdown; - priv->phy.set_suspend = rcar_gen2_usb_phy_set_suspend; - - retval = usb_add_phy_dev(&priv->phy); - if (retval < 0) { - dev_err(dev, "Failed to add USB phy\n"); - return retval; - } - - platform_set_drvdata(pdev, priv); - - return retval; -} - -static int rcar_gen2_usb_phy_remove(struct platform_device *pdev) -{ - struct rcar_gen2_usb_phy_priv *priv = platform_get_drvdata(pdev); - - usb_remove_phy(&priv->phy); - - return 0; -} - -static struct platform_driver rcar_gen2_usb_phy_driver = { - .driver = { - .name = "usb_phy_rcar_gen2", - }, - .probe = rcar_gen2_usb_phy_probe, - .remove = rcar_gen2_usb_phy_remove, -}; - -module_platform_driver(rcar_gen2_usb_phy_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Renesas R-Car Gen2 USB phy"); -MODULE_AUTHOR("Valentine Barshak "); diff --git a/include/linux/platform_data/usb-rcar-gen2-phy.h b/include/linux/platform_data/usb-rcar-gen2-phy.h deleted file mode 100644 index dd3ba46c0d90..000000000000 --- a/include/linux/platform_data/usb-rcar-gen2-phy.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2013 Renesas Solutions Corp. - * Copyright (C) 2013 Cogent Embedded, Inc. - * - * 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 __USB_RCAR_GEN2_PHY_H -#define __USB_RCAR_GEN2_PHY_H - -#include - -struct rcar_gen2_phy_platform_data { - /* USB channel 0 configuration */ - bool chan0_pci:1; /* true: PCI USB host 0, false: USBHS */ - /* USB channel 2 configuration */ - bool chan2_pci:1; /* true: PCI USB host 2, false: USBSS */ -}; - -#endif -- cgit v1.2.3 From 6be109b31ccdb9c98e7be12687171f6602527a5d Mon Sep 17 00:00:00 2001 From: Arun Ramamurthy Date: Wed, 22 Apr 2015 16:04:11 -0700 Subject: phy: core: Add devm_of_phy_get_by_index to phy-core Some generic drivers, such as ehci, may use multiple phys and for such drivers referencing phy(s) by name(s) does not make sense. Instead of inventing new naming schemes and using custom code to iterate through them, such drivers are better of using nameless phy bindings and using this newly introduced API to iterate through them. Signed-off-by: Arun Ramamurthy Reviewed-by: Ray Jui Reviewed-by: Scott Branden [kishon@ti.com: fix compilation errors] Signed-off-by: Kishon Vijay Abraham I --- Documentation/phy.txt | 7 ++++++- drivers/phy/phy-core.c | 32 ++++++++++++++++++++++++++++++++ include/linux/phy/phy.h | 9 +++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/phy.txt b/Documentation/phy.txt index 371361c69a4b..b388c5af9e72 100644 --- a/Documentation/phy.txt +++ b/Documentation/phy.txt @@ -76,6 +76,8 @@ struct phy *phy_get(struct device *dev, const char *string); struct phy *phy_optional_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *devm_phy_optional_get(struct device *dev, const char *string); +struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + int index); phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can be used to get the PHY. In the case of dt boot, the string arguments @@ -86,7 +88,10 @@ successful PHY get. On driver detach, release function is invoked on the the devres data and devres data is freed. phy_optional_get and devm_phy_optional_get should be used when the phy is optional. These two functions will never return -ENODEV, but instead returns NULL when -the phy cannot be found. +the phy cannot be found.Some generic drivers, such as ehci, may use multiple +phys and for such drivers referencing phy(s) by name(s) does not make sense. In +this case, devm_of_phy_get_by_index can be used to get a phy reference based on +the index. It should be noted that NULL is a valid phy reference. All phy consumer calls on the NULL phy become NOPs. That is the release calls, diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 3791838f4bd4..964a84d5a580 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -622,6 +622,38 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, } EXPORT_SYMBOL_GPL(devm_of_phy_get); +/** + * devm_of_phy_get_by_index() - lookup and obtain a reference to a phy by index. + * @dev: device that requests this phy + * @np: node containing the phy + * @index: index of the phy + * + * Gets the phy using _of_phy_get(), and associates a device with it using + * devres. On driver detach, release function is invoked on the devres data, + * then, devres data is freed. + * + */ +struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + int index) +{ + struct phy **ptr, *phy; + + ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + phy = _of_phy_get(np, index); + if (!IS_ERR(phy)) { + *ptr = phy; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return phy; +} +EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index); + /** * phy_create() - create a new phy * @dev: device that is creating the new phy diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index a0197fa1b116..8cf05e341cff 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -133,6 +133,8 @@ struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *devm_phy_optional_get(struct device *dev, const char *string); struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, const char *con_id); +struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, + int index); void phy_put(struct phy *phy); void devm_phy_put(struct device *dev, struct phy *phy); struct phy *of_phy_get(struct device_node *np, const char *con_id); @@ -261,6 +263,13 @@ static inline struct phy *devm_of_phy_get(struct device *dev, return ERR_PTR(-ENOSYS); } +static inline struct phy *devm_of_phy_get_by_index(struct device *dev, + struct device_node *np, + int index) +{ + return ERR_PTR(-ENOSYS); +} + static inline void phy_put(struct phy *phy) { } -- cgit v1.2.3 From 289fcff4bcdb1dcc0ce8788b7ea0f58a9e4a495f Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 13 May 2015 15:26:42 +0300 Subject: usb: add bus type for USB ULPI UTMI+ Low Pin Interface (ULPI) is a commonly used PHY interface for USB 2.0. The ULPI specification describes a standard set of registers which the vendors can extend for their specific needs. ULPI PHYs provide often functions such as charger detection and ADP sensing and probing. There are two major issues that the bus type is meant to tackle: Firstly, ULPI registers are accessed from the controller. The bus provides convenient method for the controller drivers to share that access with the actual PHY drivers. Secondly, there are already platforms that assume ULPI PHYs are runtime detected, such as many Intel Baytrail based platforms. They do not provide any kind of hardware description for the ULPI PHYs like separate ACPI device object that could be used to enumerate a device from. Signed-off-by: Heikki Krogerus Acked-by: David Cohen Signed-off-by: Felipe Balbi --- MAINTAINERS | 7 ++ drivers/usb/common/Makefile | 1 + drivers/usb/common/ulpi.c | 255 ++++++++++++++++++++++++++++++++++++++ drivers/usb/core/Kconfig | 20 +++ include/linux/mod_devicetable.h | 6 + include/linux/ulpi/driver.h | 60 +++++++++ include/linux/ulpi/interface.h | 23 ++++ include/linux/ulpi/regs.h | 130 +++++++++++++++++++ include/linux/usb/ulpi.h | 134 +------------------- scripts/mod/devicetable-offsets.c | 4 + scripts/mod/file2alias.c | 13 ++ 11 files changed, 521 insertions(+), 132 deletions(-) create mode 100644 drivers/usb/common/ulpi.c create mode 100644 include/linux/ulpi/driver.h create mode 100644 include/linux/ulpi/interface.h create mode 100644 include/linux/ulpi/regs.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index 2e5bbc0d68b2..2202e9194d83 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10453,6 +10453,13 @@ S: Maintained F: Documentation/video4linux/zr364xx.txt F: drivers/media/usb/zr364xx/ +ULPI BUS +M: Heikki Krogerus +L: linux-usb@vger.kernel.org +S: Maintained +F: drivers/usb/common/ulpi.c +F: include/linux/ulpi/ + USER-MODE LINUX (UML) M: Jeff Dike M: Richard Weinberger diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile index ca2f8bd0e431..6bbb3ec17018 100644 --- a/drivers/usb/common/Makefile +++ b/drivers/usb/common/Makefile @@ -7,3 +7,4 @@ usb-common-y += common.o usb-common-$(CONFIG_USB_LED_TRIG) += led.o obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o +obj-$(CONFIG_USB_ULPI_BUS) += ulpi.o diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c new file mode 100644 index 000000000000..0e6f968e93fe --- /dev/null +++ b/drivers/usb/common/ulpi.c @@ -0,0 +1,255 @@ +/** + * ulpi.c - USB ULPI PHY bus + * + * Copyright (C) 2015 Intel Corporation + * + * Author: Heikki Krogerus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +/* -------------------------------------------------------------------------- */ + +int ulpi_read(struct ulpi *ulpi, u8 addr) +{ + return ulpi->ops->read(ulpi->ops, addr); +} +EXPORT_SYMBOL_GPL(ulpi_read); + +int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val) +{ + return ulpi->ops->write(ulpi->ops, addr, val); +} +EXPORT_SYMBOL_GPL(ulpi_write); + +/* -------------------------------------------------------------------------- */ + +static int ulpi_match(struct device *dev, struct device_driver *driver) +{ + struct ulpi_driver *drv = to_ulpi_driver(driver); + struct ulpi *ulpi = to_ulpi_dev(dev); + const struct ulpi_device_id *id; + + for (id = drv->id_table; id->vendor; id++) + if (id->vendor == ulpi->id.vendor && + id->product == ulpi->id.product) + return 1; + + return 0; +} + +static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct ulpi *ulpi = to_ulpi_dev(dev); + + if (add_uevent_var(env, "MODALIAS=ulpi:v%04xp%04x", + ulpi->id.vendor, ulpi->id.product)) + return -ENOMEM; + return 0; +} + +static int ulpi_probe(struct device *dev) +{ + struct ulpi_driver *drv = to_ulpi_driver(dev->driver); + + return drv->probe(to_ulpi_dev(dev)); +} + +static int ulpi_remove(struct device *dev) +{ + struct ulpi_driver *drv = to_ulpi_driver(dev->driver); + + if (drv->remove) + drv->remove(to_ulpi_dev(dev)); + + return 0; +} + +static struct bus_type ulpi_bus = { + .name = "ulpi", + .match = ulpi_match, + .uevent = ulpi_uevent, + .probe = ulpi_probe, + .remove = ulpi_remove, +}; + +/* -------------------------------------------------------------------------- */ + +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ulpi *ulpi = to_ulpi_dev(dev); + + return sprintf(buf, "ulpi:v%04xp%04x\n", + ulpi->id.vendor, ulpi->id.product); +} +static DEVICE_ATTR_RO(modalias); + +static struct attribute *ulpi_dev_attrs[] = { + &dev_attr_modalias.attr, + NULL +}; + +static struct attribute_group ulpi_dev_attr_group = { + .attrs = ulpi_dev_attrs, +}; + +static const struct attribute_group *ulpi_dev_attr_groups[] = { + &ulpi_dev_attr_group, + NULL +}; + +static void ulpi_dev_release(struct device *dev) +{ + kfree(to_ulpi_dev(dev)); +} + +static struct device_type ulpi_dev_type = { + .name = "ulpi_device", + .groups = ulpi_dev_attr_groups, + .release = ulpi_dev_release, +}; + +/* -------------------------------------------------------------------------- */ + +/** + * ulpi_register_driver - register a driver with the ULPI bus + * @drv: driver being registered + * + * Registers a driver with the ULPI bus. + */ +int ulpi_register_driver(struct ulpi_driver *drv) +{ + if (!drv->probe) + return -EINVAL; + + drv->driver.bus = &ulpi_bus; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL_GPL(ulpi_register_driver); + +/** + * ulpi_unregister_driver - unregister a driver with the ULPI bus + * @drv: driver to unregister + * + * Unregisters a driver with the ULPI bus. + */ +void ulpi_unregister_driver(struct ulpi_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL_GPL(ulpi_unregister_driver); + +/* -------------------------------------------------------------------------- */ + +static int ulpi_register(struct device *dev, struct ulpi *ulpi) +{ + int ret; + + /* Test the interface */ + ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa); + if (ret < 0) + return ret; + + ret = ulpi_read(ulpi, ULPI_SCRATCH); + if (ret < 0) + return ret; + + if (ret != 0xaa) + return -ENODEV; + + ulpi->id.vendor = ulpi_read(ulpi, ULPI_VENDOR_ID_LOW); + ulpi->id.vendor |= ulpi_read(ulpi, ULPI_VENDOR_ID_HIGH) << 8; + + ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW); + ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8; + + ulpi->dev.parent = dev; + ulpi->dev.bus = &ulpi_bus; + ulpi->dev.type = &ulpi_dev_type; + dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev)); + + ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev)); + + request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product); + + ret = device_register(&ulpi->dev); + if (ret) + return ret; + + dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n", + ulpi->id.vendor, ulpi->id.product); + + return 0; +} + +/** + * ulpi_register_interface - instantiate new ULPI device + * @dev: USB controller's device interface + * @ops: ULPI register access + * + * Allocates and registers a ULPI device and an interface for it. Called from + * the USB controller that provides the ULPI interface. + */ +struct ulpi *ulpi_register_interface(struct device *dev, struct ulpi_ops *ops) +{ + struct ulpi *ulpi; + int ret; + + ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL); + if (!ulpi) + return ERR_PTR(-ENOMEM); + + ulpi->ops = ops; + ops->dev = dev; + + ret = ulpi_register(dev, ulpi); + if (ret) { + kfree(ulpi); + return ERR_PTR(ret); + } + + return ulpi; +} +EXPORT_SYMBOL_GPL(ulpi_register_interface); + +/** + * ulpi_unregister_interface - unregister ULPI interface + * @intrf: struct ulpi_interface + * + * Unregisters a ULPI device and it's interface that was created with + * ulpi_create_interface(). + */ +void ulpi_unregister_interface(struct ulpi *ulpi) +{ + device_unregister(&ulpi->dev); +} +EXPORT_SYMBOL_GPL(ulpi_unregister_interface); + +/* -------------------------------------------------------------------------- */ + +static int __init ulpi_init(void) +{ + return bus_register(&ulpi_bus); +} +module_init(ulpi_init); + +static void __exit ulpi_exit(void) +{ + bus_unregister(&ulpi_bus); +} +module_exit(ulpi_exit); + +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("USB ULPI PHY bus"); diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index cc0ced08bae2..a99c89e78126 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -84,3 +84,23 @@ config USB_OTG_FSM Implements OTG Finite State Machine as specified in On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification. +config USB_ULPI_BUS + tristate "USB ULPI PHY interface support" + depends on USB_SUPPORT + help + UTMI+ Low Pin Interface (ULPI) is specification for a commonly used + USB 2.0 PHY interface. The ULPI specification defines a standard set + of registers that can be used to detect the vendor and product which + allows ULPI to be handled as a bus. This module is the driver for that + bus. + + The ULPI interfaces (the buses) are registered by the drivers for USB + controllers which support ULPI register access and have ULPI PHY + attached to them. The ULPI PHY drivers themselves are normal PHY + drivers. + + ULPI PHYs provide often functions such as ADP sensing/probing (OTG + protocol) and USB charger detection. + + To compile this driver as a module, choose M here: the module will + be called ulpi. diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 3bfd56778c29..7ab00d61d30a 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -629,4 +629,10 @@ struct mcb_device_id { kernel_ulong_t driver_data; }; +struct ulpi_device_id { + __u16 vendor; + __u16 product; + kernel_ulong_t driver_data; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/ulpi/driver.h b/include/linux/ulpi/driver.h new file mode 100644 index 000000000000..388f6e08b9d4 --- /dev/null +++ b/include/linux/ulpi/driver.h @@ -0,0 +1,60 @@ +#ifndef __LINUX_ULPI_DRIVER_H +#define __LINUX_ULPI_DRIVER_H + +#include + +#include + +struct ulpi_ops; + +/** + * struct ulpi - describes ULPI PHY device + * @id: vendor and product ids for ULPI device + * @ops: I/O access + * @dev: device interface + */ +struct ulpi { + struct ulpi_device_id id; + struct ulpi_ops *ops; + struct device dev; +}; + +#define to_ulpi_dev(d) container_of(d, struct ulpi, dev) + +static inline void ulpi_set_drvdata(struct ulpi *ulpi, void *data) +{ + dev_set_drvdata(&ulpi->dev, data); +} + +static inline void *ulpi_get_drvdata(struct ulpi *ulpi) +{ + return dev_get_drvdata(&ulpi->dev); +} + +/** + * struct ulpi_driver - describes a ULPI PHY driver + * @id_table: array of device identifiers supported by this driver + * @probe: binds this driver to ULPI device + * @remove: unbinds this driver from ULPI device + * @driver: the name and owner members must be initialized by the drivers + */ +struct ulpi_driver { + const struct ulpi_device_id *id_table; + int (*probe)(struct ulpi *ulpi); + void (*remove)(struct ulpi *ulpi); + struct device_driver driver; +}; + +#define to_ulpi_driver(d) container_of(d, struct ulpi_driver, driver) + +int ulpi_register_driver(struct ulpi_driver *drv); +void ulpi_unregister_driver(struct ulpi_driver *drv); + +#define module_ulpi_driver(__ulpi_driver) \ + module_driver(__ulpi_driver, ulpi_register_driver, \ + ulpi_unregister_driver) + +int ulpi_read(struct ulpi *ulpi, u8 addr); +int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val); + +#endif /* __LINUX_ULPI_DRIVER_H */ diff --git a/include/linux/ulpi/interface.h b/include/linux/ulpi/interface.h new file mode 100644 index 000000000000..4de8ab491038 --- /dev/null +++ b/include/linux/ulpi/interface.h @@ -0,0 +1,23 @@ +#ifndef __LINUX_ULPI_INTERFACE_H +#define __LINUX_ULPI_INTERFACE_H + +#include + +struct ulpi; + +/** + * struct ulpi_ops - ULPI register access + * @dev: the interface provider + * @read: read operation for ULPI register access + * @write: write operation for ULPI register access + */ +struct ulpi_ops { + struct device *dev; + int (*read)(struct ulpi_ops *ops, u8 addr); + int (*write)(struct ulpi_ops *ops, u8 addr, u8 val); +}; + +struct ulpi *ulpi_register_interface(struct device *, struct ulpi_ops *); +void ulpi_unregister_interface(struct ulpi *); + +#endif /* __LINUX_ULPI_INTERFACE_H */ diff --git a/include/linux/ulpi/regs.h b/include/linux/ulpi/regs.h new file mode 100644 index 000000000000..b5b8b8804560 --- /dev/null +++ b/include/linux/ulpi/regs.h @@ -0,0 +1,130 @@ +#ifndef __LINUX_ULPI_REGS_H +#define __LINUX_ULPI_REGS_H + +/* + * Macros for Set and Clear + * See ULPI 1.1 specification to find the registers with Set and Clear offsets + */ +#define ULPI_SET(a) (a + 1) +#define ULPI_CLR(a) (a + 2) + +/* + * Register Map + */ +#define ULPI_VENDOR_ID_LOW 0x00 +#define ULPI_VENDOR_ID_HIGH 0x01 +#define ULPI_PRODUCT_ID_LOW 0x02 +#define ULPI_PRODUCT_ID_HIGH 0x03 +#define ULPI_FUNC_CTRL 0x04 +#define ULPI_IFC_CTRL 0x07 +#define ULPI_OTG_CTRL 0x0a +#define ULPI_USB_INT_EN_RISE 0x0d +#define ULPI_USB_INT_EN_FALL 0x10 +#define ULPI_USB_INT_STS 0x13 +#define ULPI_USB_INT_LATCH 0x14 +#define ULPI_DEBUG 0x15 +#define ULPI_SCRATCH 0x16 +/* Optional Carkit Registers */ +#define ULPI_CARKIT_CTRL 0x19 +#define ULPI_CARKIT_INT_DELAY 0x1c +#define ULPI_CARKIT_INT_EN 0x1d +#define ULPI_CARKIT_INT_STS 0x20 +#define ULPI_CARKIT_INT_LATCH 0x21 +#define ULPI_CARKIT_PLS_CTRL 0x22 +/* Other Optional Registers */ +#define ULPI_TX_POS_WIDTH 0x25 +#define ULPI_TX_NEG_WIDTH 0x26 +#define ULPI_POLARITY_RECOVERY 0x27 +/* Access Extended Register Set */ +#define ULPI_ACCESS_EXTENDED 0x2f +/* Vendor Specific */ +#define ULPI_VENDOR_SPECIFIC 0x30 +/* Extended Registers */ +#define ULPI_EXT_VENDOR_SPECIFIC 0x80 + +/* + * Register Bits + */ + +/* Function Control */ +#define ULPI_FUNC_CTRL_XCVRSEL BIT(0) +#define ULPI_FUNC_CTRL_XCVRSEL_MASK 0x3 +#define ULPI_FUNC_CTRL_HIGH_SPEED 0x0 +#define ULPI_FUNC_CTRL_FULL_SPEED 0x1 +#define ULPI_FUNC_CTRL_LOW_SPEED 0x2 +#define ULPI_FUNC_CTRL_FS4LS 0x3 +#define ULPI_FUNC_CTRL_TERMSELECT BIT(2) +#define ULPI_FUNC_CTRL_OPMODE BIT(3) +#define ULPI_FUNC_CTRL_OPMODE_MASK (0x3 << 3) +#define ULPI_FUNC_CTRL_OPMODE_NORMAL (0x0 << 3) +#define ULPI_FUNC_CTRL_OPMODE_NONDRIVING (0x1 << 3) +#define ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI (0x2 << 3) +#define ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP (0x3 << 3) +#define ULPI_FUNC_CTRL_RESET BIT(5) +#define ULPI_FUNC_CTRL_SUSPENDM BIT(6) + +/* Interface Control */ +#define ULPI_IFC_CTRL_6_PIN_SERIAL_MODE BIT(0) +#define ULPI_IFC_CTRL_3_PIN_SERIAL_MODE BIT(1) +#define ULPI_IFC_CTRL_CARKITMODE BIT(2) +#define ULPI_IFC_CTRL_CLOCKSUSPENDM BIT(3) +#define ULPI_IFC_CTRL_AUTORESUME BIT(4) +#define ULPI_IFC_CTRL_EXTERNAL_VBUS BIT(5) +#define ULPI_IFC_CTRL_PASSTHRU BIT(6) +#define ULPI_IFC_CTRL_PROTECT_IFC_DISABLE BIT(7) + +/* OTG Control */ +#define ULPI_OTG_CTRL_ID_PULLUP BIT(0) +#define ULPI_OTG_CTRL_DP_PULLDOWN BIT(1) +#define ULPI_OTG_CTRL_DM_PULLDOWN BIT(2) +#define ULPI_OTG_CTRL_DISCHRGVBUS BIT(3) +#define ULPI_OTG_CTRL_CHRGVBUS BIT(4) +#define ULPI_OTG_CTRL_DRVVBUS BIT(5) +#define ULPI_OTG_CTRL_DRVVBUS_EXT BIT(6) +#define ULPI_OTG_CTRL_EXTVBUSIND BIT(7) + +/* USB Interrupt Enable Rising, + * USB Interrupt Enable Falling, + * USB Interrupt Status and + * USB Interrupt Latch + */ +#define ULPI_INT_HOST_DISCONNECT BIT(0) +#define ULPI_INT_VBUS_VALID BIT(1) +#define ULPI_INT_SESS_VALID BIT(2) +#define ULPI_INT_SESS_END BIT(3) +#define ULPI_INT_IDGRD BIT(4) + +/* Debug */ +#define ULPI_DEBUG_LINESTATE0 BIT(0) +#define ULPI_DEBUG_LINESTATE1 BIT(1) + +/* Carkit Control */ +#define ULPI_CARKIT_CTRL_CARKITPWR BIT(0) +#define ULPI_CARKIT_CTRL_IDGNDDRV BIT(1) +#define ULPI_CARKIT_CTRL_TXDEN BIT(2) +#define ULPI_CARKIT_CTRL_RXDEN BIT(3) +#define ULPI_CARKIT_CTRL_SPKLEFTEN BIT(4) +#define ULPI_CARKIT_CTRL_SPKRIGHTEN BIT(5) +#define ULPI_CARKIT_CTRL_MICEN BIT(6) + +/* Carkit Interrupt Enable */ +#define ULPI_CARKIT_INT_EN_IDFLOAT_RISE BIT(0) +#define ULPI_CARKIT_INT_EN_IDFLOAT_FALL BIT(1) +#define ULPI_CARKIT_INT_EN_CARINTDET BIT(2) +#define ULPI_CARKIT_INT_EN_DP_RISE BIT(3) +#define ULPI_CARKIT_INT_EN_DP_FALL BIT(4) + +/* Carkit Interrupt Status and + * Carkit Interrupt Latch + */ +#define ULPI_CARKIT_INT_IDFLOAT BIT(0) +#define ULPI_CARKIT_INT_CARINTDET BIT(1) +#define ULPI_CARKIT_INT_DP BIT(2) + +/* Carkit Pulse Control*/ +#define ULPI_CARKIT_PLS_CTRL_TXPLSEN BIT(0) +#define ULPI_CARKIT_PLS_CTRL_RXPLSEN BIT(1) +#define ULPI_CARKIT_PLS_CTRL_SPKRLEFT_BIASEN BIT(2) +#define ULPI_CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN BIT(3) + +#endif /* __LINUX_ULPI_REGS_H */ diff --git a/include/linux/usb/ulpi.h b/include/linux/usb/ulpi.h index 5c295c26ad37..5f07407a367a 100644 --- a/include/linux/usb/ulpi.h +++ b/include/linux/usb/ulpi.h @@ -12,6 +12,8 @@ #define __LINUX_USB_ULPI_H #include +#include + /*-------------------------------------------------------------------------*/ /* @@ -49,138 +51,6 @@ /*-------------------------------------------------------------------------*/ -/* - * Macros for Set and Clear - * See ULPI 1.1 specification to find the registers with Set and Clear offsets - */ -#define ULPI_SET(a) (a + 1) -#define ULPI_CLR(a) (a + 2) - -/*-------------------------------------------------------------------------*/ - -/* - * Register Map - */ -#define ULPI_VENDOR_ID_LOW 0x00 -#define ULPI_VENDOR_ID_HIGH 0x01 -#define ULPI_PRODUCT_ID_LOW 0x02 -#define ULPI_PRODUCT_ID_HIGH 0x03 -#define ULPI_FUNC_CTRL 0x04 -#define ULPI_IFC_CTRL 0x07 -#define ULPI_OTG_CTRL 0x0a -#define ULPI_USB_INT_EN_RISE 0x0d -#define ULPI_USB_INT_EN_FALL 0x10 -#define ULPI_USB_INT_STS 0x13 -#define ULPI_USB_INT_LATCH 0x14 -#define ULPI_DEBUG 0x15 -#define ULPI_SCRATCH 0x16 -/* Optional Carkit Registers */ -#define ULPI_CARCIT_CTRL 0x19 -#define ULPI_CARCIT_INT_DELAY 0x1c -#define ULPI_CARCIT_INT_EN 0x1d -#define ULPI_CARCIT_INT_STS 0x20 -#define ULPI_CARCIT_INT_LATCH 0x21 -#define ULPI_CARCIT_PLS_CTRL 0x22 -/* Other Optional Registers */ -#define ULPI_TX_POS_WIDTH 0x25 -#define ULPI_TX_NEG_WIDTH 0x26 -#define ULPI_POLARITY_RECOVERY 0x27 -/* Access Extended Register Set */ -#define ULPI_ACCESS_EXTENDED 0x2f -/* Vendor Specific */ -#define ULPI_VENDOR_SPECIFIC 0x30 -/* Extended Registers */ -#define ULPI_EXT_VENDOR_SPECIFIC 0x80 - -/*-------------------------------------------------------------------------*/ - -/* - * Register Bits - */ - -/* Function Control */ -#define ULPI_FUNC_CTRL_XCVRSEL (1 << 0) -#define ULPI_FUNC_CTRL_XCVRSEL_MASK (3 << 0) -#define ULPI_FUNC_CTRL_HIGH_SPEED (0 << 0) -#define ULPI_FUNC_CTRL_FULL_SPEED (1 << 0) -#define ULPI_FUNC_CTRL_LOW_SPEED (2 << 0) -#define ULPI_FUNC_CTRL_FS4LS (3 << 0) -#define ULPI_FUNC_CTRL_TERMSELECT (1 << 2) -#define ULPI_FUNC_CTRL_OPMODE (1 << 3) -#define ULPI_FUNC_CTRL_OPMODE_MASK (3 << 3) -#define ULPI_FUNC_CTRL_OPMODE_NORMAL (0 << 3) -#define ULPI_FUNC_CTRL_OPMODE_NONDRIVING (1 << 3) -#define ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI (2 << 3) -#define ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP (3 << 3) -#define ULPI_FUNC_CTRL_RESET (1 << 5) -#define ULPI_FUNC_CTRL_SUSPENDM (1 << 6) - -/* Interface Control */ -#define ULPI_IFC_CTRL_6_PIN_SERIAL_MODE (1 << 0) -#define ULPI_IFC_CTRL_3_PIN_SERIAL_MODE (1 << 1) -#define ULPI_IFC_CTRL_CARKITMODE (1 << 2) -#define ULPI_IFC_CTRL_CLOCKSUSPENDM (1 << 3) -#define ULPI_IFC_CTRL_AUTORESUME (1 << 4) -#define ULPI_IFC_CTRL_EXTERNAL_VBUS (1 << 5) -#define ULPI_IFC_CTRL_PASSTHRU (1 << 6) -#define ULPI_IFC_CTRL_PROTECT_IFC_DISABLE (1 << 7) - -/* OTG Control */ -#define ULPI_OTG_CTRL_ID_PULLUP (1 << 0) -#define ULPI_OTG_CTRL_DP_PULLDOWN (1 << 1) -#define ULPI_OTG_CTRL_DM_PULLDOWN (1 << 2) -#define ULPI_OTG_CTRL_DISCHRGVBUS (1 << 3) -#define ULPI_OTG_CTRL_CHRGVBUS (1 << 4) -#define ULPI_OTG_CTRL_DRVVBUS (1 << 5) -#define ULPI_OTG_CTRL_DRVVBUS_EXT (1 << 6) -#define ULPI_OTG_CTRL_EXTVBUSIND (1 << 7) - -/* USB Interrupt Enable Rising, - * USB Interrupt Enable Falling, - * USB Interrupt Status and - * USB Interrupt Latch - */ -#define ULPI_INT_HOST_DISCONNECT (1 << 0) -#define ULPI_INT_VBUS_VALID (1 << 1) -#define ULPI_INT_SESS_VALID (1 << 2) -#define ULPI_INT_SESS_END (1 << 3) -#define ULPI_INT_IDGRD (1 << 4) - -/* Debug */ -#define ULPI_DEBUG_LINESTATE0 (1 << 0) -#define ULPI_DEBUG_LINESTATE1 (1 << 1) - -/* Carkit Control */ -#define ULPI_CARKIT_CTRL_CARKITPWR (1 << 0) -#define ULPI_CARKIT_CTRL_IDGNDDRV (1 << 1) -#define ULPI_CARKIT_CTRL_TXDEN (1 << 2) -#define ULPI_CARKIT_CTRL_RXDEN (1 << 3) -#define ULPI_CARKIT_CTRL_SPKLEFTEN (1 << 4) -#define ULPI_CARKIT_CTRL_SPKRIGHTEN (1 << 5) -#define ULPI_CARKIT_CTRL_MICEN (1 << 6) - -/* Carkit Interrupt Enable */ -#define ULPI_CARKIT_INT_EN_IDFLOAT_RISE (1 << 0) -#define ULPI_CARKIT_INT_EN_IDFLOAT_FALL (1 << 1) -#define ULPI_CARKIT_INT_EN_CARINTDET (1 << 2) -#define ULPI_CARKIT_INT_EN_DP_RISE (1 << 3) -#define ULPI_CARKIT_INT_EN_DP_FALL (1 << 4) - -/* Carkit Interrupt Status and - * Carkit Interrupt Latch - */ -#define ULPI_CARKIT_INT_IDFLOAT (1 << 0) -#define ULPI_CARKIT_INT_CARINTDET (1 << 1) -#define ULPI_CARKIT_INT_DP (1 << 2) - -/* Carkit Pulse Control*/ -#define ULPI_CARKIT_PLS_CTRL_TXPLSEN (1 << 0) -#define ULPI_CARKIT_PLS_CTRL_RXPLSEN (1 << 1) -#define ULPI_CARKIT_PLS_CTRL_SPKRLEFT_BIASEN (1 << 2) -#define ULPI_CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN (1 << 3) - -/*-------------------------------------------------------------------------*/ - #if IS_ENABLED(CONFIG_USB_ULPI) struct usb_phy *otg_ulpi_create(struct usb_phy_io_ops *ops, unsigned int flags); diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index fce36d0f6898..ada8417362c7 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -189,5 +189,9 @@ int main(void) DEVID_FIELD(rio_device_id, asm_did); DEVID_FIELD(rio_device_id, asm_vid); + DEVID(ulpi_device_id); + DEVID_FIELD(ulpi_device_id, vendor); + DEVID_FIELD(ulpi_device_id, product); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 78691d51a479..a7a8560db44d 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1192,6 +1192,19 @@ static int do_rio_entry(const char *filename, } ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry); +/* Looks like: ulpi:vNpN */ +static int do_ulpi_entry(const char *filename, void *symval, + char *alias) +{ + DEF_FIELD(symval, ulpi_device_id, vendor); + DEF_FIELD(symval, ulpi_device_id, product); + + sprintf(alias, "ulpi:v%04xp%04x", vendor, product); + + return 1; +} +ADD_TO_DEVTABLE("ulpi", ulpi_device_id, do_ulpi_entry); + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { -- cgit v1.2.3 From e0213bc5467ca5fe44ab04527f0e47998f30c046 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 May 2015 20:04:14 +0900 Subject: usb: renesas_usbhs: Change USBHS_TYPE_R8A779x to USBHS_TYPE_RCAR_GEN2 Since the HSUSB controllers of R-Car Gen2 are the same specification (they have 16 pipes and usb-dmac), this patch changes USBHS_TYPE_R8A7790 and USBHS_TYPE_R8A7791 to USBHS_TYPE_RCAR_GEN2. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 15 ++++----------- include/linux/usb/renesas_usbhs.h | 3 +-- 2 files changed, 5 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 0f7e850fd4aa..b56bb9d882fc 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -466,11 +466,11 @@ static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) static const struct of_device_id usbhs_of_match[] = { { .compatible = "renesas,usbhs-r8a7790", - .data = (void *)USBHS_TYPE_R8A7790, + .data = (void *)USBHS_TYPE_RCAR_GEN2, }, { .compatible = "renesas,usbhs-r8a7791", - .data = (void *)USBHS_TYPE_R8A7791, + .data = (void *)USBHS_TYPE_RCAR_GEN2, }, { }, }; @@ -497,14 +497,8 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev) if (gpio > 0) dparam->enable_gpio = gpio; - switch (dparam->type) { - case USBHS_TYPE_R8A7790: - case USBHS_TYPE_R8A7791: + if (dparam->type == USBHS_TYPE_RCAR_GEN2) dparam->has_usb_dmac = 1; - break; - default: - break; - } return info; } @@ -559,8 +553,7 @@ static int usbhs_probe(struct platform_device *pdev) sizeof(struct renesas_usbhs_driver_param)); switch (priv->dparam.type) { - case USBHS_TYPE_R8A7790: - case USBHS_TYPE_R8A7791: + case USBHS_TYPE_RCAR_GEN2: priv->pfunc = usbhs_rcar2_ops; if (!priv->dparam.pipe_type) { priv->dparam.pipe_type = usbhsc_new_pipe_type; diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index f06529c14141..3dd5a781da99 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -169,8 +169,7 @@ struct renesas_usbhs_driver_param { #define USBHS_USB_DMAC_XFER_SIZE 32 /* hardcode the xfer size */ }; -#define USBHS_TYPE_R8A7790 1 -#define USBHS_TYPE_R8A7791 2 +#define USBHS_TYPE_RCAR_GEN2 1 /* * option: -- cgit v1.2.3 From a09e23f53e2c14a65a3b14a00060fea163081e1f Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Sat, 16 May 2015 22:33:35 +0200 Subject: usb: gadget: net2280: check interrupts for all endpoints USB3380 in enhanced mode has 4 IN and 4 OUT endpoints. Check interrupts for all of them. Tested-by: Ricardo Ribalda Delgado Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 57 +++++++++++++++++++++++++++++++--------- include/linux/usb/net2280.h | 3 +++ 2 files changed, 47 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 878a98ed84f5..a78a9c048b87 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -2883,6 +2883,26 @@ next_endpoints3: return; } +static void usb338x_handle_ep_intr(struct net2280 *dev, u32 stat0) +{ + u32 index; + u32 bit; + + for (index = 0; index < ARRAY_SIZE(ep_bit); index++) { + bit = BIT(ep_bit[index]); + + if (!stat0) + break; + + if (!(stat0 & bit)) + continue; + + stat0 &= ~bit; + + handle_ep_small(&dev->ep[index]); + } +} + static void handle_stat0_irqs(struct net2280 *dev, u32 stat) { struct net2280_ep *ep; @@ -3107,20 +3127,31 @@ do_stall: #undef w_length next_endpoints: - /* endpoint data irq ? */ - scratch = stat & 0x7f; - stat &= ~0x7f; - for (num = 0; scratch; num++) { - u32 t; - - /* do this endpoint's FIFO and queue need tending? */ - t = BIT(num); - if ((scratch & t) == 0) - continue; - scratch ^= t; + if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) { + u32 mask = (BIT(ENDPOINT_0_INTERRUPT) | + USB3380_IRQSTAT0_EP_INTR_MASK_IN | + USB3380_IRQSTAT0_EP_INTR_MASK_OUT); + + if (stat & mask) { + usb338x_handle_ep_intr(dev, stat & mask); + stat &= ~mask; + } + } else { + /* endpoint data irq ? */ + scratch = stat & 0x7f; + stat &= ~0x7f; + for (num = 0; scratch; num++) { + u32 t; + + /* do this endpoint's FIFO and queue need tending? */ + t = BIT(num); + if ((scratch & t) == 0) + continue; + scratch ^= t; - ep = &dev->ep[num]; - handle_ep_small(ep); + ep = &dev->ep[num]; + handle_ep_small(ep); + } } if (stat) diff --git a/include/linux/usb/net2280.h b/include/linux/usb/net2280.h index 148b8fa5b1a2..725120224472 100644 --- a/include/linux/usb/net2280.h +++ b/include/linux/usb/net2280.h @@ -168,6 +168,9 @@ struct net2280_regs { #define ENDPOINT_B_INTERRUPT 2 #define ENDPOINT_A_INTERRUPT 1 #define ENDPOINT_0_INTERRUPT 0 +#define USB3380_IRQSTAT0_EP_INTR_MASK_IN (0xF << 17) +#define USB3380_IRQSTAT0_EP_INTR_MASK_OUT (0xF << 1) + u32 irqstat1; #define POWER_STATE_CHANGE_INTERRUPT 27 #define PCI_ARBITER_TIMEOUT_INTERRUPT 26 -- cgit v1.2.3 From c65c4f052bc3b67989bf54914798513685c54988 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Sat, 16 May 2015 22:33:36 +0200 Subject: usb: gadget: net2280: fix use of GPEP in both directions USB3380 enhanced mode allows GPEP to be used in both IN and OUT directions. However, IN and OUT endpoints must use same USB endpoint address (bEndpointAddress). Fix this by setting the ep_cfg.ep_number during initialization and keep it in net2280_enable() Tested-by: Ricardo Ribalda Delgado Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 41 +++++++++++++++++++++++++++++++--------- include/linux/usb/usb338x.h | 4 ++++ 2 files changed, 36 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index a78a9c048b87..779e6fe0005f 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -144,7 +144,9 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct net2280 *dev; struct net2280_ep *ep; - u32 max, tmp; + u32 max; + u32 tmp = 0; + u32 type; unsigned long flags; static const u32 ep_key[9] = { 1, 0, 1, 0, 1, 1, 0, 1, 0 }; int ret = 0; @@ -200,15 +202,29 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* set type, direction, address; reset fifo counters */ writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat); - tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); - if (tmp == USB_ENDPOINT_XFER_INT) { + + if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) { + tmp = readl(&ep->cfg->ep_cfg); + /* If USB ep number doesn't match hardware ep number */ + if ((tmp & 0xf) != usb_endpoint_num(desc)) { + ret = -EINVAL; + spin_unlock_irqrestore(&dev->lock, flags); + goto print_err; + } + if (ep->is_in) + tmp &= ~USB3380_EP_CFG_MASK_IN; + else + tmp &= ~USB3380_EP_CFG_MASK_OUT; + } + type = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + if (type == USB_ENDPOINT_XFER_INT) { /* erratum 0105 workaround prevents hs NYET */ if (dev->chiprev == 0100 && dev->gadget.speed == USB_SPEED_HIGH && !(desc->bEndpointAddress & USB_DIR_IN)) writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); - } else if (tmp == USB_ENDPOINT_XFER_BULK) { + } else if (type == USB_ENDPOINT_XFER_BULK) { /* catch some particularly blatant driver bugs */ if ((dev->gadget.speed == USB_SPEED_SUPER && max != 1024) || (dev->gadget.speed == USB_SPEED_HIGH && max != 512) || @@ -218,10 +234,10 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto print_err; } } - ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); + ep->is_iso = (type == USB_ENDPOINT_XFER_ISOC); /* Enable this endpoint */ if (dev->quirks & PLX_LEGACY) { - tmp <<= ENDPOINT_TYPE; + tmp |= type << ENDPOINT_TYPE; tmp |= desc->bEndpointAddress; /* default full fifo lines */ tmp |= (4 << ENDPOINT_BYTE_COUNT); @@ -230,16 +246,17 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) } else { /* In Legacy mode, only OUT endpoints are used */ if (dev->enhanced_mode && ep->is_in) { - tmp <<= IN_ENDPOINT_TYPE; + tmp |= type << IN_ENDPOINT_TYPE; tmp |= BIT(IN_ENDPOINT_ENABLE); } else { - tmp <<= OUT_ENDPOINT_TYPE; + tmp |= type << OUT_ENDPOINT_TYPE; tmp |= BIT(OUT_ENDPOINT_ENABLE); tmp |= (ep->is_in << ENDPOINT_DIRECTION); } tmp |= (4 << ENDPOINT_BYTE_COUNT); - tmp |= usb_endpoint_num(desc); + if (!dev->enhanced_mode) + tmp |= usb_endpoint_num(desc); tmp |= (ep->ep.maxburst << MAX_BURST_SIZE); } @@ -2074,6 +2091,12 @@ static void usb_reinit_338x(struct net2280 *dev) if (dev->enhanced_mode) { ep->cfg = &dev->epregs[ne[i]]; + /* + * Set USB endpoint number, hardware allows same number + * in both directions. + */ + if (i > 0 && i < 5) + writel(ne[i], &ep->cfg->ep_cfg); ep->regs = (struct net2280_ep_regs __iomem *) (((void __iomem *)&dev->epregs[ne[i]]) + ep_reg_addr[i]); diff --git a/include/linux/usb/usb338x.h b/include/linux/usb/usb338x.h index f92eb635b9d3..11525d8d89a7 100644 --- a/include/linux/usb/usb338x.h +++ b/include/linux/usb/usb338x.h @@ -43,6 +43,10 @@ #define IN_ENDPOINT_TYPE 12 #define OUT_ENDPOINT_ENABLE 10 #define OUT_ENDPOINT_TYPE 8 +#define USB3380_EP_CFG_MASK_IN ((0x3 << IN_ENDPOINT_TYPE) | \ + BIT(IN_ENDPOINT_ENABLE)) +#define USB3380_EP_CFG_MASK_OUT ((0x3 << OUT_ENDPOINT_TYPE) | \ + BIT(OUT_ENDPOINT_ENABLE)) struct usb338x_usb_ext_regs { u32 usbclass; -- cgit v1.2.3 From e842b84c8e7221c45c8dbd7de09185c6149e1cf9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 23 Mar 2015 09:52:48 +1100 Subject: usb: phy: Add interface to get phy give of device_node. Split the "get phy from device_node" functionality out of "get phy by phandle" so it can be used directly. This is useful when a battery-charger is intimately associated with a particular phy but handled by a separate driver. The charger can find the device_node based on sibling relationships without the need for a redundant declaration in the devicetree description. As a peripheral that gets a phy will often want to register a notifier block, and de-register it later, that functionality is included so the de-registration is automatic. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy.c | 97 +++++++++++++++++++++++++++++++++++-------------- include/linux/usb/phy.h | 2 + 2 files changed, 72 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index d1cd6b50f520..98f75d2842b7 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -22,6 +22,11 @@ static LIST_HEAD(phy_list); static LIST_HEAD(phy_bind_list); static DEFINE_SPINLOCK(phy_lock); +struct phy_devm { + struct usb_phy *phy; + struct notifier_block *nb; +}; + static struct usb_phy *__usb_find_phy(struct list_head *list, enum usb_phy_type type) { @@ -79,6 +84,15 @@ static void devm_usb_phy_release(struct device *dev, void *res) usb_put_phy(phy); } +static void devm_usb_phy_release2(struct device *dev, void *_res) +{ + struct phy_devm *res = _res; + + if (res->nb) + usb_unregister_notifier(res->phy, res->nb); + usb_put_phy(res->phy); +} + static int devm_usb_phy_match(struct device *dev, void *res, void *match_data) { struct usb_phy **phy = res; @@ -153,40 +167,30 @@ err0: EXPORT_SYMBOL_GPL(usb_get_phy); /** - * devm_usb_get_phy_by_phandle - find the USB PHY by phandle + * devm_usb_get_phy_by_node - find the USB PHY by device_node * @dev - device that requests this phy - * @phandle - name of the property holding the phy phandle value - * @index - the index of the phy + * @node - the device_node for the phy device. + * @nb - a notifier_block to register with the phy. * - * Returns the phy driver associated with the given phandle value, + * Returns the phy driver associated with the given device_node, * after getting a refcount to it, -ENODEV if there is no such phy or - * -EPROBE_DEFER if there is a phandle to the phy, but the device is - * not yet loaded. While at that, it also associates the device with + * -EPROBE_DEFER if the device is not yet loaded. While at that, it + * also associates the device with * the phy using devres. On driver detach, release function is invoked * on the devres data, then, devres data is freed. * - * For use by USB host and peripheral drivers. + * For use by peripheral drivers for devices related to a phy, + * such as a charger. */ -struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, - const char *phandle, u8 index) +struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, + struct device_node *node, + struct notifier_block *nb) { - struct usb_phy *phy = ERR_PTR(-ENOMEM), **ptr; + struct usb_phy *phy = ERR_PTR(-ENOMEM); + struct phy_devm *ptr; unsigned long flags; - struct device_node *node; - if (!dev->of_node) { - dev_dbg(dev, "device does not have a device node entry\n"); - return ERR_PTR(-EINVAL); - } - - node = of_parse_phandle(dev->of_node, phandle, index); - if (!node) { - dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, - dev->of_node->full_name); - return ERR_PTR(-ENODEV); - } - - ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); + ptr = devres_alloc(devm_usb_phy_release2, sizeof(*ptr), GFP_KERNEL); if (!ptr) { dev_dbg(dev, "failed to allocate memory for devres\n"); goto err0; @@ -205,8 +209,10 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, devres_free(ptr); goto err1; } - - *ptr = phy; + if (nb) + usb_register_notifier(phy, nb); + ptr->phy = phy; + ptr->nb = nb; devres_add(dev, ptr); get_device(phy->dev); @@ -215,10 +221,47 @@ err1: spin_unlock_irqrestore(&phy_lock, flags); err0: - of_node_put(node); return phy; } +EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_node); + +/** + * devm_usb_get_phy_by_phandle - find the USB PHY by phandle + * @dev - device that requests this phy + * @phandle - name of the property holding the phy phandle value + * @index - the index of the phy + * + * Returns the phy driver associated with the given phandle value, + * after getting a refcount to it, -ENODEV if there is no such phy or + * -EPROBE_DEFER if there is a phandle to the phy, but the device is + * not yet loaded. While at that, it also associates the device with + * the phy using devres. On driver detach, release function is invoked + * on the devres data, then, devres data is freed. + * + * For use by USB host and peripheral drivers. + */ +struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, + const char *phandle, u8 index) +{ + struct device_node *node; + struct usb_phy *phy; + + if (!dev->of_node) { + dev_dbg(dev, "device does not have a device node entry\n"); + return ERR_PTR(-EINVAL); + } + + node = of_parse_phandle(dev->of_node, phandle, index); + if (!node) { + dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, + dev->of_node->full_name); + return ERR_PTR(-ENODEV); + } + phy = devm_usb_get_phy_by_node(dev, node, NULL); + of_node_put(node); + return phy; +} EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle); /** diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index bc91b5d380fd..8ed1e29ef329 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -205,6 +205,8 @@ extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index); extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, const char *phandle, u8 index); +extern struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, + struct device_node *node, struct notifier_block *nb); extern void usb_put_phy(struct usb_phy *); extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); extern int usb_bind_phy(const char *dev_name, u8 index, -- cgit v1.2.3 From 24fe86a617c550fb9bdc6c8bd7cf647d3955f8ba Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 29 Mar 2015 12:50:46 +0200 Subject: phy: sun4i-usb: Add a sunxi specific function for setting squelch-detect The sunxi otg phy has a bug where it wrongly detects a high speed squelch when reset on the root port gets de-asserted with a lo-speed device. The workaround for this is to disable squelch detect before de-asserting reset, and re-enabling it after the reset de-assert is done. Add a sunxi specific phy function to allow the sunxi-musb glue to do this. Acked-by: Kishon Vijay Abraham I Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi --- drivers/phy/phy-sun4i-usb.c | 9 +++++++++ include/linux/phy/phy-sun4i-usb.h | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 include/linux/phy/phy-sun4i-usb.h (limited to 'include') diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index a2b08f3ccb03..e17c539e4f6f 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ #define PHY_OTG_FUNC_EN 0x28 #define PHY_VBUS_DET_EN 0x29 #define PHY_DISCON_TH_SEL 0x2a +#define PHY_SQUELCH_DETECT 0x3c #define MAX_PHYS 3 @@ -204,6 +206,13 @@ static int sun4i_usb_phy_power_off(struct phy *_phy) return 0; } +void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled) +{ + struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + + sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2); +} + static struct phy_ops sun4i_usb_phy_ops = { .init = sun4i_usb_phy_init, .exit = sun4i_usb_phy_exit, diff --git a/include/linux/phy/phy-sun4i-usb.h b/include/linux/phy/phy-sun4i-usb.h new file mode 100644 index 000000000000..50aed92ea89c --- /dev/null +++ b/include/linux/phy/phy-sun4i-usb.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program 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. + */ + +#ifndef PHY_SUN4I_USB_H_ +#define PHY_SUN4I_USB_H_ + +#include "phy.h" + +/** + * sun4i_usb_phy_set_squelch_detect() - Enable/disable squelch detect + * @phy: reference to a sun4i usb phy + * @enabled: wether to enable or disable squelch detect + */ +void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled); + +#endif -- cgit v1.2.3 From 307c858bc245da5229b30186546590e1d472fc8f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 28 May 2015 16:08:02 +0200 Subject: usb: phy: add static inline wrapper for devm_usb_get_phy_by_node The newly introduced devm_usb_get_phy_by_node function only has an extern declaration, but no alternative for the case that CONFIG_USB_PHY is disabled, which leads to a build error when it is used anyway: drivers/power/twl4030_charger.c: In function 'twl4030_bci_probe': drivers/power/twl4030_charger.c:648:23: error: implicit declaration of function 'devm_usb_get_phy_by_node' [-Werror=implicit-function-declaration] bci->transceiver = devm_usb_get_phy_by_node( This adds the wrapper in the same way that we have one for all other usb-phy API functions. Signed-off-by: Arnd Bergmann Fixes: e842b84c8e7 ("usb: phy: Add interface to get phy give of device_node.") Signed-off-by: Felipe Balbi --- include/linux/usb/phy.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 8ed1e29ef329..e39f251cf861 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -240,6 +240,12 @@ static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, return ERR_PTR(-ENXIO); } +static inline struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, + struct device_node *node, struct notifier_block *nb) +{ + return ERR_PTR(-ENXIO); +} + static inline void usb_put_phy(struct usb_phy *x) { } -- cgit v1.2.3 From f0e6a326deec8b51ee12f82a34057efd3d0979b8 Mon Sep 17 00:00:00 2001 From: Abhishek Bist Date: Wed, 27 May 2015 23:54:19 +0530 Subject: USB: hcd.h : Removed an unnecessary function prototype usb_find_interface_driver() This function is used to call in early version of linux kernel in order to find out the interface used by a usb device. But now it's use is completely abolished. So,it would be relevant to remove this obselete function from kernel mainline. Signed-off-by: Abhishek Bist Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/hcd.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 68b1e836dff1..c9aa7792de10 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -622,8 +622,6 @@ extern struct list_head usb_bus_list; extern struct mutex usb_bus_list_lock; extern wait_queue_head_t usb_kill_urb_queue; -extern int usb_find_interface_driver(struct usb_device *dev, - struct usb_interface *interface); #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) -- cgit v1.2.3 From 138c3f03b017e261316a4f1ec793e1ff74516def Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Tue, 26 May 2015 17:15:29 +0530 Subject: drivers:usb:fsl: Add support for USB controller version-2.5 Add support for USB controller version-2.5 used in T4240 rev2.0, T1024, T1040, T2080, LS1021A Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fsl-mph-dr-of.c | 5 +++++ include/linux/fsl_devices.h | 1 + 2 files changed, 6 insertions(+) (limited to 'include') diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index e588ccd468fc..5e0d60035216 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -127,6 +127,7 @@ static int usb_get_ver_info(struct device_node *np) * returns 1 for usb controller version 1.6 * returns 2 for usb controller version 2.2 * returns 3 for usb controller version 2.4 + * returns 4 for usb controller version 2.5 * returns 0 otherwise */ if (of_device_is_compatible(np, "fsl-usb2-dr")) { @@ -136,6 +137,8 @@ static int usb_get_ver_info(struct device_node *np) ver = FSL_USB_VER_2_2; else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.4")) ver = FSL_USB_VER_2_4; + else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.5")) + ver = FSL_USB_VER_2_5; else /* for previous controller versions */ ver = FSL_USB_VER_OLD; @@ -153,6 +156,8 @@ static int usb_get_ver_info(struct device_node *np) ver = FSL_USB_VER_2_2; else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.4")) ver = FSL_USB_VER_2_4; + else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.5")) + ver = FSL_USB_VER_2_5; else /* for previous controller versions */ ver = FSL_USB_VER_OLD; } diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index a82296af413f..2a2f56b292c1 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -24,6 +24,7 @@ #define FSL_USB_VER_1_6 1 #define FSL_USB_VER_2_2 2 #define FSL_USB_VER_2_4 3 +#define FSL_USB_VER_2_5 4 #include -- cgit v1.2.3