Merge tag 'drivers-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Aug 2014 18:34:32 +0000 (11:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Aug 2014 18:34:32 +0000 (11:34 -0700)
Pull ARM SoC driver changes from Olof Johansson:
 "A handful of driver-related changes.  We've had a bunch of them going
  in through other branches as well, so it's only a part of what we
  really have this release.

  Larger pieces are:

   - Removal of a now unused PWM driver for atmel
     [ This includes AVR32 changes that have been appropriately acked ]
   - Performance counter support for the arm CCN interconnect
   - OMAP mailbox driver cleanups and consolidation
   - PCI and SATA PHY drivers for SPEAr 13xx platforms
   - Redefinition (with backwards compatibility!) of PCI DT bindings for
     Tegra to better model regulators/power"

Note: this merge also fixes up the semantic conflict with the new
calling convention for devm_phy_create(), see commit f0ed817638b5 ("phy:
core: Let node ptr of PHY point to PHY and not of PHY provider") that
came in through Greg's USB tree.

Semantic merge patch by Stephen Rothwell <sfr@canb.auug.org.au> through
the next tree.

* tag 'drivers-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (38 commits)
  bus: arm-ccn: Fix error handling at event allocation
  mailbox/omap: add a parent structure for every IP instance
  mailbox/omap: remove the private mailbox structure
  mailbox/omap: consolidate OMAP mailbox driver
  mailbox/omap: simplify the fifo assignment by using macros
  mailbox/omap: remove omap_mbox_type_t from mailbox ops
  mailbox/omap: remove OMAP1 mailbox driver
  mailbox/omap: use devm_* interfaces
  bus: ARM CCN: add PERF_EVENTS dependency
  bus: ARM CCN PMU driver
  PCI: spear: Remove spear13xx_pcie_remove()
  PCI: spear: Fix Section mismatch compilation warning for probe()
  ARM: tegra: Remove legacy PCIe power supply properties
  PCI: tegra: Remove deprecated power supply properties
  PCI: tegra: Implement accurate power supply scheme
  ARM: SPEAr13xx: Update defconfigs
  ARM: SPEAr13xx: Add pcie and miphy DT nodes
  ARM: SPEAr13xx: Add bindings and dt node for misc block
  ARM: SPEAr13xx: Fix static mapping table
  phy: Add drivers for PCIe and SATA phy on SPEAr13xx
  ...

15 files changed:
1  2 
MAINTAINERS
arch/arm/boot/dts/tegra20-tamonten.dtsi
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-spear/spear13xx.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/pci/host/pci-tegra.c
drivers/phy/Kconfig
drivers/phy/Makefile
drivers/phy/phy-spear1310-miphy.c
drivers/phy/phy-spear1340-miphy.c
drivers/pinctrl/pinctrl-tegra-xusb.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile

diff --cc MAINTAINERS
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -197,25 -171,23 +197,37 @@@ config PHY_EXYNOS5_USBDR
          This driver provides PHY interface for USB 3.0 DRD controller
          present on Exynos5 SoC series.
  
--config PHY_XGENE
--      tristate "APM X-Gene 15Gbps PHY support"
--      depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)
-       select GENERIC_PHY
-       help
-         This option enables support for APM X-Gene SoC multi-purpose PHY.
 +config PHY_QCOM_APQ8064_SATA
 +      tristate "Qualcomm APQ8064 SATA SerDes/PHY driver"
 +      depends on ARCH_QCOM
 +      depends on HAS_IOMEM
 +      depends on OF
 +      select GENERIC_PHY
 +
 +config PHY_QCOM_IPQ806X_SATA
 +      tristate "Qualcomm IPQ806x SATA SerDes/PHY driver"
 +      depends on ARCH_QCOM
 +      depends on HAS_IOMEM
 +      depends on OF
        select GENERIC_PHY
 -      help
 -        This option enables support for APM X-Gene SoC multi-purpose PHY.
  
+ config PHY_ST_SPEAR1310_MIPHY
+       tristate "ST SPEAR1310-MIPHY driver"
+       select GENERIC_PHY
+       help
+         Support for ST SPEAr1310 MIPHY which can be used for PCIe and SATA.
+ config PHY_ST_SPEAR1340_MIPHY
+       tristate "ST SPEAR1340-MIPHY driver"
+       select GENERIC_PHY
+       help
+         Support for ST SPEAr1340 MIPHY which can be used for PCIe and SATA.
++config PHY_XGENE
++      tristate "APM X-Gene 15Gbps PHY support"
++      depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)
++      select GENERIC_PHY
++      help
++        This option enables support for APM X-Gene SoC multi-purpose PHY.
++
  endmenu
@@@ -21,8 -18,7 +21,10 @@@ phy-exynos-usb2-y                    += phy-samsung-usb2
  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o
  phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o
 +phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)    += phy-s5pv210-usb2.o
  obj-$(CONFIG_PHY_EXYNOS5_USBDRD)      += phy-exynos5-usbdrd.o
--obj-$(CONFIG_PHY_XGENE)                       += phy-xgene.o
 +obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)   += phy-qcom-apq8064-sata.o
 +obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)   += phy-qcom-ipq806x-sata.o
+ obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)  += phy-spear1310-miphy.o
+ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)  += phy-spear1340-miphy.o
++obj-$(CONFIG_PHY_XGENE)                       += phy-xgene.o
index 0000000,c58c869..6dcbfcd
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,274 +1,274 @@@
 -      priv->phy = devm_phy_create(dev, &spear1310_miphy_ops, NULL);
+ /*
+  * ST SPEAr1310-miphy driver
+  *
+  * Copyright (C) 2014 ST Microelectronics
+  * Pratyush Anand <pratyush.anand@st.com>
+  * Mohit Kumar <mohit.kumar@st.com>
+  *
+  * 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 <linux/bitops.h>
+ #include <linux/delay.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/kernel.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of_device.h>
+ #include <linux/phy/phy.h>
+ #include <linux/regmap.h>
+ /* SPEAr1310 Registers */
+ #define SPEAR1310_PCIE_SATA_CFG                       0x3A4
+       #define SPEAR1310_PCIE_SATA2_SEL_PCIE           (0 << 31)
+       #define SPEAR1310_PCIE_SATA1_SEL_PCIE           (0 << 30)
+       #define SPEAR1310_PCIE_SATA0_SEL_PCIE           (0 << 29)
+       #define SPEAR1310_PCIE_SATA2_SEL_SATA           BIT(31)
+       #define SPEAR1310_PCIE_SATA1_SEL_SATA           BIT(30)
+       #define SPEAR1310_PCIE_SATA0_SEL_SATA           BIT(29)
+       #define SPEAR1310_SATA2_CFG_TX_CLK_EN           BIT(27)
+       #define SPEAR1310_SATA2_CFG_RX_CLK_EN           BIT(26)
+       #define SPEAR1310_SATA2_CFG_POWERUP_RESET       BIT(25)
+       #define SPEAR1310_SATA2_CFG_PM_CLK_EN           BIT(24)
+       #define SPEAR1310_SATA1_CFG_TX_CLK_EN           BIT(23)
+       #define SPEAR1310_SATA1_CFG_RX_CLK_EN           BIT(22)
+       #define SPEAR1310_SATA1_CFG_POWERUP_RESET       BIT(21)
+       #define SPEAR1310_SATA1_CFG_PM_CLK_EN           BIT(20)
+       #define SPEAR1310_SATA0_CFG_TX_CLK_EN           BIT(19)
+       #define SPEAR1310_SATA0_CFG_RX_CLK_EN           BIT(18)
+       #define SPEAR1310_SATA0_CFG_POWERUP_RESET       BIT(17)
+       #define SPEAR1310_SATA0_CFG_PM_CLK_EN           BIT(16)
+       #define SPEAR1310_PCIE2_CFG_DEVICE_PRESENT      BIT(11)
+       #define SPEAR1310_PCIE2_CFG_POWERUP_RESET       BIT(10)
+       #define SPEAR1310_PCIE2_CFG_CORE_CLK_EN         BIT(9)
+       #define SPEAR1310_PCIE2_CFG_AUX_CLK_EN          BIT(8)
+       #define SPEAR1310_PCIE1_CFG_DEVICE_PRESENT      BIT(7)
+       #define SPEAR1310_PCIE1_CFG_POWERUP_RESET       BIT(6)
+       #define SPEAR1310_PCIE1_CFG_CORE_CLK_EN         BIT(5)
+       #define SPEAR1310_PCIE1_CFG_AUX_CLK_EN          BIT(4)
+       #define SPEAR1310_PCIE0_CFG_DEVICE_PRESENT      BIT(3)
+       #define SPEAR1310_PCIE0_CFG_POWERUP_RESET       BIT(2)
+       #define SPEAR1310_PCIE0_CFG_CORE_CLK_EN         BIT(1)
+       #define SPEAR1310_PCIE0_CFG_AUX_CLK_EN          BIT(0)
+       #define SPEAR1310_PCIE_CFG_MASK(x) ((0xF << (x * 4)) | BIT((x + 29)))
+       #define SPEAR1310_SATA_CFG_MASK(x) ((0xF << (x * 4 + 16)) | \
+                       BIT((x + 29)))
+       #define SPEAR1310_PCIE_CFG_VAL(x) \
+                       (SPEAR1310_PCIE_SATA##x##_SEL_PCIE | \
+                       SPEAR1310_PCIE##x##_CFG_AUX_CLK_EN | \
+                       SPEAR1310_PCIE##x##_CFG_CORE_CLK_EN | \
+                       SPEAR1310_PCIE##x##_CFG_POWERUP_RESET | \
+                       SPEAR1310_PCIE##x##_CFG_DEVICE_PRESENT)
+       #define SPEAR1310_SATA_CFG_VAL(x) \
+                       (SPEAR1310_PCIE_SATA##x##_SEL_SATA | \
+                       SPEAR1310_SATA##x##_CFG_PM_CLK_EN | \
+                       SPEAR1310_SATA##x##_CFG_POWERUP_RESET | \
+                       SPEAR1310_SATA##x##_CFG_RX_CLK_EN | \
+                       SPEAR1310_SATA##x##_CFG_TX_CLK_EN)
+ #define SPEAR1310_PCIE_MIPHY_CFG_1            0x3A8
+       #define SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT     BIT(31)
+       #define SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2       BIT(28)
+       #define SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(x)   (x << 16)
+       #define SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT   BIT(15)
+       #define SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2     BIT(12)
+       #define SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(x) (x << 0)
+       #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_MASK (0xFFFF)
+       #define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK (0xFFFF << 16)
+       #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA \
+                       (SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \
+                       SPEAR1310_MIPHY_DUAL_CLK_REF_DIV2 | \
+                       SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(60) | \
+                       SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \
+                       SPEAR1310_MIPHY_SINGLE_CLK_REF_DIV2 | \
+                       SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(60))
+       #define SPEAR1310_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \
+                       (SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(120))
+       #define SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE \
+                       (SPEAR1310_MIPHY_DUAL_OSC_BYPASS_EXT | \
+                       SPEAR1310_MIPHY_DUAL_PLL_RATIO_TOP(25) | \
+                       SPEAR1310_MIPHY_SINGLE_OSC_BYPASS_EXT | \
+                       SPEAR1310_MIPHY_SINGLE_PLL_RATIO_TOP(25))
+ #define SPEAR1310_PCIE_MIPHY_CFG_2            0x3AC
+ enum spear1310_miphy_mode {
+       SATA,
+       PCIE,
+ };
+ struct spear1310_miphy_priv {
+       /* instance id of this phy */
+       u32                             id;
+       /* phy mode: 0 for SATA 1 for PCIe */
+       enum spear1310_miphy_mode       mode;
+       /* regmap for any soc specific misc registers */
+       struct regmap                   *misc;
+       /* phy struct pointer */
+       struct phy                      *phy;
+ };
+ static int spear1310_miphy_pcie_init(struct spear1310_miphy_priv *priv)
+ {
+       u32 val;
+       regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1,
+                          SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK,
+                          SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE);
+       switch (priv->id) {
+       case 0:
+               val = SPEAR1310_PCIE_CFG_VAL(0);
+               break;
+       case 1:
+               val = SPEAR1310_PCIE_CFG_VAL(1);
+               break;
+       case 2:
+               val = SPEAR1310_PCIE_CFG_VAL(2);
+               break;
+       default:
+               return -EINVAL;
+       }
+       regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG,
+                          SPEAR1310_PCIE_CFG_MASK(priv->id), val);
+       return 0;
+ }
+ static int spear1310_miphy_pcie_exit(struct spear1310_miphy_priv *priv)
+ {
+       regmap_update_bits(priv->misc, SPEAR1310_PCIE_SATA_CFG,
+                          SPEAR1310_PCIE_CFG_MASK(priv->id), 0);
+       regmap_update_bits(priv->misc, SPEAR1310_PCIE_MIPHY_CFG_1,
+                          SPEAR1310_PCIE_SATA_MIPHY_CFG_PCIE_MASK, 0);
+       return 0;
+ }
+ static int spear1310_miphy_init(struct phy *phy)
+ {
+       struct spear1310_miphy_priv *priv = phy_get_drvdata(phy);
+       int ret = 0;
+       if (priv->mode == PCIE)
+               ret = spear1310_miphy_pcie_init(priv);
+       return ret;
+ }
+ static int spear1310_miphy_exit(struct phy *phy)
+ {
+       struct spear1310_miphy_priv *priv = phy_get_drvdata(phy);
+       int ret = 0;
+       if (priv->mode == PCIE)
+               ret = spear1310_miphy_pcie_exit(priv);
+       return ret;
+ }
+ static const struct of_device_id spear1310_miphy_of_match[] = {
+       { .compatible = "st,spear1310-miphy" },
+       { },
+ };
+ MODULE_DEVICE_TABLE(of, spear1310_miphy_of_match);
+ static struct phy_ops spear1310_miphy_ops = {
+       .init = spear1310_miphy_init,
+       .exit = spear1310_miphy_exit,
+       .owner = THIS_MODULE,
+ };
+ static struct phy *spear1310_miphy_xlate(struct device *dev,
+                                        struct of_phandle_args *args)
+ {
+       struct spear1310_miphy_priv *priv = dev_get_drvdata(dev);
+       if (args->args_count < 1) {
+               dev_err(dev, "DT did not pass correct no of args\n");
+               return NULL;
+       }
+       priv->mode = args->args[0];
+       if (priv->mode != SATA && priv->mode != PCIE) {
+               dev_err(dev, "DT did not pass correct phy mode\n");
+               return NULL;
+       }
+       return priv->phy;
+ }
+ static int spear1310_miphy_probe(struct platform_device *pdev)
+ {
+       struct device *dev = &pdev->dev;
+       struct spear1310_miphy_priv *priv;
+       struct phy_provider *phy_provider;
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(dev, "can't alloc spear1310_miphy private date memory\n");
+               return -ENOMEM;
+       }
+       priv->misc =
+               syscon_regmap_lookup_by_phandle(dev->of_node, "misc");
+       if (IS_ERR(priv->misc)) {
+               dev_err(dev, "failed to find misc regmap\n");
+               return PTR_ERR(priv->misc);
+       }
+       if (of_property_read_u32(dev->of_node, "phy-id", &priv->id)) {
+               dev_err(dev, "failed to find phy id\n");
+               return -EINVAL;
+       }
++      priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops, NULL);
+       if (IS_ERR(priv->phy)) {
+               dev_err(dev, "failed to create SATA PCIe PHY\n");
+               return PTR_ERR(priv->phy);
+       }
+       dev_set_drvdata(dev, priv);
+       phy_set_drvdata(priv->phy, priv);
+       phy_provider =
+               devm_of_phy_provider_register(dev, spear1310_miphy_xlate);
+       if (IS_ERR(phy_provider)) {
+               dev_err(dev, "failed to register phy provider\n");
+               return PTR_ERR(phy_provider);
+       }
+       return 0;
+ }
+ static struct platform_driver spear1310_miphy_driver = {
+       .probe          = spear1310_miphy_probe,
+       .driver = {
+               .name = "spear1310-miphy",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(spear1310_miphy_of_match),
+       },
+ };
+ static int __init spear1310_miphy_phy_init(void)
+ {
+       return platform_driver_register(&spear1310_miphy_driver);
+ }
+ module_init(spear1310_miphy_phy_init);
+ static void __exit spear1310_miphy_phy_exit(void)
+ {
+       platform_driver_unregister(&spear1310_miphy_driver);
+ }
+ module_exit(spear1310_miphy_phy_exit);
+ MODULE_DESCRIPTION("ST SPEAR1310-MIPHY driver");
+ MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>");
+ MODULE_LICENSE("GPL v2");
index 0000000,8de98ad..7135ba2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,307 +1,307 @@@
 -      priv->phy = devm_phy_create(dev, &spear1340_miphy_ops, NULL);
+ /*
+  * ST spear1340-miphy driver
+  *
+  * Copyright (C) 2014 ST Microelectronics
+  * Pratyush Anand <pratyush.anand@st.com>
+  * Mohit Kumar <mohit.kumar@st.com>
+  *
+  * 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 <linux/bitops.h>
+ #include <linux/delay.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/kernel.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of_device.h>
+ #include <linux/phy/phy.h>
+ #include <linux/regmap.h>
+ /* SPEAr1340 Registers */
+ /* Power Management Registers */
+ #define SPEAR1340_PCM_CFG                     0x100
+       #define SPEAR1340_PCM_CFG_SATA_POWER_EN         BIT(11)
+ #define SPEAR1340_PCM_WKUP_CFG                        0x104
+ #define SPEAR1340_SWITCH_CTR                  0x108
+ #define SPEAR1340_PERIP1_SW_RST                       0x318
+       #define SPEAR1340_PERIP1_SW_RSATA               BIT(12)
+ #define SPEAR1340_PERIP2_SW_RST                       0x31C
+ #define SPEAR1340_PERIP3_SW_RST                       0x320
+ /* PCIE - SATA configuration registers */
+ #define SPEAR1340_PCIE_SATA_CFG                       0x424
+       /* PCIE CFG MASks */
+       #define SPEAR1340_PCIE_CFG_DEVICE_PRESENT       BIT(11)
+       #define SPEAR1340_PCIE_CFG_POWERUP_RESET        BIT(10)
+       #define SPEAR1340_PCIE_CFG_CORE_CLK_EN          BIT(9)
+       #define SPEAR1340_PCIE_CFG_AUX_CLK_EN           BIT(8)
+       #define SPEAR1340_SATA_CFG_TX_CLK_EN            BIT(4)
+       #define SPEAR1340_SATA_CFG_RX_CLK_EN            BIT(3)
+       #define SPEAR1340_SATA_CFG_POWERUP_RESET        BIT(2)
+       #define SPEAR1340_SATA_CFG_PM_CLK_EN            BIT(1)
+       #define SPEAR1340_PCIE_SATA_SEL_PCIE            (0)
+       #define SPEAR1340_PCIE_SATA_SEL_SATA            (1)
+       #define SPEAR1340_PCIE_SATA_CFG_MASK            0xF1F
+       #define SPEAR1340_PCIE_CFG_VAL  (SPEAR1340_PCIE_SATA_SEL_PCIE | \
+                       SPEAR1340_PCIE_CFG_AUX_CLK_EN | \
+                       SPEAR1340_PCIE_CFG_CORE_CLK_EN | \
+                       SPEAR1340_PCIE_CFG_POWERUP_RESET | \
+                       SPEAR1340_PCIE_CFG_DEVICE_PRESENT)
+       #define SPEAR1340_SATA_CFG_VAL  (SPEAR1340_PCIE_SATA_SEL_SATA | \
+                       SPEAR1340_SATA_CFG_PM_CLK_EN | \
+                       SPEAR1340_SATA_CFG_POWERUP_RESET | \
+                       SPEAR1340_SATA_CFG_RX_CLK_EN | \
+                       SPEAR1340_SATA_CFG_TX_CLK_EN)
+ #define SPEAR1340_PCIE_MIPHY_CFG              0x428
+       #define SPEAR1340_MIPHY_OSC_BYPASS_EXT          BIT(31)
+       #define SPEAR1340_MIPHY_CLK_REF_DIV2            BIT(27)
+       #define SPEAR1340_MIPHY_CLK_REF_DIV4            (2 << 27)
+       #define SPEAR1340_MIPHY_CLK_REF_DIV8            (3 << 27)
+       #define SPEAR1340_MIPHY_PLL_RATIO_TOP(x)        (x << 0)
+       #define SPEAR1340_PCIE_MIPHY_CFG_MASK           0xF80000FF
+       #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA \
+                       (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \
+                       SPEAR1340_MIPHY_CLK_REF_DIV2 | \
+                       SPEAR1340_MIPHY_PLL_RATIO_TOP(60))
+       #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \
+                       (SPEAR1340_MIPHY_PLL_RATIO_TOP(120))
+       #define SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE \
+                       (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \
+                       SPEAR1340_MIPHY_PLL_RATIO_TOP(25))
+ enum spear1340_miphy_mode {
+       SATA,
+       PCIE,
+ };
+ struct spear1340_miphy_priv {
+       /* phy mode: 0 for SATA 1 for PCIe */
+       enum spear1340_miphy_mode       mode;
+       /* regmap for any soc specific misc registers */
+       struct regmap                   *misc;
+       /* phy struct pointer */
+       struct phy                      *phy;
+ };
+ static int spear1340_miphy_sata_init(struct spear1340_miphy_priv *priv)
+ {
+       regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
+                          SPEAR1340_PCIE_SATA_CFG_MASK,
+                          SPEAR1340_SATA_CFG_VAL);
+       regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
+                          SPEAR1340_PCIE_MIPHY_CFG_MASK,
+                          SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK);
+       /* Switch on sata power domain */
+       regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG,
+                          SPEAR1340_PCM_CFG_SATA_POWER_EN,
+                          SPEAR1340_PCM_CFG_SATA_POWER_EN);
+       /* Wait for SATA power domain on */
+       msleep(20);
+       /* Disable PCIE SATA Controller reset */
+       regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST,
+                          SPEAR1340_PERIP1_SW_RSATA, 0);
+       /* Wait for SATA reset de-assert completion */
+       msleep(20);
+       return 0;
+ }
+ static int spear1340_miphy_sata_exit(struct spear1340_miphy_priv *priv)
+ {
+       regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
+                          SPEAR1340_PCIE_SATA_CFG_MASK, 0);
+       regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
+                          SPEAR1340_PCIE_MIPHY_CFG_MASK, 0);
+       /* Enable PCIE SATA Controller reset */
+       regmap_update_bits(priv->misc, SPEAR1340_PERIP1_SW_RST,
+                          SPEAR1340_PERIP1_SW_RSATA,
+                          SPEAR1340_PERIP1_SW_RSATA);
+       /* Wait for SATA power domain off */
+       msleep(20);
+       /* Switch off sata power domain */
+       regmap_update_bits(priv->misc, SPEAR1340_PCM_CFG,
+                          SPEAR1340_PCM_CFG_SATA_POWER_EN, 0);
+       /* Wait for SATA reset assert completion */
+       msleep(20);
+       return 0;
+ }
+ static int spear1340_miphy_pcie_init(struct spear1340_miphy_priv *priv)
+ {
+       regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
+                          SPEAR1340_PCIE_MIPHY_CFG_MASK,
+                          SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE);
+       regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
+                          SPEAR1340_PCIE_SATA_CFG_MASK,
+                          SPEAR1340_PCIE_CFG_VAL);
+       return 0;
+ }
+ static int spear1340_miphy_pcie_exit(struct spear1340_miphy_priv *priv)
+ {
+       regmap_update_bits(priv->misc, SPEAR1340_PCIE_MIPHY_CFG,
+                          SPEAR1340_PCIE_MIPHY_CFG_MASK, 0);
+       regmap_update_bits(priv->misc, SPEAR1340_PCIE_SATA_CFG,
+                          SPEAR1340_PCIE_SATA_CFG_MASK, 0);
+       return 0;
+ }
+ static int spear1340_miphy_init(struct phy *phy)
+ {
+       struct spear1340_miphy_priv *priv = phy_get_drvdata(phy);
+       int ret = 0;
+       if (priv->mode == SATA)
+               ret = spear1340_miphy_sata_init(priv);
+       else if (priv->mode == PCIE)
+               ret = spear1340_miphy_pcie_init(priv);
+       return ret;
+ }
+ static int spear1340_miphy_exit(struct phy *phy)
+ {
+       struct spear1340_miphy_priv *priv = phy_get_drvdata(phy);
+       int ret = 0;
+       if (priv->mode == SATA)
+               ret = spear1340_miphy_sata_exit(priv);
+       else if (priv->mode == PCIE)
+               ret = spear1340_miphy_pcie_exit(priv);
+       return ret;
+ }
+ static const struct of_device_id spear1340_miphy_of_match[] = {
+       { .compatible = "st,spear1340-miphy" },
+       { },
+ };
+ MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match);
+ static struct phy_ops spear1340_miphy_ops = {
+       .init = spear1340_miphy_init,
+       .exit = spear1340_miphy_exit,
+       .owner = THIS_MODULE,
+ };
+ #ifdef CONFIG_PM_SLEEP
+ static int spear1340_miphy_suspend(struct device *dev)
+ {
+       struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
+       int ret = 0;
+       if (priv->mode == SATA)
+               ret = spear1340_miphy_sata_exit(priv);
+       return ret;
+ }
+ static int spear1340_miphy_resume(struct device *dev)
+ {
+       struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
+       int ret = 0;
+       if (priv->mode == SATA)
+               ret = spear1340_miphy_sata_init(priv);
+       return ret;
+ }
+ #endif
+ static SIMPLE_DEV_PM_OPS(spear1340_miphy_pm_ops, spear1340_miphy_suspend,
+                        spear1340_miphy_resume);
+ static struct phy *spear1340_miphy_xlate(struct device *dev,
+                                        struct of_phandle_args *args)
+ {
+       struct spear1340_miphy_priv *priv = dev_get_drvdata(dev);
+       if (args->args_count < 1) {
+               dev_err(dev, "DT did not pass correct no of args\n");
+               return NULL;
+       }
+       priv->mode = args->args[0];
+       if (priv->mode != SATA && priv->mode != PCIE) {
+               dev_err(dev, "DT did not pass correct phy mode\n");
+               return NULL;
+       }
+       return priv->phy;
+ }
+ static int spear1340_miphy_probe(struct platform_device *pdev)
+ {
+       struct device *dev = &pdev->dev;
+       struct spear1340_miphy_priv *priv;
+       struct phy_provider *phy_provider;
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(dev, "can't alloc spear1340_miphy private date memory\n");
+               return -ENOMEM;
+       }
+       priv->misc =
+               syscon_regmap_lookup_by_phandle(dev->of_node, "misc");
+       if (IS_ERR(priv->misc)) {
+               dev_err(dev, "failed to find misc regmap\n");
+               return PTR_ERR(priv->misc);
+       }
++      priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops, NULL);
+       if (IS_ERR(priv->phy)) {
+               dev_err(dev, "failed to create SATA PCIe PHY\n");
+               return PTR_ERR(priv->phy);
+       }
+       dev_set_drvdata(dev, priv);
+       phy_set_drvdata(priv->phy, priv);
+       phy_provider =
+               devm_of_phy_provider_register(dev, spear1340_miphy_xlate);
+       if (IS_ERR(phy_provider)) {
+               dev_err(dev, "failed to register phy provider\n");
+               return PTR_ERR(phy_provider);
+       }
+       return 0;
+ }
+ static struct platform_driver spear1340_miphy_driver = {
+       .probe          = spear1340_miphy_probe,
+       .driver = {
+               .name = "spear1340-miphy",
+               .owner = THIS_MODULE,
+               .pm = &spear1340_miphy_pm_ops,
+               .of_match_table = of_match_ptr(spear1340_miphy_of_match),
+       },
+ };
+ static int __init spear1340_miphy_phy_init(void)
+ {
+       return platform_driver_register(&spear1340_miphy_driver);
+ }
+ module_init(spear1340_miphy_phy_init);
+ static void __exit spear1340_miphy_phy_exit(void)
+ {
+       platform_driver_unregister(&spear1340_miphy_driver);
+ }
+ module_exit(spear1340_miphy_phy_exit);
+ MODULE_DESCRIPTION("ST SPEAR1340-MIPHY driver");
+ MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>");
+ MODULE_LICENSE("GPL v2");
index 4a7daf5,0000000..a066204
mode 100644,000000..100644
--- /dev/null
@@@ -1,973 -1,0 +1,973 @@@
-       phy = devm_phy_create(&pdev->dev, &pcie_phy_ops, NULL);
 +/*
 + * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms and conditions of the GNU General Public License,
 + * version 2, as published by the Free Software Foundation.
 + *
 + * This program is distributed in the hope 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.
 + */
 +
 +#include <linux/delay.h>
 +#include <linux/io.h>
 +#include <linux/module.h>
 +#include <linux/of.h>
 +#include <linux/phy/phy.h>
 +#include <linux/pinctrl/pinctrl.h>
 +#include <linux/pinctrl/pinmux.h>
 +#include <linux/platform_device.h>
 +#include <linux/reset.h>
 +
 +#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 +
 +#include "core.h"
 +#include "pinctrl-utils.h"
 +
 +#define XUSB_PADCTL_ELPG_PROGRAM 0x01c
 +#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
 +#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
 +#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
 +
 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12)
 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1)
 +
 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044
 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6)
 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
 +#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
 +
 +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
 +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
 +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
 +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3)
 +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1)
 +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0)
 +
 +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148
 +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
 +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
 +
 +struct tegra_xusb_padctl_function {
 +      const char *name;
 +      const char * const *groups;
 +      unsigned int num_groups;
 +};
 +
 +struct tegra_xusb_padctl_group {
 +      const unsigned int *funcs;
 +      unsigned int num_funcs;
 +};
 +
 +struct tegra_xusb_padctl_soc {
 +      const struct pinctrl_pin_desc *pins;
 +      unsigned int num_pins;
 +
 +      const struct tegra_xusb_padctl_function *functions;
 +      unsigned int num_functions;
 +
 +      const struct tegra_xusb_padctl_lane *lanes;
 +      unsigned int num_lanes;
 +};
 +
 +struct tegra_xusb_padctl_lane {
 +      const char *name;
 +
 +      unsigned int offset;
 +      unsigned int shift;
 +      unsigned int mask;
 +      unsigned int iddq;
 +
 +      const unsigned int *funcs;
 +      unsigned int num_funcs;
 +};
 +
 +struct tegra_xusb_padctl {
 +      struct device *dev;
 +      void __iomem *regs;
 +      struct mutex lock;
 +      struct reset_control *rst;
 +
 +      const struct tegra_xusb_padctl_soc *soc;
 +      struct pinctrl_dev *pinctrl;
 +      struct pinctrl_desc desc;
 +
 +      struct phy_provider *provider;
 +      struct phy *phys[2];
 +
 +      unsigned int enable;
 +};
 +
 +static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value,
 +                               unsigned long offset)
 +{
 +      writel(value, padctl->regs + offset);
 +}
 +
 +static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
 +                             unsigned long offset)
 +{
 +      return readl(padctl->regs + offset);
 +}
 +
 +static int tegra_xusb_padctl_get_groups_count(struct pinctrl_dev *pinctrl)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +
 +      return padctl->soc->num_pins;
 +}
 +
 +static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl,
 +                                                  unsigned int group)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +
 +      return padctl->soc->pins[group].name;
 +}
 +
 +enum tegra_xusb_padctl_param {
 +      TEGRA_XUSB_PADCTL_IDDQ,
 +};
 +
 +static const struct tegra_xusb_padctl_property {
 +      const char *name;
 +      enum tegra_xusb_padctl_param param;
 +} properties[] = {
 +      { "nvidia,iddq", TEGRA_XUSB_PADCTL_IDDQ },
 +};
 +
 +#define TEGRA_XUSB_PADCTL_PACK(param, value) ((param) << 16 | (value))
 +#define TEGRA_XUSB_PADCTL_UNPACK_PARAM(config) ((config) >> 16)
 +#define TEGRA_XUSB_PADCTL_UNPACK_VALUE(config) ((config) & 0xffff)
 +
 +static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl,
 +                                         struct device_node *np,
 +                                         struct pinctrl_map **maps,
 +                                         unsigned int *reserved_maps,
 +                                         unsigned int *num_maps)
 +{
 +      unsigned int i, reserve = 0, num_configs = 0;
 +      unsigned long config, *configs = NULL;
 +      const char *function, *group;
 +      struct property *prop;
 +      int err = 0;
 +      u32 value;
 +
 +      err = of_property_read_string(np, "nvidia,function", &function);
 +      if (err < 0) {
 +              if (err != -EINVAL)
 +                      return err;
 +
 +              function = NULL;
 +      }
 +
 +      for (i = 0; i < ARRAY_SIZE(properties); i++) {
 +              err = of_property_read_u32(np, properties[i].name, &value);
 +              if (err < 0) {
 +                      if (err == -EINVAL)
 +                              continue;
 +
 +                      return err;
 +              }
 +
 +              config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, value);
 +
 +              err = pinctrl_utils_add_config(padctl->pinctrl, &configs,
 +                                             &num_configs, config);
 +              if (err < 0)
 +                      return err;
 +      }
 +
 +      if (function)
 +              reserve++;
 +
 +      if (num_configs)
 +              reserve++;
 +
 +      err = of_property_count_strings(np, "nvidia,lanes");
 +      if (err < 0)
 +              return err;
 +
 +      reserve *= err;
 +
 +      err = pinctrl_utils_reserve_map(padctl->pinctrl, maps, reserved_maps,
 +                                      num_maps, reserve);
 +      if (err < 0)
 +              return err;
 +
 +      of_property_for_each_string(np, "nvidia,lanes", prop, group) {
 +              if (function) {
 +                      err = pinctrl_utils_add_map_mux(padctl->pinctrl, maps,
 +                                      reserved_maps, num_maps, group,
 +                                      function);
 +                      if (err < 0)
 +                              return err;
 +              }
 +
 +              if (num_configs) {
 +                      err = pinctrl_utils_add_map_configs(padctl->pinctrl,
 +                                      maps, reserved_maps, num_maps, group,
 +                                      configs, num_configs,
 +                                      PIN_MAP_TYPE_CONFIGS_GROUP);
 +                      if (err < 0)
 +                              return err;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl,
 +                                          struct device_node *parent,
 +                                          struct pinctrl_map **maps,
 +                                          unsigned int *num_maps)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +      unsigned int reserved_maps = 0;
 +      struct device_node *np;
 +      int err;
 +
 +      *num_maps = 0;
 +      *maps = NULL;
 +
 +      for_each_child_of_node(parent, np) {
 +              err = tegra_xusb_padctl_parse_subnode(padctl, np, maps,
 +                                                    &reserved_maps,
 +                                                    num_maps);
 +              if (err < 0)
 +                      return err;
 +      }
 +
 +      return 0;
 +}
 +
 +static const struct pinctrl_ops tegra_xusb_padctl_pinctrl_ops = {
 +      .get_groups_count = tegra_xusb_padctl_get_groups_count,
 +      .get_group_name = tegra_xusb_padctl_get_group_name,
 +      .dt_node_to_map = tegra_xusb_padctl_dt_node_to_map,
 +      .dt_free_map = pinctrl_utils_dt_free_map,
 +};
 +
 +static int tegra_xusb_padctl_get_functions_count(struct pinctrl_dev *pinctrl)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +
 +      return padctl->soc->num_functions;
 +}
 +
 +static const char *
 +tegra_xusb_padctl_get_function_name(struct pinctrl_dev *pinctrl,
 +                                  unsigned int function)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +
 +      return padctl->soc->functions[function].name;
 +}
 +
 +static int tegra_xusb_padctl_get_function_groups(struct pinctrl_dev *pinctrl,
 +                                               unsigned int function,
 +                                               const char * const **groups,
 +                                               unsigned * const num_groups)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +
 +      *num_groups = padctl->soc->functions[function].num_groups;
 +      *groups = padctl->soc->functions[function].groups;
 +
 +      return 0;
 +}
 +
 +static int tegra_xusb_padctl_pinmux_enable(struct pinctrl_dev *pinctrl,
 +                                         unsigned int function,
 +                                         unsigned int group)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +      const struct tegra_xusb_padctl_lane *lane;
 +      unsigned int i;
 +      u32 value;
 +
 +      lane = &padctl->soc->lanes[group];
 +
 +      for (i = 0; i < lane->num_funcs; i++)
 +              if (lane->funcs[i] == function)
 +                      break;
 +
 +      if (i >= lane->num_funcs)
 +              return -EINVAL;
 +
 +      value = padctl_readl(padctl, lane->offset);
 +      value &= ~(lane->mask << lane->shift);
 +      value |= i << lane->shift;
 +      padctl_writel(padctl, value, lane->offset);
 +
 +      return 0;
 +}
 +
 +static const struct pinmux_ops tegra_xusb_padctl_pinmux_ops = {
 +      .get_functions_count = tegra_xusb_padctl_get_functions_count,
 +      .get_function_name = tegra_xusb_padctl_get_function_name,
 +      .get_function_groups = tegra_xusb_padctl_get_function_groups,
 +      .enable = tegra_xusb_padctl_pinmux_enable,
 +};
 +
 +static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 +                                             unsigned int group,
 +                                             unsigned long *config)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +      const struct tegra_xusb_padctl_lane *lane;
 +      enum tegra_xusb_padctl_param param;
 +      u32 value;
 +
 +      param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(*config);
 +      lane = &padctl->soc->lanes[group];
 +
 +      switch (param) {
 +      case TEGRA_XUSB_PADCTL_IDDQ:
 +              /* lanes with iddq == 0 don't support this parameter */
 +              if (lane->iddq == 0)
 +                      return -EINVAL;
 +
 +              value = padctl_readl(padctl, lane->offset);
 +
 +              if (value & BIT(lane->iddq))
 +                      value = 0;
 +              else
 +                      value = 1;
 +
 +              *config = TEGRA_XUSB_PADCTL_PACK(param, value);
 +              break;
 +
 +      default:
 +              dev_err(padctl->dev, "invalid configuration parameter: %04x\n",
 +                      param);
 +              return -ENOTSUPP;
 +      }
 +
 +      return 0;
 +}
 +
 +static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
 +                                             unsigned int group,
 +                                             unsigned long *configs,
 +                                             unsigned int num_configs)
 +{
 +      struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 +      const struct tegra_xusb_padctl_lane *lane;
 +      enum tegra_xusb_padctl_param param;
 +      unsigned long value;
 +      unsigned int i;
 +      u32 regval;
 +
 +      lane = &padctl->soc->lanes[group];
 +
 +      for (i = 0; i < num_configs; i++) {
 +              param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(configs[i]);
 +              value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(configs[i]);
 +
 +              switch (param) {
 +              case TEGRA_XUSB_PADCTL_IDDQ:
 +                      /* lanes with iddq == 0 don't support this parameter */
 +                      if (lane->iddq == 0)
 +                              return -EINVAL;
 +
 +                      regval = padctl_readl(padctl, lane->offset);
 +
 +                      if (value)
 +                              regval &= ~BIT(lane->iddq);
 +                      else
 +                              regval |= BIT(lane->iddq);
 +
 +                      padctl_writel(padctl, regval, lane->offset);
 +                      break;
 +
 +              default:
 +                      dev_err(padctl->dev,
 +                              "invalid configuration parameter: %04x\n",
 +                              param);
 +                      return -ENOTSUPP;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +#ifdef CONFIG_DEBUG_FS
 +static const char *strip_prefix(const char *s)
 +{
 +      const char *comma = strchr(s, ',');
 +      if (!comma)
 +              return s;
 +
 +      return comma + 1;
 +}
 +
 +static void
 +tegra_xusb_padctl_pinconf_group_dbg_show(struct pinctrl_dev *pinctrl,
 +                                       struct seq_file *s,
 +                                       unsigned int group)
 +{
 +      unsigned int i;
 +
 +      for (i = 0; i < ARRAY_SIZE(properties); i++) {
 +              unsigned long config, value;
 +              int err;
 +
 +              config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, 0);
 +
 +              err = tegra_xusb_padctl_pinconf_group_get(pinctrl, group,
 +                                                        &config);
 +              if (err < 0)
 +                      continue;
 +
 +              value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(config);
 +
 +              seq_printf(s, "\n\t%s=%lu\n", strip_prefix(properties[i].name),
 +                         value);
 +      }
 +}
 +
 +static void
 +tegra_xusb_padctl_pinconf_config_dbg_show(struct pinctrl_dev *pinctrl,
 +                                        struct seq_file *s,
 +                                        unsigned long config)
 +{
 +      enum tegra_xusb_padctl_param param;
 +      const char *name = "unknown";
 +      unsigned long value;
 +      unsigned int i;
 +
 +      param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(config);
 +      value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(config);
 +
 +      for (i = 0; i < ARRAY_SIZE(properties); i++) {
 +              if (properties[i].param == param) {
 +                      name = properties[i].name;
 +                      break;
 +              }
 +      }
 +
 +      seq_printf(s, "%s=%lu", strip_prefix(name), value);
 +}
 +#endif
 +
 +static const struct pinconf_ops tegra_xusb_padctl_pinconf_ops = {
 +      .pin_config_group_get = tegra_xusb_padctl_pinconf_group_get,
 +      .pin_config_group_set = tegra_xusb_padctl_pinconf_group_set,
 +#ifdef CONFIG_DEBUG_FS
 +      .pin_config_group_dbg_show = tegra_xusb_padctl_pinconf_group_dbg_show,
 +      .pin_config_config_dbg_show = tegra_xusb_padctl_pinconf_config_dbg_show,
 +#endif
 +};
 +
 +static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
 +{
 +      u32 value;
 +
 +      mutex_lock(&padctl->lock);
 +
 +      if (padctl->enable++ > 0)
 +              goto out;
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
 +      value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
 +      padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
 +
 +      usleep_range(100, 200);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
 +      value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
 +      padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
 +
 +      usleep_range(100, 200);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
 +      value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
 +      padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
 +
 +out:
 +      mutex_unlock(&padctl->lock);
 +      return 0;
 +}
 +
 +static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
 +{
 +      u32 value;
 +
 +      mutex_lock(&padctl->lock);
 +
 +      if (WARN_ON(padctl->enable == 0))
 +              goto out;
 +
 +      if (--padctl->enable > 0)
 +              goto out;
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
 +      value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
 +      padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
 +
 +      usleep_range(100, 200);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
 +      value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
 +      padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
 +
 +      usleep_range(100, 200);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
 +      value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
 +      padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
 +
 +out:
 +      mutex_unlock(&padctl->lock);
 +      return 0;
 +}
 +
 +static int tegra_xusb_phy_init(struct phy *phy)
 +{
 +      struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
 +
 +      return tegra_xusb_padctl_enable(padctl);
 +}
 +
 +static int tegra_xusb_phy_exit(struct phy *phy)
 +{
 +      struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
 +
 +      return tegra_xusb_padctl_disable(padctl);
 +}
 +
 +static int pcie_phy_power_on(struct phy *phy)
 +{
 +      struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
 +      unsigned long timeout;
 +      int err = -ETIMEDOUT;
 +      u32 value;
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 +      value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
 +      value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN |
 +               XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN |
 +               XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 +      value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 +
 +      timeout = jiffies + msecs_to_jiffies(50);
 +
 +      while (time_before(jiffies, timeout)) {
 +              value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 +              if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) {
 +                      err = 0;
 +                      break;
 +              }
 +
 +              usleep_range(100, 200);
 +      }
 +
 +      return err;
 +}
 +
 +static int pcie_phy_power_off(struct phy *phy)
 +{
 +      struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
 +      u32 value;
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 +      value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 +
 +      return 0;
 +}
 +
 +static const struct phy_ops pcie_phy_ops = {
 +      .init = tegra_xusb_phy_init,
 +      .exit = tegra_xusb_phy_exit,
 +      .power_on = pcie_phy_power_on,
 +      .power_off = pcie_phy_power_off,
 +      .owner = THIS_MODULE,
 +};
 +
 +static int sata_phy_power_on(struct phy *phy)
 +{
 +      struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
 +      unsigned long timeout;
 +      int err = -ETIMEDOUT;
 +      u32 value;
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
 +      value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
 +      value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +      value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
 +      value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +      value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +      value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +
 +      timeout = jiffies + msecs_to_jiffies(50);
 +
 +      while (time_before(jiffies, timeout)) {
 +              value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +              if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) {
 +                      err = 0;
 +                      break;
 +              }
 +
 +              usleep_range(100, 200);
 +      }
 +
 +      return err;
 +}
 +
 +static int sata_phy_power_off(struct phy *phy)
 +{
 +      struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
 +      u32 value;
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +      value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +      value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +      value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
 +      value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 +
 +      value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
 +      value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
 +      value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
 +      padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
 +
 +      return 0;
 +}
 +
 +static const struct phy_ops sata_phy_ops = {
 +      .init = tegra_xusb_phy_init,
 +      .exit = tegra_xusb_phy_exit,
 +      .power_on = sata_phy_power_on,
 +      .power_off = sata_phy_power_off,
 +      .owner = THIS_MODULE,
 +};
 +
 +static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
 +                                         struct of_phandle_args *args)
 +{
 +      struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
 +      unsigned int index = args->args[0];
 +
 +      if (args->args_count <= 0)
 +              return ERR_PTR(-EINVAL);
 +
 +      if (index > ARRAY_SIZE(padctl->phys))
 +              return ERR_PTR(-EINVAL);
 +
 +      return padctl->phys[index];
 +}
 +
 +#define PIN_OTG_0   0
 +#define PIN_OTG_1   1
 +#define PIN_OTG_2   2
 +#define PIN_ULPI_0  3
 +#define PIN_HSIC_0  4
 +#define PIN_HSIC_1  5
 +#define PIN_PCIE_0  6
 +#define PIN_PCIE_1  7
 +#define PIN_PCIE_2  8
 +#define PIN_PCIE_3  9
 +#define PIN_PCIE_4 10
 +#define PIN_SATA_0 11
 +
 +static const struct pinctrl_pin_desc tegra124_pins[] = {
 +      PINCTRL_PIN(PIN_OTG_0,  "otg-0"),
 +      PINCTRL_PIN(PIN_OTG_1,  "otg-1"),
 +      PINCTRL_PIN(PIN_OTG_2,  "otg-2"),
 +      PINCTRL_PIN(PIN_ULPI_0, "ulpi-0"),
 +      PINCTRL_PIN(PIN_HSIC_0, "hsic-0"),
 +      PINCTRL_PIN(PIN_HSIC_1, "hsic-1"),
 +      PINCTRL_PIN(PIN_PCIE_0, "pcie-0"),
 +      PINCTRL_PIN(PIN_PCIE_1, "pcie-1"),
 +      PINCTRL_PIN(PIN_PCIE_2, "pcie-2"),
 +      PINCTRL_PIN(PIN_PCIE_3, "pcie-3"),
 +      PINCTRL_PIN(PIN_PCIE_4, "pcie-4"),
 +      PINCTRL_PIN(PIN_SATA_0, "sata-0"),
 +};
 +
 +static const char * const tegra124_snps_groups[] = {
 +      "otg-0",
 +      "otg-1",
 +      "otg-2",
 +      "ulpi-0",
 +      "hsic-0",
 +      "hsic-1",
 +};
 +
 +static const char * const tegra124_xusb_groups[] = {
 +      "otg-0",
 +      "otg-1",
 +      "otg-2",
 +      "ulpi-0",
 +      "hsic-0",
 +      "hsic-1",
 +};
 +
 +static const char * const tegra124_uart_groups[] = {
 +      "otg-0",
 +      "otg-1",
 +      "otg-2",
 +};
 +
 +static const char * const tegra124_pcie_groups[] = {
 +      "pcie-0",
 +      "pcie-1",
 +      "pcie-2",
 +      "pcie-3",
 +      "pcie-4",
 +      "sata-0",
 +};
 +
 +static const char * const tegra124_usb3_groups[] = {
 +      "pcie-0",
 +      "pcie-1",
 +      "pcie-2",
 +      "pcie-3",
 +      "pcie-4",
 +      "sata-0",
 +};
 +
 +static const char * const tegra124_sata_groups[] = {
 +      "pcie-0",
 +      "pcie-1",
 +      "pcie-2",
 +      "pcie-3",
 +      "pcie-4",
 +      "sata-0",
 +};
 +
 +static const char * const tegra124_rsvd_groups[] = {
 +      "otg-0",
 +      "otg-1",
 +      "otg-2",
 +      "pcie-0",
 +      "pcie-1",
 +      "pcie-2",
 +      "pcie-3",
 +      "pcie-4",
 +      "sata-0",
 +};
 +
 +#define TEGRA124_FUNCTION(_name)                                      \
 +      {                                                               \
 +              .name = #_name,                                         \
 +              .num_groups = ARRAY_SIZE(tegra124_##_name##_groups),    \
 +              .groups = tegra124_##_name##_groups,                    \
 +      }
 +
 +static struct tegra_xusb_padctl_function tegra124_functions[] = {
 +      TEGRA124_FUNCTION(snps),
 +      TEGRA124_FUNCTION(xusb),
 +      TEGRA124_FUNCTION(uart),
 +      TEGRA124_FUNCTION(pcie),
 +      TEGRA124_FUNCTION(usb3),
 +      TEGRA124_FUNCTION(sata),
 +      TEGRA124_FUNCTION(rsvd),
 +};
 +
 +enum tegra124_function {
 +      TEGRA124_FUNC_SNPS,
 +      TEGRA124_FUNC_XUSB,
 +      TEGRA124_FUNC_UART,
 +      TEGRA124_FUNC_PCIE,
 +      TEGRA124_FUNC_USB3,
 +      TEGRA124_FUNC_SATA,
 +      TEGRA124_FUNC_RSVD,
 +};
 +
 +static const unsigned int tegra124_otg_functions[] = {
 +      TEGRA124_FUNC_SNPS,
 +      TEGRA124_FUNC_XUSB,
 +      TEGRA124_FUNC_UART,
 +      TEGRA124_FUNC_RSVD,
 +};
 +
 +static const unsigned int tegra124_usb_functions[] = {
 +      TEGRA124_FUNC_SNPS,
 +      TEGRA124_FUNC_XUSB,
 +};
 +
 +static const unsigned int tegra124_pci_functions[] = {
 +      TEGRA124_FUNC_PCIE,
 +      TEGRA124_FUNC_USB3,
 +      TEGRA124_FUNC_SATA,
 +      TEGRA124_FUNC_RSVD,
 +};
 +
 +#define TEGRA124_LANE(_name, _offset, _shift, _mask, _iddq, _funcs)   \
 +      {                                                               \
 +              .name = _name,                                          \
 +              .offset = _offset,                                      \
 +              .shift = _shift,                                        \
 +              .mask = _mask,                                          \
 +              .iddq = _iddq,                                          \
 +              .num_funcs = ARRAY_SIZE(tegra124_##_funcs##_functions), \
 +              .funcs = tegra124_##_funcs##_functions,                 \
 +      }
 +
 +static const struct tegra_xusb_padctl_lane tegra124_lanes[] = {
 +      TEGRA124_LANE("otg-0",  0x004,  0, 0x3, 0, otg),
 +      TEGRA124_LANE("otg-1",  0x004,  2, 0x3, 0, otg),
 +      TEGRA124_LANE("otg-2",  0x004,  4, 0x3, 0, otg),
 +      TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb),
 +      TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb),
 +      TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb),
 +      TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci),
 +      TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci),
 +      TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci),
 +      TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci),
 +      TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci),
 +      TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci),
 +};
 +
 +static const struct tegra_xusb_padctl_soc tegra124_soc = {
 +      .num_pins = ARRAY_SIZE(tegra124_pins),
 +      .pins = tegra124_pins,
 +      .num_functions = ARRAY_SIZE(tegra124_functions),
 +      .functions = tegra124_functions,
 +      .num_lanes = ARRAY_SIZE(tegra124_lanes),
 +      .lanes = tegra124_lanes,
 +};
 +
 +static const struct of_device_id tegra_xusb_padctl_of_match[] = {
 +      { .compatible = "nvidia,tegra124-xusb-padctl", .data = &tegra124_soc },
 +      { }
 +};
 +MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
 +
 +static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 +{
 +      struct tegra_xusb_padctl *padctl;
 +      const struct of_device_id *match;
 +      struct resource *res;
 +      struct phy *phy;
 +      int err;
 +
 +      padctl = devm_kzalloc(&pdev->dev, sizeof(*padctl), GFP_KERNEL);
 +      if (!padctl)
 +              return -ENOMEM;
 +
 +      platform_set_drvdata(pdev, padctl);
 +      mutex_init(&padctl->lock);
 +      padctl->dev = &pdev->dev;
 +
 +      match = of_match_node(tegra_xusb_padctl_of_match, pdev->dev.of_node);
 +      padctl->soc = match->data;
 +
 +      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 +      padctl->regs = devm_ioremap_resource(&pdev->dev, res);
 +      if (IS_ERR(padctl->regs))
 +              return PTR_ERR(padctl->regs);
 +
 +      padctl->rst = devm_reset_control_get(&pdev->dev, NULL);
 +      if (IS_ERR(padctl->rst))
 +              return PTR_ERR(padctl->rst);
 +
 +      err = reset_control_deassert(padctl->rst);
 +      if (err < 0)
 +              return err;
 +
 +      memset(&padctl->desc, 0, sizeof(padctl->desc));
 +      padctl->desc.name = dev_name(padctl->dev);
 +      padctl->desc.pctlops = &tegra_xusb_padctl_pinctrl_ops;
 +      padctl->desc.pmxops = &tegra_xusb_padctl_pinmux_ops;
 +      padctl->desc.confops = &tegra_xusb_padctl_pinconf_ops;
 +      padctl->desc.owner = THIS_MODULE;
 +
 +      padctl->pinctrl = pinctrl_register(&padctl->desc, &pdev->dev, padctl);
 +      if (!padctl->pinctrl) {
 +              dev_err(&pdev->dev, "failed to register pincontrol\n");
 +              err = -ENODEV;
 +              goto reset;
 +      }
 +
-       phy = devm_phy_create(&pdev->dev, &sata_phy_ops, NULL);
++      phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops, NULL);
 +      if (IS_ERR(phy)) {
 +              err = PTR_ERR(phy);
 +              goto unregister;
 +      }
 +
 +      padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
 +      phy_set_drvdata(phy, padctl);
 +
++      phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops, NULL);
 +      if (IS_ERR(phy)) {
 +              err = PTR_ERR(phy);
 +              goto unregister;
 +      }
 +
 +      padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy;
 +      phy_set_drvdata(phy, padctl);
 +
 +      padctl->provider = devm_of_phy_provider_register(&pdev->dev,
 +                                                       tegra_xusb_padctl_xlate);
 +      if (err < 0) {
 +              dev_err(&pdev->dev, "failed to register PHYs: %d\n", err);
 +              goto unregister;
 +      }
 +
 +      return 0;
 +
 +unregister:
 +      pinctrl_unregister(padctl->pinctrl);
 +reset:
 +      reset_control_assert(padctl->rst);
 +      return err;
 +}
 +
 +static int tegra_xusb_padctl_remove(struct platform_device *pdev)
 +{
 +      struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev);
 +      int err;
 +
 +      pinctrl_unregister(padctl->pinctrl);
 +
 +      err = reset_control_assert(padctl->rst);
 +      if (err < 0)
 +              dev_err(&pdev->dev, "failed to assert reset: %d\n", err);
 +
 +      return err;
 +}
 +
 +static struct platform_driver tegra_xusb_padctl_driver = {
 +      .driver = {
 +              .name = "tegra-xusb-padctl",
 +              .of_match_table = tegra_xusb_padctl_of_match,
 +      },
 +      .probe = tegra_xusb_padctl_probe,
 +      .remove = tegra_xusb_padctl_remove,
 +};
 +module_platform_driver(tegra_xusb_padctl_driver);
 +
 +MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
 +MODULE_DESCRIPTION("Tegra 124 XUSB Pad Control driver");
 +MODULE_LICENSE("GPL v2");
Simple merge
Simple merge