Skip to contentSkip to conversation

usb: phy: samsung: Introducing usb phy driver for samsung SoCs

PATCH Superseded Praveen Paneri 11 participants 27 messages Sep 17, 2012 – Oct 22, 2012

Subsystems (5)

v6 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v6 cover usb: phy: samsung: Introducing usb phy driver for samsung SoCs

Changes from v5:
Moved clk_get() to driver's probe function. Now reference clock frequency selection value is stored in samsung_usbphy structure for later use. Used IS_ENABLED() instead of #ifdef in samsung_usbphy_get_driver_data().

Changes from v4:
Moved header file contents to driver's source file Removed unnecessary print message from driver's probe function Dropped the Free Software Foundation address from the header Changed the platform data code to use __initdata

Changes from v3:
Replaced susbsys_initcall()/module_exit() by module_platform_driver(). Accordingly in the hsotg driver returned -EPROBE_DEFER until phy driver is registered
Removed unnecessary devm_usb_put_phy() call from the hsotg driver remove.

Changes from v2:
Changed the driver filenames to samsung-usbphy
Changed 's3c' to 'samsung' for platform device as well as platform data Moved platform data structure to a separate file
Rectified coding style related errors

Changes from v1:
Rebased patches to latest usb-next branch
Changed the name 'sec_usbphy' to 'samsung_usbphy'

This patch set introduces a phy driver for samsung SoCs. It uses the existing transceiver infrastructure to provide phy control functions. Use of this driver can be extended for usb host phy as well. Over the period of time all the phy related code for most of the samsung SoCs can be integrated here. Removing the existing phy code from mach-s3c64xx. Same can be done for other SoCs when they start supporting this phy driver.
This driver is tested with smdk6410 and Exynos4210(with DT).

Praveen Paneri (5):
usb: phy: samsung: Introducing usb phy driver for hsotg
usb: s3c-hsotg: Adding phy driver support
ARM: S3C64XX: Removing old phy setup code
ARM: S3C64XX: Enabling samsung-usbphy driver
ARM: Exynos4210: Enabling samsung-usbphy driver

 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 arch/arm/boot/dts/exynos4210.dtsi                  |    5 +
 arch/arm/mach-exynos/include/mach/map.h            |    1 +
 arch/arm/mach-exynos/mach-exynos4-dt.c             |    8 +
 arch/arm/mach-exynos/setup-usb-phy.c               |   13 +
 arch/arm/mach-s3c64xx/include/mach/map.h           |    2 +
 arch/arm/mach-s3c64xx/mach-crag6410.c              |   10 +-
 arch/arm/mach-s3c64xx/mach-smartq.c                |   11 +-
 arch/arm/mach-s3c64xx/mach-smdk6410.c              |   10 +-
 arch/arm/mach-s3c64xx/setup-usb-phy.c              |   79 +----
 arch/arm/plat-samsung/devs.c                       |   28 ++
 arch/arm/plat-samsung/include/plat/devs.h          |    1 +
 arch/arm/plat-samsung/include/plat/usb-phy.h       |    1 +
 drivers/usb/gadget/s3c-hsotg.c                     |   37 ++-
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 18 files changed, 520 insertions(+), 91 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
#1 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +9 -0
new file mode 100644
index 0000000..fefd9c8
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+	region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
 	help
 	  Enable this to support Marvell USB 3.0 phy controller for Marvell
 	  SoC.
+
+config SAMSUNG_USBPHY
+	bool "Samsung USB PHY controller Driver"
+	depends on USB_S3C_HSOTG
+	select USB_OTG_UTILS
+	help
+	  Enable this to support Samsung USB phy controller for samsung
+	  SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)			+= omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +360 -0

360 lines not on this page · raw message

include/linux/platform_data/samsung-usbphy.h new file +27 -0
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *		http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+	void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
Signature · 1 line
1.7.1
#2 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

Hi Kishon, Felipe,

Any further comments on these patches? Can they be merged now?

Thanks,
Praveen

Quoted 463 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +9 -0
new file mode 100644
index 0000000..fefd9c8
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+       region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
        help
          Enable this to support Marvell USB 3.0 phy controller for Marvell
          SoC.
+
+config SAMSUNG_USBPHY
+       bool "Samsung USB PHY controller Driver"
+       depends on USB_S3C_HSOTG
+       select USB_OTG_UTILS
+       help
+         Enable this to support Samsung USB phy controller for samsung
+         SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)                 += omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)              += isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)               += mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)   += tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)           += samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +360 -0
new file mode 100644
index 0000000..95ec4d0
@@ -0,0 +1,360 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR                             (0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK                 (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE                 (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN            (1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND               (1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK             (0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP                   (1 << 5)
+
+#define S3C_PHYCLK                             (0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL                 (1 << 6)
+#define S3C_PHYCLK_EXT_OSC                     (1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N                 (1 << 4)
+#define S3C_PHYCLK_ID_PULL                     (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                 (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                        (0)
+#define S3C_PHYCLK_CLKSEL_48M                  (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                  (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                  (0x3 << 0)
+
+#define S3C_RSTCON                             (0x08)
+
+#define S3C_RSTCON_PHYCLK                      (1 << 2)
+#define S3C_RSTCON_HCLK                                (1 << 1)
+#define S3C_RSTCON_PHY                         (1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+       TYPE_S3C64XX,
+       TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+       struct usb_phy  phy;
+       struct samsung_usbphy_data *plat;
+       struct device   *dev;
+       struct clk      *clk;
+       void __iomem    *regs;
+       int             ref_clk_freq;
+       int             cpu_type;
+};
+
+#define phy_to_sphy(x)         container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+       struct clk *ref_clk;
+       int refclk_freq = 0;
+
+       ref_clk = clk_get(sphy->dev, "xusbxti");
+       if (IS_ERR(ref_clk)) {
+               dev_err(sphy->dev, "Failed to get reference clock\n");
+               return PTR_ERR(ref_clk);
+       }
+
+       switch (clk_get_rate(ref_clk)) {
+       case 12 * MHZ:
+               refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+               break;
+       case 24 * MHZ:
+               refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+               break;
+       default:
+       case 48 * MHZ:
+               /* default reference clock */
+               refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+               break;
+       }
+       clk_put(ref_clk);
+
+       return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phypwr;
+       u32 phyclk;
+       u32 rstcon;
+
+       /* set clock frequency for PLL */
+       phyclk = sphy->ref_clk_freq;
+       phypwr = readl(regs + S3C_PHYPWR);
+       rstcon = readl(regs + S3C_RSTCON);
+
+       switch (sphy->cpu_type) {
+       case TYPE_S3C64XX:
+               phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+               phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+               rstcon |= S3C_RSTCON_PHY;
+               break;
+       case TYPE_EXYNOS4210:
+               phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+               rstcon |= S3C_RSTCON_PHY;
+       default:
+               break;
+       }
+
+       writel(phyclk, regs + S3C_PHYCLK);
+       /* set to normal of PHY0 */
+       writel(phypwr, regs + S3C_PHYPWR);
+       /* reset all ports of PHY and Link */
+       writel(rstcon, regs + S3C_RSTCON);
+       udelay(10);
+       rstcon &= ~S3C_RSTCON_PHY;
+       writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phypwr;
+
+       phypwr = readl(regs + S3C_PHYPWR);
+
+       switch (sphy->cpu_type) {
+       case TYPE_S3C64XX:
+               phypwr |= S3C_PHYPWR_NORMAL_MASK;
+               break;
+       case TYPE_EXYNOS4210:
+               phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+       default:
+               break;
+       }
+
+       /* unset to normal of PHY0 */
+       writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+       int ret = 0;
+
+       sphy = phy_to_sphy(phy);
+
+       /* Enable the phy clock */
+       ret = clk_prepare_enable(sphy->clk);
+       if (ret) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return ret;
+       }
+
+       /* Disable phy isolation */
+       if (sphy->plat && sphy->plat->pmu_isolation)
+               sphy->plat->pmu_isolation(false);
+
+       /* Initialize usb phy registers */
+       samsung_usbphy_enable(sphy);
+
+       /* Disable the phy clock */
+       clk_disable_unprepare(sphy->clk);
+       return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+
+       sphy = phy_to_sphy(phy);
+
+       if (clk_prepare_enable(sphy->clk)) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return;
+       }
+
+       /* De-initialize usb phy registers */
+       samsung_usbphy_disable(sphy);
+
+       /* Enable phy isolation */
+       if (sphy->plat && sphy->plat->pmu_isolation)
+               sphy->plat->pmu_isolation(true);
+
+       clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+       if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+               int data;
+               const struct of_device_id *match;
+               match = of_match_node(samsung_usbphy_dt_match,
+                                                       pdev->dev.of_node);
+               data = (int) match->data;
+               return data;
+       }
+
+       return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy;
+       struct samsung_usbphy_data *pdata;
+       struct device *dev = &pdev->dev;
+       struct resource *phy_mem;
+       void __iomem    *phy_base;
+       struct clk *clk;
+       int     ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+               return -EINVAL;
+       }
+
+       phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!phy_mem) {
+               dev_err(dev, "%s: missing mem resource\n", __func__);
+               return -ENODEV;
+       }
+
+       phy_base = devm_request_and_ioremap(dev, phy_mem);
+       if (!phy_base) {
+               dev_err(dev, "%s: register mapping failed\n", __func__);
+               return -ENXIO;
+       }
+
+       sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+       if (!sphy)
+               return -ENOMEM;
+
+       clk = devm_clk_get(dev, "otg");
+       if (IS_ERR(clk)) {
+               dev_err(dev, "Failed to get otg clock\n");
+               return PTR_ERR(clk);
+       }
+
+       sphy->dev               = &pdev->dev;
+       sphy->plat              = pdata;
+       sphy->regs              = phy_base;
+       sphy->clk               = clk;
+       sphy->phy.dev           = sphy->dev;
+       sphy->phy.label         = "samsung-usbphy";
+       sphy->phy.init          = samsung_usbphy_init;
+       sphy->phy.shutdown      = samsung_usbphy_shutdown;
+       sphy->cpu_type          = samsung_usbphy_get_driver_data(pdev);
+       sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
+
+       ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+       if (ret)
+               goto err;
+
+       platform_set_drvdata(pdev, sphy);
+err:
+       return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&sphy->phy);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+       {
+               .compatible = "samsung,s3c64xx-usbphy",
+               .data = (void *)TYPE_S3C64XX,
+       }, {
+               .compatible = "samsung,exynos4210-usbphy",
+               .data = (void *)TYPE_EXYNOS4210,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+       {
+               .name           = "s3c64xx-usbphy",
+               .driver_data    = TYPE_S3C64XX,
+       }, {
+               .name           = "exynos4210-usbphy",
+               .driver_data    = TYPE_EXYNOS4210,
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+       .probe          = samsung_usbphy_probe,
+       .remove         = __devexit_p(samsung_usbphy_remove),
+       .id_table       = samsung_usbphy_driver_ids,
+       .driver         = {
+               .name   = "samsung-usbphy",
+               .owner  = THIS_MODULE,
+               .of_match_table = samsung_usbphy_dt_match,
+       },
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +27 -1
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *             http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+       void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
--

1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

Hi,

Quoted 3 lines · Praveen Paneri

Hi Kishon, Felipe,

Any further comments on these patches? Can they be merged now?

I don't have any other comments.

Thanks
Kishon

#4 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

In reply to Praveen Paneri
Quoted 3 lines · Praveen Paneri

Hi Kishon, Felipe,

Any further comments on these patches? Can they be merged now?

One nitpick inline.

Marc

Quoted 361 lines

Thanks,
Praveen

Quoted 356 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +9 -0
new file mode 100644
index 0000000..fefd9c8
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+       region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
        help
          Enable this to support Marvell USB 3.0 phy controller for Marvell
          SoC.
+
+config SAMSUNG_USBPHY
+       bool "Samsung USB PHY controller Driver"
+       depends on USB_S3C_HSOTG
+       select USB_OTG_UTILS
+       help
+         Enable this to support Samsung USB phy controller for samsung
+         SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)                 += omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)              += isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)               += mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)   += tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)           += samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +293 -0
new file mode 100644
index 0000000..95ec4d0
@@ -0,0 +1,360 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR                             (0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK                 (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE                 (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN            (1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND               (1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK             (0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP                   (1 << 5)
+
+#define S3C_PHYCLK                             (0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL                 (1 << 6)
+#define S3C_PHYCLK_EXT_OSC                     (1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N                 (1 << 4)
+#define S3C_PHYCLK_ID_PULL                     (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                 (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                        (0)
+#define S3C_PHYCLK_CLKSEL_48M                  (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                  (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                  (0x3 << 0)
+
+#define S3C_RSTCON                             (0x08)
+
+#define S3C_RSTCON_PHYCLK                      (1 << 2)
+#define S3C_RSTCON_HCLK                                (1 << 1)
+#define S3C_RSTCON_PHY                         (1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+       TYPE_S3C64XX,
+       TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+       struct usb_phy  phy;
+       struct samsung_usbphy_data *plat;
+       struct device   *dev;
+       struct clk      *clk;
+       void __iomem    *regs;
+       int             ref_clk_freq;
+       int             cpu_type;
+};
+
+#define phy_to_sphy(x)         container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+       struct clk *ref_clk;
+       int refclk_freq = 0;
+
+       ref_clk = clk_get(sphy->dev, "xusbxti");
+       if (IS_ERR(ref_clk)) {
+               dev_err(sphy->dev, "Failed to get reference clock\n");
+               return PTR_ERR(ref_clk);
+       }
+
+       switch (clk_get_rate(ref_clk)) {
+       case 12 * MHZ:
+               refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+               break;
+       case 24 * MHZ:
+               refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+               break;
+       default:
+       case 48 * MHZ:
+               /* default reference clock */
+               refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+               break;
+       }
+       clk_put(ref_clk);
+
+       return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phypwr;
+       u32 phyclk;
+       u32 rstcon;
+
+       /* set clock frequency for PLL */
+       phyclk = sphy->ref_clk_freq;
+       phypwr = readl(regs + S3C_PHYPWR);
+       rstcon = readl(regs + S3C_RSTCON);
+
+       switch (sphy->cpu_type) {
+       case TYPE_S3C64XX:
+               phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+               phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+               rstcon |= S3C_RSTCON_PHY;
+               break;
+       case TYPE_EXYNOS4210:
+               phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+               rstcon |= S3C_RSTCON_PHY;
+       default:
+               break;
+       }
+
+       writel(phyclk, regs + S3C_PHYCLK);
+       /* set to normal of PHY0 */
+       writel(phypwr, regs + S3C_PHYPWR);
+       /* reset all ports of PHY and Link */
+       writel(rstcon, regs + S3C_RSTCON);
+       udelay(10);
+       rstcon &= ~S3C_RSTCON_PHY;
+       writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phypwr;
+
+       phypwr = readl(regs + S3C_PHYPWR);
+
+       switch (sphy->cpu_type) {
+       case TYPE_S3C64XX:
+               phypwr |= S3C_PHYPWR_NORMAL_MASK;
+               break;
+       case TYPE_EXYNOS4210:
+               phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+       default:
+               break;
+       }
+
+       /* unset to normal of PHY0 */
+       writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+       int ret = 0;
+
+       sphy = phy_to_sphy(phy);
+
+       /* Enable the phy clock */
+       ret = clk_prepare_enable(sphy->clk);
+       if (ret) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return ret;
+       }
+
+       /* Disable phy isolation */
+       if (sphy->plat && sphy->plat->pmu_isolation)
+               sphy->plat->pmu_isolation(false);
+
+       /* Initialize usb phy registers */
+       samsung_usbphy_enable(sphy);
+
+       /* Disable the phy clock */
+       clk_disable_unprepare(sphy->clk);
+       return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+
+       sphy = phy_to_sphy(phy);
+
+       if (clk_prepare_enable(sphy->clk)) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return;
+       }
+
+       /* De-initialize usb phy registers */
+       samsung_usbphy_disable(sphy);
+
+       /* Enable phy isolation */
+       if (sphy->plat && sphy->plat->pmu_isolation)
+               sphy->plat->pmu_isolation(true);
+
+       clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+       if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+               int data;
+               const struct of_device_id *match;
+               match = of_match_node(samsung_usbphy_dt_match,
+                                                       pdev->dev.of_node);
+               data = (int) match->data;
+               return data;
+       }
+
+       return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy;
+       struct samsung_usbphy_data *pdata;
+       struct device *dev = &pdev->dev;
+       struct resource *phy_mem;
+       void __iomem    *phy_base;
+       struct clk *clk;
+       int     ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+               return -EINVAL;
+       }
+
+       phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!phy_mem) {
+               dev_err(dev, "%s: missing mem resource\n", __func__);
+               return -ENODEV;
+       }
+
+       phy_base = devm_request_and_ioremap(dev, phy_mem);
+       if (!phy_base) {
+               dev_err(dev, "%s: register mapping failed\n", __func__);
+               return -ENXIO;
+       }
+
+       sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+       if (!sphy)
+               return -ENOMEM;
+
+       clk = devm_clk_get(dev, "otg");
+       if (IS_ERR(clk)) {
+               dev_err(dev, "Failed to get otg clock\n");
+               return PTR_ERR(clk);
+       }
+
+       sphy->dev               = &pdev->dev;
+       sphy->plat              = pdata;
+       sphy->regs              = phy_base;
+       sphy->clk               = clk;
+       sphy->phy.dev           = sphy->dev;
+       sphy->phy.label         = "samsung-usbphy";
+       sphy->phy.init          = samsung_usbphy_init;
+       sphy->phy.shutdown      = samsung_usbphy_shutdown;
Quoted 8 lines

drivers/usb/phy/samsung-usbphy.c line 301

Quoted 8 lines
drivers/usb/phy/samsung-usbphy.c new file +8 -0
+       sphy->cpu_type          = samsung_usbphy_get_driver_data(pdev);
+       sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
+
+       ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+       if (ret)
+               goto err;
+
+       platform_set_drvdata(pdev, sphy);

To avoid potential race conditions, you should first setup platform_set_drvdata(), then add the phy.

Quoted 104 lines
Quoted 95 lines
drivers/usb/phy/samsung-usbphy.c new file +59 -0
+err:
+       return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&sphy->phy);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+       {
+               .compatible = "samsung,s3c64xx-usbphy",
+               .data = (void *)TYPE_S3C64XX,
+       }, {
+               .compatible = "samsung,exynos4210-usbphy",
+               .data = (void *)TYPE_EXYNOS4210,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+       {
+               .name           = "s3c64xx-usbphy",
+               .driver_data    = TYPE_S3C64XX,
+       }, {
+               .name           = "exynos4210-usbphy",
+               .driver_data    = TYPE_EXYNOS4210,
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+       .probe          = samsung_usbphy_probe,
+       .remove         = __devexit_p(samsung_usbphy_remove),
+       .id_table       = samsung_usbphy_driver_ids,
+       .driver         = {
+               .name   = "samsung-usbphy",
+               .owner  = THIS_MODULE,
+               .of_match_table = samsung_usbphy_dt_match,
+       },
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +27 -1
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *             http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+       void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
--

1.7.1

Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 12 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 259 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120925/0201bc14/attachment.sig>
#5 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

Quoted 372 lines · Marc Kleine-Budde
Quoted 3 lines · Praveen Paneri

Hi Kishon, Felipe,

Any further comments on these patches? Can they be merged now?

One nitpick inline.

Marc

Quoted 364 lines

Thanks,
Praveen

Quoted 359 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +9 -0
new file mode 100644
index 0000000..fefd9c8
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+       region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
        help
          Enable this to support Marvell USB 3.0 phy controller for Marvell
          SoC.
+
+config SAMSUNG_USBPHY
+       bool "Samsung USB PHY controller Driver"
+       depends on USB_S3C_HSOTG
+       select USB_OTG_UTILS
+       help
+         Enable this to support Samsung USB phy controller for samsung
+         SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)                 += omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)              += isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)               += mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)   += tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)           += samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +296 -0
new file mode 100644
index 0000000..95ec4d0
@@ -0,0 +1,360 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR                             (0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK                 (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE                 (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN            (1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND               (1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK             (0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP                   (1 << 5)
+
+#define S3C_PHYCLK                             (0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL                 (1 << 6)
+#define S3C_PHYCLK_EXT_OSC                     (1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N                 (1 << 4)
+#define S3C_PHYCLK_ID_PULL                     (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                 (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                        (0)
+#define S3C_PHYCLK_CLKSEL_48M                  (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                  (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                  (0x3 << 0)
+
+#define S3C_RSTCON                             (0x08)
+
+#define S3C_RSTCON_PHYCLK                      (1 << 2)
+#define S3C_RSTCON_HCLK                                (1 << 1)
+#define S3C_RSTCON_PHY                         (1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+       TYPE_S3C64XX,
+       TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+       struct usb_phy  phy;
+       struct samsung_usbphy_data *plat;
+       struct device   *dev;
+       struct clk      *clk;
+       void __iomem    *regs;
+       int             ref_clk_freq;
+       int             cpu_type;
+};
+
+#define phy_to_sphy(x)         container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+       struct clk *ref_clk;
+       int refclk_freq = 0;
+
+       ref_clk = clk_get(sphy->dev, "xusbxti");
+       if (IS_ERR(ref_clk)) {
+               dev_err(sphy->dev, "Failed to get reference clock\n");
+               return PTR_ERR(ref_clk);
+       }
+
+       switch (clk_get_rate(ref_clk)) {
+       case 12 * MHZ:
+               refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+               break;
+       case 24 * MHZ:
+               refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+               break;
+       default:
+       case 48 * MHZ:
+               /* default reference clock */
+               refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+               break;
+       }
+       clk_put(ref_clk);
+
+       return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phypwr;
+       u32 phyclk;
+       u32 rstcon;
+
+       /* set clock frequency for PLL */
+       phyclk = sphy->ref_clk_freq;
+       phypwr = readl(regs + S3C_PHYPWR);
+       rstcon = readl(regs + S3C_RSTCON);
+
+       switch (sphy->cpu_type) {
+       case TYPE_S3C64XX:
+               phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+               phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+               rstcon |= S3C_RSTCON_PHY;
+               break;
+       case TYPE_EXYNOS4210:
+               phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+               rstcon |= S3C_RSTCON_PHY;
+       default:
+               break;
+       }
+
+       writel(phyclk, regs + S3C_PHYCLK);
+       /* set to normal of PHY0 */
+       writel(phypwr, regs + S3C_PHYPWR);
+       /* reset all ports of PHY and Link */
+       writel(rstcon, regs + S3C_RSTCON);
+       udelay(10);
+       rstcon &= ~S3C_RSTCON_PHY;
+       writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+       void __iomem *regs = sphy->regs;
+       u32 phypwr;
+
+       phypwr = readl(regs + S3C_PHYPWR);
+
+       switch (sphy->cpu_type) {
+       case TYPE_S3C64XX:
+               phypwr |= S3C_PHYPWR_NORMAL_MASK;
+               break;
+       case TYPE_EXYNOS4210:
+               phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+       default:
+               break;
+       }
+
+       /* unset to normal of PHY0 */
+       writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+       int ret = 0;
+
+       sphy = phy_to_sphy(phy);
+
+       /* Enable the phy clock */
+       ret = clk_prepare_enable(sphy->clk);
+       if (ret) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return ret;
+       }
+
+       /* Disable phy isolation */
+       if (sphy->plat && sphy->plat->pmu_isolation)
+               sphy->plat->pmu_isolation(false);
+
+       /* Initialize usb phy registers */
+       samsung_usbphy_enable(sphy);
+
+       /* Disable the phy clock */
+       clk_disable_unprepare(sphy->clk);
+       return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+       struct samsung_usbphy *sphy;
+
+       sphy = phy_to_sphy(phy);
+
+       if (clk_prepare_enable(sphy->clk)) {
+               dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+               return;
+       }
+
+       /* De-initialize usb phy registers */
+       samsung_usbphy_disable(sphy);
+
+       /* Enable phy isolation */
+       if (sphy->plat && sphy->plat->pmu_isolation)
+               sphy->plat->pmu_isolation(true);
+
+       clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+       if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+               int data;
+               const struct of_device_id *match;
+               match = of_match_node(samsung_usbphy_dt_match,
+                                                       pdev->dev.of_node);
+               data = (int) match->data;
+               return data;
+       }
+
+       return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy;
+       struct samsung_usbphy_data *pdata;
+       struct device *dev = &pdev->dev;
+       struct resource *phy_mem;
+       void __iomem    *phy_base;
+       struct clk *clk;
+       int     ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+               return -EINVAL;
+       }
+
+       phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!phy_mem) {
+               dev_err(dev, "%s: missing mem resource\n", __func__);
+               return -ENODEV;
+       }
+
+       phy_base = devm_request_and_ioremap(dev, phy_mem);
+       if (!phy_base) {
+               dev_err(dev, "%s: register mapping failed\n", __func__);
+               return -ENXIO;
+       }
+
+       sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+       if (!sphy)
+               return -ENOMEM;
+
+       clk = devm_clk_get(dev, "otg");
+       if (IS_ERR(clk)) {
+               dev_err(dev, "Failed to get otg clock\n");
+               return PTR_ERR(clk);
+       }
+
+       sphy->dev               = &pdev->dev;
+       sphy->plat              = pdata;
+       sphy->regs              = phy_base;
+       sphy->clk               = clk;
+       sphy->phy.dev           = sphy->dev;
+       sphy->phy.label         = "samsung-usbphy";
+       sphy->phy.init          = samsung_usbphy_init;
+       sphy->phy.shutdown      = samsung_usbphy_shutdown;
+       sphy->cpu_type          = samsung_usbphy_get_driver_data(pdev);
+       sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
+
Quoted 8 lines
Quoted 5 lines

drivers/usb/phy/samsung-usbphy.c line 301

Quoted 5 lines
drivers/usb/phy/samsung-usbphy.c new file +5 -0
+       ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+       if (ret)
+               goto err;
+
+       platform_set_drvdata(pdev, sphy);

To avoid potential race conditions, you should first setup platform_set_drvdata(), then add the phy.

It will not be the case as driver_data is not used as of now, may be I can just remove the platform_set_drvdata() call from here.

Quoted 113 lines
Quoted 96 lines
Quoted 96 lines
drivers/usb/phy/samsung-usbphy.c new file +59 -0
+err:
+       return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+       struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&sphy->phy);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+       {
+               .compatible = "samsung,s3c64xx-usbphy",
+               .data = (void *)TYPE_S3C64XX,
+       }, {
+               .compatible = "samsung,exynos4210-usbphy",
+               .data = (void *)TYPE_EXYNOS4210,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+       {
+               .name           = "s3c64xx-usbphy",
+               .driver_data    = TYPE_S3C64XX,
+       }, {
+               .name           = "exynos4210-usbphy",
+               .driver_data    = TYPE_EXYNOS4210,
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+       .probe          = samsung_usbphy_probe,
+       .remove         = __devexit_p(samsung_usbphy_remove),
+       .id_table       = samsung_usbphy_driver_ids,
+       .driver         = {
+               .name   = "samsung-usbphy",
+               .owner  = THIS_MODULE,
+               .of_match_table = samsung_usbphy_dt_match,
+       },
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +27 -1
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *             http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+       void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
--

1.7.1

Quoted 9 lines
Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

--

Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |
#6 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

Quoted 1 line

From v6:

Added TODO for phy bindings with controller
Dropped platform_set_drvdata() from driver probe

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |   11 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  355 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 402 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +11 -0
new file mode 100644
index 0000000..7d54d59
@@ -0,0 +1,11 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+TODO: Adding the PHY binding with controller(s) according to the under 
+developement generic PHY driver.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+	region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
 	help
 	  Enable this to support Marvell USB 3.0 phy controller for Marvell
 	  SoC.
+
+config SAMSUNG_USBPHY
+	bool "Samsung USB PHY controller Driver"
+	depends on USB_S3C_HSOTG
+	select USB_OTG_UTILS
+	help
+	  Enable this to support Samsung USB phy controller for samsung
+	  SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)			+= omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +355 -0

355 lines not on this page · raw message

include/linux/platform_data/samsung-usbphy.h new file +27 -0
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *		http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+	void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
Signature · 1 line
1.7.1
#7 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

platform_set_drvdata() required for driver's remove function, so adding it back.

Quoted 1 line

From v6:

Added TODO for phy bindings with controller
Dropped platform_set_drvdata() from driver probe

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |   11 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  357 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 404 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +11 -0
new file mode 100644
index 0000000..7b26e2d
@@ -0,0 +1,11 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+TODO: Adding the PHY binding with controller(s) according to the under
+developement generic PHY driver.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+	region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
 	help
 	  Enable this to support Marvell USB 3.0 phy controller for Marvell
 	  SoC.
+
+config SAMSUNG_USBPHY
+	bool "Samsung USB PHY controller Driver"
+	depends on USB_S3C_HSOTG
+	select USB_OTG_UTILS
+	help
+	  Enable this to support Samsung USB phy controller for samsung
+	  SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)			+= omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +357 -0

357 lines not on this page · raw message

include/linux/platform_data/samsung-usbphy.h new file +27 -0
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *		http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+	void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
Signature · 1 line
1.7.1
#8 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

Quoted 11 lines · Praveen Paneri

platform_set_drvdata() required for driver's remove function, so adding it back.

From v6:
Added TODO for phy bindings with controller
Dropped platform_set_drvdata() from driver probe

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

this commit log needs improvement. There are stuff there which shouldn't go to git's history.

I would like to get Tested-bys and Acked-by from DT maintainers.

Quoted 454 lines
---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |   11 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  357 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 404 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +11 -0
new file mode 100644
index 0000000..7b26e2d
@@ -0,0 +1,11 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+TODO: Adding the PHY binding with controller(s) according to the under
+developement generic PHY driver.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+	region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
 	help
 	  Enable this to support Marvell USB 3.0 phy controller for Marvell
 	  SoC.
+
+config SAMSUNG_USBPHY
+	bool "Samsung USB PHY controller Driver"
+	depends on USB_S3C_HSOTG
+	select USB_OTG_UTILS
+	help
+	  Enable this to support Samsung USB phy controller for samsung
+	  SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)			+= omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +357 -0
new file mode 100644
index 0000000..14c182f
@@ -0,0 +1,357 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR				(0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK			(0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE			(1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN		(1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND		(1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK		(0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP			(1 << 5)
+
+#define S3C_PHYCLK				(0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL			(1 << 6)
+#define S3C_PHYCLK_EXT_OSC			(1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N			(1 << 4)
+#define S3C_PHYCLK_ID_PULL			(1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK			(0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT			(0)
+#define S3C_PHYCLK_CLKSEL_48M			(0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M			(0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M			(0x3 << 0)
+
+#define S3C_RSTCON				(0x08)
+
+#define S3C_RSTCON_PHYCLK			(1 << 2)
+#define S3C_RSTCON_HCLK				(1 << 1)
+#define S3C_RSTCON_PHY				(1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+	TYPE_S3C64XX,
+	TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+	struct usb_phy	phy;
+	struct samsung_usbphy_data *plat;
+	struct device	*dev;
+	struct clk	*clk;
+	void __iomem	*regs;
+	int		ref_clk_freq;
+	int		cpu_type;
+};
+
+#define phy_to_sphy(x)		container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+	struct clk *ref_clk;
+	int refclk_freq = 0;
+
+	ref_clk = clk_get(sphy->dev, "xusbxti");
+	if (IS_ERR(ref_clk)) {
+		dev_err(sphy->dev, "Failed to get reference clock\n");
+		return PTR_ERR(ref_clk);
+	}
+
+	switch (clk_get_rate(ref_clk)) {
+	case 12 * MHZ:
+		refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+		break;
+	case 24 * MHZ:
+		refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+		break;
+	default:
+	case 48 * MHZ:
+		/* default reference clock */
+		refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+		break;
+	}
+	clk_put(ref_clk);
+
+	return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+	void __iomem *regs = sphy->regs;
+	u32 phypwr;
+	u32 phyclk;
+	u32 rstcon;
+
+	/* set clock frequency for PLL */
+	phyclk = sphy->ref_clk_freq;
+	phypwr = readl(regs + S3C_PHYPWR);
+	rstcon = readl(regs + S3C_RSTCON);
+
+	switch (sphy->cpu_type) {
+	case TYPE_S3C64XX:
+		phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+		phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+		rstcon |= S3C_RSTCON_PHY;
+		break;
+	case TYPE_EXYNOS4210:
+		phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+		rstcon |= S3C_RSTCON_PHY;
+	default:
+		break;
+	}
+
+	writel(phyclk, regs + S3C_PHYCLK);
+	/* set to normal of PHY0 */
+	writel(phypwr, regs + S3C_PHYPWR);
+	/* reset all ports of PHY and Link */
+	writel(rstcon, regs + S3C_RSTCON);
+	udelay(10);
+	rstcon &= ~S3C_RSTCON_PHY;
+	writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+	void __iomem *regs = sphy->regs;
+	u32 phypwr;
+
+	phypwr = readl(regs + S3C_PHYPWR);
+
+	switch (sphy->cpu_type) {
+	case TYPE_S3C64XX:
+		phypwr |= S3C_PHYPWR_NORMAL_MASK;
+		break;
+	case TYPE_EXYNOS4210:
+		phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+	default:
+		break;
+	}
+
+	/* unset to normal of PHY0 */
+	writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+	struct samsung_usbphy *sphy;
+	int ret = 0;
+
+	sphy = phy_to_sphy(phy);
+
+	/* Enable the phy clock */
+	ret = clk_prepare_enable(sphy->clk);
+	if (ret) {
+		dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+		return ret;
+	}
+
+	/* Disable phy isolation */
+	if (sphy->plat && sphy->plat->pmu_isolation)
+		sphy->plat->pmu_isolation(false);
+
+	/* Initialize usb phy registers */
+	samsung_usbphy_enable(sphy);
+
+	/* Disable the phy clock */
+	clk_disable_unprepare(sphy->clk);
+	return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+	struct samsung_usbphy *sphy;
+
+	sphy = phy_to_sphy(phy);
+
+	if (clk_prepare_enable(sphy->clk)) {
+		dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+		return;
+	}
+
+	/* De-initialize usb phy registers */
+	samsung_usbphy_disable(sphy);
+
+	/* Enable phy isolation */
+	if (sphy->plat && sphy->plat->pmu_isolation)
+		sphy->plat->pmu_isolation(true);
+
+	clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+		int data;
+		const struct of_device_id *match;
+		match = of_match_node(samsung_usbphy_dt_match,
+							pdev->dev.of_node);
+		data = (int) match->data;
+		return data;
+	}
+
+	return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+	struct samsung_usbphy *sphy;
+	struct samsung_usbphy_data *pdata;
+	struct device *dev = &pdev->dev;
+	struct resource *phy_mem;
+	void __iomem	*phy_base;
+	struct clk *clk;
+	int	ret = 0;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+		return -EINVAL;
+	}
+
+	phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!phy_mem) {
+		dev_err(dev, "%s: missing mem resource\n", __func__);
+		return -ENODEV;
+	}
+
+	phy_base = devm_request_and_ioremap(dev, phy_mem);
+	if (!phy_base) {
+		dev_err(dev, "%s: register mapping failed\n", __func__);
+		return -ENXIO;
+	}
+
+	sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+	if (!sphy)
+		return -ENOMEM;
+
+	clk = devm_clk_get(dev, "otg");
+	if (IS_ERR(clk)) {
+		dev_err(dev, "Failed to get otg clock\n");
+		return PTR_ERR(clk);
+	}
+
+	sphy->dev		= &pdev->dev;
+	sphy->plat		= pdata;
+	sphy->regs		= phy_base;
+	sphy->clk		= clk;
+	sphy->phy.dev		= sphy->dev;
+	sphy->phy.label		= "samsung-usbphy";
+	sphy->phy.init		= samsung_usbphy_init;
+	sphy->phy.shutdown	= samsung_usbphy_shutdown;
+	sphy->cpu_type		= samsung_usbphy_get_driver_data(pdev);
+	sphy->ref_clk_freq	= samsung_usbphy_get_refclk_freq(sphy);
+
+	platform_set_drvdata(pdev, sphy);
+
+	ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+	return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+	struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+	usb_remove_phy(&sphy->phy);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+	{
+		.compatible = "samsung,s3c64xx-usbphy",
+		.data = (void *)TYPE_S3C64XX,
+	}, {
+		.compatible = "samsung,exynos4210-usbphy",
+		.data = (void *)TYPE_EXYNOS4210,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+	{
+		.name		= "s3c64xx-usbphy",
+		.driver_data	= TYPE_S3C64XX,
+	}, {
+		.name		= "exynos4210-usbphy",
+		.driver_data	= TYPE_EXYNOS4210,
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+	.probe		= samsung_usbphy_probe,
+	.remove		= __devexit_p(samsung_usbphy_remove),
+	.id_table	= samsung_usbphy_driver_ids,
+	.driver		= {
+		.name	= "samsung-usbphy",
+		.owner	= THIS_MODULE,
+		.of_match_table = samsung_usbphy_dt_match,
+	},
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +27 -0
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *		http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+	void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
Signature · 1 line
1.7.1
Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121015/73c439f6/attachment.sig>
#9 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

+ Tomasz Figa,

Quoted 475 lines · Felipe Balbi
Quoted 11 lines · Praveen Paneri

platform_set_drvdata() required for driver's remove function, so adding it back.

From v6:
Added TODO for phy bindings with controller
Dropped platform_set_drvdata() from driver probe

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

this commit log needs improvement. There are stuff there which shouldn't go to git's history.

I would like to get Tested-bys and Acked-by from DT maintainers.

Quoted 452 lines
---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |   11 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  357 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 404 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +11 -0
new file mode 100644
index 0000000..7b26e2d
@@ -0,0 +1,11 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+TODO: Adding the PHY binding with controller(s) according to the under
+developement generic PHY driver.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+     region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
      help
        Enable this to support Marvell USB 3.0 phy controller for Marvell
        SoC.
+
+config SAMSUNG_USBPHY
+     bool "Samsung USB PHY controller Driver"
+     depends on USB_S3C_HSOTG
+     select USB_OTG_UTILS
+     help
+       Enable this to support Samsung USB phy controller for samsung
+       SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)                       += omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)            += isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)             += mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)         += samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +357 -0
new file mode 100644
index 0000000..14c182f
@@ -0,0 +1,357 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR                           (0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK                       (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE                       (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN          (1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND             (1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK           (0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP                 (1 << 5)
+
+#define S3C_PHYCLK                           (0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL                       (1 << 6)
+#define S3C_PHYCLK_EXT_OSC                   (1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N                       (1 << 4)
+#define S3C_PHYCLK_ID_PULL                   (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                       (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                      (0)
+#define S3C_PHYCLK_CLKSEL_48M                        (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                        (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                        (0x3 << 0)
+
+#define S3C_RSTCON                           (0x08)
+
+#define S3C_RSTCON_PHYCLK                    (1 << 2)
+#define S3C_RSTCON_HCLK                              (1 << 1)
+#define S3C_RSTCON_PHY                               (1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+     TYPE_S3C64XX,
+     TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+     struct usb_phy  phy;
+     struct samsung_usbphy_data *plat;
+     struct device   *dev;
+     struct clk      *clk;
+     void __iomem    *regs;
+     int             ref_clk_freq;
+     int             cpu_type;
+};
+
+#define phy_to_sphy(x)               container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+     struct clk *ref_clk;
+     int refclk_freq = 0;
+
+     ref_clk = clk_get(sphy->dev, "xusbxti");
+     if (IS_ERR(ref_clk)) {
+             dev_err(sphy->dev, "Failed to get reference clock\n");
+             return PTR_ERR(ref_clk);
+     }
+
+     switch (clk_get_rate(ref_clk)) {
+     case 12 * MHZ:
+             refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+             break;
+     case 24 * MHZ:
+             refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+             break;
+     default:
+     case 48 * MHZ:
+             /* default reference clock */
+             refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+             break;
+     }
+     clk_put(ref_clk);
+
+     return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+     void __iomem *regs = sphy->regs;
+     u32 phypwr;
+     u32 phyclk;
+     u32 rstcon;
+
+     /* set clock frequency for PLL */
+     phyclk = sphy->ref_clk_freq;
+     phypwr = readl(regs + S3C_PHYPWR);
+     rstcon = readl(regs + S3C_RSTCON);
+
+     switch (sphy->cpu_type) {
+     case TYPE_S3C64XX:
+             phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+             phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+             rstcon |= S3C_RSTCON_PHY;
+             break;
+     case TYPE_EXYNOS4210:
+             phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+             rstcon |= S3C_RSTCON_PHY;
+     default:
+             break;
+     }
+
+     writel(phyclk, regs + S3C_PHYCLK);
+     /* set to normal of PHY0 */
+     writel(phypwr, regs + S3C_PHYPWR);
+     /* reset all ports of PHY and Link */
+     writel(rstcon, regs + S3C_RSTCON);
+     udelay(10);
+     rstcon &= ~S3C_RSTCON_PHY;
+     writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+     void __iomem *regs = sphy->regs;
+     u32 phypwr;
+
+     phypwr = readl(regs + S3C_PHYPWR);
+
+     switch (sphy->cpu_type) {
+     case TYPE_S3C64XX:
+             phypwr |= S3C_PHYPWR_NORMAL_MASK;
+             break;
+     case TYPE_EXYNOS4210:
+             phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+     default:
+             break;
+     }
+
+     /* unset to normal of PHY0 */
+     writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+     struct samsung_usbphy *sphy;
+     int ret = 0;
+
+     sphy = phy_to_sphy(phy);
+
+     /* Enable the phy clock */
+     ret = clk_prepare_enable(sphy->clk);
+     if (ret) {
+             dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+             return ret;
+     }
+
+     /* Disable phy isolation */
+     if (sphy->plat && sphy->plat->pmu_isolation)
+             sphy->plat->pmu_isolation(false);
+
+     /* Initialize usb phy registers */
+     samsung_usbphy_enable(sphy);
+
+     /* Disable the phy clock */
+     clk_disable_unprepare(sphy->clk);
+     return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+     struct samsung_usbphy *sphy;
+
+     sphy = phy_to_sphy(phy);
+
+     if (clk_prepare_enable(sphy->clk)) {
+             dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+             return;
+     }
+
+     /* De-initialize usb phy registers */
+     samsung_usbphy_disable(sphy);
+
+     /* Enable phy isolation */
+     if (sphy->plat && sphy->plat->pmu_isolation)
+             sphy->plat->pmu_isolation(true);
+
+     clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+     if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+             int data;
+             const struct of_device_id *match;
+             match = of_match_node(samsung_usbphy_dt_match,
+                                                     pdev->dev.of_node);
+             data = (int) match->data;
+             return data;
+     }
+
+     return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+     struct samsung_usbphy *sphy;
+     struct samsung_usbphy_data *pdata;
+     struct device *dev = &pdev->dev;
+     struct resource *phy_mem;
+     void __iomem    *phy_base;
+     struct clk *clk;
+     int     ret = 0;
+
+     pdata = pdev->dev.platform_data;
+     if (!pdata) {
+             dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+             return -EINVAL;
+     }
+
+     phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+     if (!phy_mem) {
+             dev_err(dev, "%s: missing mem resource\n", __func__);
+             return -ENODEV;
+     }
+
+     phy_base = devm_request_and_ioremap(dev, phy_mem);
+     if (!phy_base) {
+             dev_err(dev, "%s: register mapping failed\n", __func__);
+             return -ENXIO;
+     }
+
+     sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+     if (!sphy)
+             return -ENOMEM;
+
+     clk = devm_clk_get(dev, "otg");
+     if (IS_ERR(clk)) {
+             dev_err(dev, "Failed to get otg clock\n");
+             return PTR_ERR(clk);
+     }
+
+     sphy->dev               = &pdev->dev;
+     sphy->plat              = pdata;
+     sphy->regs              = phy_base;
+     sphy->clk               = clk;
+     sphy->phy.dev           = sphy->dev;
+     sphy->phy.label         = "samsung-usbphy";
+     sphy->phy.init          = samsung_usbphy_init;
+     sphy->phy.shutdown      = samsung_usbphy_shutdown;
+     sphy->cpu_type          = samsung_usbphy_get_driver_data(pdev);
+     sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
+
+     platform_set_drvdata(pdev, sphy);
+
+     ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+     return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+     struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+     usb_remove_phy(&sphy->phy);
+
+     return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+     {
+             .compatible = "samsung,s3c64xx-usbphy",
+             .data = (void *)TYPE_S3C64XX,
+     }, {
+             .compatible = "samsung,exynos4210-usbphy",
+             .data = (void *)TYPE_EXYNOS4210,
+     },
+     {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+     {
+             .name           = "s3c64xx-usbphy",
+             .driver_data    = TYPE_S3C64XX,
+     }, {
+             .name           = "exynos4210-usbphy",
+             .driver_data    = TYPE_EXYNOS4210,
+     },
+     {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+     .probe          = samsung_usbphy_probe,
+     .remove         = __devexit_p(samsung_usbphy_remove),
+     .id_table       = samsung_usbphy_driver_ids,
+     .driver         = {
+             .name   = "samsung-usbphy",
+             .owner  = THIS_MODULE,
+             .of_match_table = samsung_usbphy_dt_match,
+     },
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +27 -1
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *           http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+     void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
--
Quoted 2 lines

1.7.1

--
balbi

#10 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

In reply to Felipe Balbi
Quoted 8 lines · Felipe Balbi
Quoted 7 lines · Praveen Paneri

platform_set_drvdata() required for driver's remove function, so adding it back.

From v6:
Added TODO for phy bindings with controller
Dropped platform_set_drvdata() from driver probe

Quoted 7 lines
Quoted 4 lines

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

this commit log needs improvement. There are stuff there which shouldn't go to git's history.

I will resend the patches with improved commit log.

Thanks,
Praveen

Quoted 460 lines

I would like to get Tested-bys and Acked-by from DT maintainers.

Quoted 452 lines
---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |   11 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  357 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 404 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +11 -0
new file mode 100644
index 0000000..7b26e2d
@@ -0,0 +1,11 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+TODO: Adding the PHY binding with controller(s) according to the under
+developement generic PHY driver.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+     region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
      help
        Enable this to support Marvell USB 3.0 phy controller for Marvell
        SoC.
+
+config SAMSUNG_USBPHY
+     bool "Samsung USB PHY controller Driver"
+     depends on USB_S3C_HSOTG
+     select USB_OTG_UTILS
+     help
+       Enable this to support Samsung USB phy controller for samsung
+       SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)                       += omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)            += isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)             += mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)         += samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +357 -0
new file mode 100644
index 0000000..14c182f
@@ -0,0 +1,357 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR                           (0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK                       (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE                       (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN          (1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND             (1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK           (0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP                 (1 << 5)
+
+#define S3C_PHYCLK                           (0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL                       (1 << 6)
+#define S3C_PHYCLK_EXT_OSC                   (1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N                       (1 << 4)
+#define S3C_PHYCLK_ID_PULL                   (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                       (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                      (0)
+#define S3C_PHYCLK_CLKSEL_48M                        (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                        (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                        (0x3 << 0)
+
+#define S3C_RSTCON                           (0x08)
+
+#define S3C_RSTCON_PHYCLK                    (1 << 2)
+#define S3C_RSTCON_HCLK                              (1 << 1)
+#define S3C_RSTCON_PHY                               (1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+     TYPE_S3C64XX,
+     TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+     struct usb_phy  phy;
+     struct samsung_usbphy_data *plat;
+     struct device   *dev;
+     struct clk      *clk;
+     void __iomem    *regs;
+     int             ref_clk_freq;
+     int             cpu_type;
+};
+
+#define phy_to_sphy(x)               container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+     struct clk *ref_clk;
+     int refclk_freq = 0;
+
+     ref_clk = clk_get(sphy->dev, "xusbxti");
+     if (IS_ERR(ref_clk)) {
+             dev_err(sphy->dev, "Failed to get reference clock\n");
+             return PTR_ERR(ref_clk);
+     }
+
+     switch (clk_get_rate(ref_clk)) {
+     case 12 * MHZ:
+             refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+             break;
+     case 24 * MHZ:
+             refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+             break;
+     default:
+     case 48 * MHZ:
+             /* default reference clock */
+             refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+             break;
+     }
+     clk_put(ref_clk);
+
+     return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+     void __iomem *regs = sphy->regs;
+     u32 phypwr;
+     u32 phyclk;
+     u32 rstcon;
+
+     /* set clock frequency for PLL */
+     phyclk = sphy->ref_clk_freq;
+     phypwr = readl(regs + S3C_PHYPWR);
+     rstcon = readl(regs + S3C_RSTCON);
+
+     switch (sphy->cpu_type) {
+     case TYPE_S3C64XX:
+             phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+             phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+             rstcon |= S3C_RSTCON_PHY;
+             break;
+     case TYPE_EXYNOS4210:
+             phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+             rstcon |= S3C_RSTCON_PHY;
+     default:
+             break;
+     }
+
+     writel(phyclk, regs + S3C_PHYCLK);
+     /* set to normal of PHY0 */
+     writel(phypwr, regs + S3C_PHYPWR);
+     /* reset all ports of PHY and Link */
+     writel(rstcon, regs + S3C_RSTCON);
+     udelay(10);
+     rstcon &= ~S3C_RSTCON_PHY;
+     writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+     void __iomem *regs = sphy->regs;
+     u32 phypwr;
+
+     phypwr = readl(regs + S3C_PHYPWR);
+
+     switch (sphy->cpu_type) {
+     case TYPE_S3C64XX:
+             phypwr |= S3C_PHYPWR_NORMAL_MASK;
+             break;
+     case TYPE_EXYNOS4210:
+             phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+     default:
+             break;
+     }
+
+     /* unset to normal of PHY0 */
+     writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+     struct samsung_usbphy *sphy;
+     int ret = 0;
+
+     sphy = phy_to_sphy(phy);
+
+     /* Enable the phy clock */
+     ret = clk_prepare_enable(sphy->clk);
+     if (ret) {
+             dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+             return ret;
+     }
+
+     /* Disable phy isolation */
+     if (sphy->plat && sphy->plat->pmu_isolation)
+             sphy->plat->pmu_isolation(false);
+
+     /* Initialize usb phy registers */
+     samsung_usbphy_enable(sphy);
+
+     /* Disable the phy clock */
+     clk_disable_unprepare(sphy->clk);
+     return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+     struct samsung_usbphy *sphy;
+
+     sphy = phy_to_sphy(phy);
+
+     if (clk_prepare_enable(sphy->clk)) {
+             dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+             return;
+     }
+
+     /* De-initialize usb phy registers */
+     samsung_usbphy_disable(sphy);
+
+     /* Enable phy isolation */
+     if (sphy->plat && sphy->plat->pmu_isolation)
+             sphy->plat->pmu_isolation(true);
+
+     clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+     if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+             int data;
+             const struct of_device_id *match;
+             match = of_match_node(samsung_usbphy_dt_match,
+                                                     pdev->dev.of_node);
+             data = (int) match->data;
+             return data;
+     }
+
+     return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+     struct samsung_usbphy *sphy;
+     struct samsung_usbphy_data *pdata;
+     struct device *dev = &pdev->dev;
+     struct resource *phy_mem;
+     void __iomem    *phy_base;
+     struct clk *clk;
+     int     ret = 0;
+
+     pdata = pdev->dev.platform_data;
+     if (!pdata) {
+             dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+             return -EINVAL;
+     }
+
+     phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+     if (!phy_mem) {
+             dev_err(dev, "%s: missing mem resource\n", __func__);
+             return -ENODEV;
+     }
+
+     phy_base = devm_request_and_ioremap(dev, phy_mem);
+     if (!phy_base) {
+             dev_err(dev, "%s: register mapping failed\n", __func__);
+             return -ENXIO;
+     }
+
+     sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+     if (!sphy)
+             return -ENOMEM;
+
+     clk = devm_clk_get(dev, "otg");
+     if (IS_ERR(clk)) {
+             dev_err(dev, "Failed to get otg clock\n");
+             return PTR_ERR(clk);
+     }
+
+     sphy->dev               = &pdev->dev;
+     sphy->plat              = pdata;
+     sphy->regs              = phy_base;
+     sphy->clk               = clk;
+     sphy->phy.dev           = sphy->dev;
+     sphy->phy.label         = "samsung-usbphy";
+     sphy->phy.init          = samsung_usbphy_init;
+     sphy->phy.shutdown      = samsung_usbphy_shutdown;
+     sphy->cpu_type          = samsung_usbphy_get_driver_data(pdev);
+     sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
+
+     platform_set_drvdata(pdev, sphy);
+
+     ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+     return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+     struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+     usb_remove_phy(&sphy->phy);
+
+     return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+     {
+             .compatible = "samsung,s3c64xx-usbphy",
+             .data = (void *)TYPE_S3C64XX,
+     }, {
+             .compatible = "samsung,exynos4210-usbphy",
+             .data = (void *)TYPE_EXYNOS4210,
+     },
+     {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+     {
+             .name           = "s3c64xx-usbphy",
+             .driver_data    = TYPE_S3C64XX,
+     }, {
+             .name           = "exynos4210-usbphy",
+             .driver_data    = TYPE_EXYNOS4210,
+     },
+     {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+     .probe          = samsung_usbphy_probe,
+     .remove         = __devexit_p(samsung_usbphy_remove),
+     .id_table       = samsung_usbphy_driver_ids,
+     .driver         = {
+             .name   = "samsung-usbphy",
+             .owner  = THIS_MODULE,
+             .of_match_table = samsung_usbphy_dt_match,
+     },
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +27 -1
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *           http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+     void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
--
Quoted 2 lines

1.7.1

--
balbi

#11 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

In reply to Felipe Balbi

Hi!

Quoted 1 line
Quoted 1 line

+#define S3C_PHYPWR (0x00)

...

Quoted 11 lines

drivers/usb/phy/samsung-usbphy.c line 52

Quoted 11 lines
drivers/usb/phy/samsung-usbphy.c new file +11 -0
+#define S3C_PHYCLK				(0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL			(1 << 6)
+#define S3C_PHYCLK_EXT_OSC			(1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N			(1 << 4)
+#define S3C_PHYCLK_ID_PULL			(1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK			(0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT			(0)
+#define S3C_PHYCLK_CLKSEL_48M			(0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M			(0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M			(0x3 << 0)

I believe these 0x 's should be removed. Ouch and << 0 is interesting, too, just remove it.

Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#12 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

Hi,

Quoted 4 lines · Pavel Machek

Hi!

Quoted 1 line
Quoted 1 line

+#define S3C_PHYPWR (0x00)

...

Quoted 14 lines
Quoted 11 lines

drivers/usb/phy/samsung-usbphy.c line 52

Quoted 11 lines
drivers/usb/phy/samsung-usbphy.c new file +11 -0
+#define S3C_PHYCLK                         (0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL                     (1 << 6)
+#define S3C_PHYCLK_EXT_OSC                 (1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N                     (1 << 4)
+#define S3C_PHYCLK_ID_PULL                 (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                     (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                    (0)
+#define S3C_PHYCLK_CLKSEL_48M                      (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                      (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                      (0x3 << 0)

I believe these 0x 's should be removed. Ouch and << 0 is interesting, too, just remove it.

Yes it makes sense to maintain a uniform pattern across all the definition. How about maintaining hex values everywhere instead of dropping 0x's? It will make it easier to add big values to the definitions tomorrow, if needed.
About "<< 0", IMHO people must have started using it to maintain a parallelism with other definitions. I do not mind changing it if you still feel that it's very much needed
thanks :)

Praveen

Quoted 9 lines

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#13 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

In reply to Praveen Paneri
Quoted 12 lines · Praveen Paneri

platform_set_drvdata() required for driver's remove function, so adding it back.

From v6:
Added TODO for phy bindings with controller
Dropped platform_set_drvdata() from driver probe

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

Quoted 7 lines
---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |   11 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  357

++++++++++++++++++++

drivers/usb/phy/Makefile obj-$(CONFIG_OMAP_USB2) +=

Quoted 47 lines
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 404 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-
usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +10 -0
new file mode 100644
index 0000000..7b26e2d
@@ -0,0 +1,11 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+TODO: Adding the PHY binding with controller(s) according to the under
+developement generic PHY driver.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory

mapped

Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +1 -0
+	region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
 	help
 	  Enable this to support Marvell USB 3.0 phy controller for Marvell
 	  SoC.
+
+config SAMSUNG_USBPHY
+	bool "Samsung USB PHY controller Driver"
+	depends on USB_S3C_HSOTG
+	select USB_OTG_UTILS
+	help
+	  Enable this to support Samsung USB phy controller for samsung
+	  SoCs.
drivers/usb/phy/Makefile +0 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)			+=

omap-usb2.o

drivers/usb/phy/samsung-usbphy.c

Quoted 10 lines
drivers/usb/phy/Makefile +1 -0
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
drivers/usb/phy/samsung- renamed from drivers/usb/phy/samsung-usbphy.c +0 -0

usbphy.c
new file mode 100644
index 0000000..14c182f

drivers/usb/phy/samsung-usbphy.c new file +0 -0

Hi,

Basically I agree and this is a good approach to support usb phy for Samsung stuff...but there are some comments ;)

Quoted 25 lines
drivers/usb/phy/samsung-usbphy.c new file +8 -0
@@ -0,0 +1,357 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG

controller
+ *
+ * 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.
+ *
+ * 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.
+ */

drivers/usb/phy/samsung-usbphy.c new file +5 -0
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>

drivers/usb/phy/samsung-usbphy.c line 33

Quoted 10 lines
drivers/usb/phy/samsung-usbphy.c new file +10 -0
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR				(0x00)
+

IMHO, according to the file name, samsung-usbphy, SAMSUNG_ is better here?

drivers/usb/phy/samsung-usbphy.c line 39

Quoted 6 lines
drivers/usb/phy/samsung-usbphy.c new file +6 -0
+#define S3C_PHYPWR_NORMAL_MASK			(0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE			(1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN		(1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND		(1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK		(0x39 << 0)

Hmm...is this right? If so, need to use exact name for the definition.

See arch/arm/mach-exynos/include/mach/regs-usb-phy.h

Quoted 1 line

+#define EXYNOS4_PHYPWR_SLEEP (1 << 5)

Ditto.

drivers/usb/phy/samsung-usbphy.c line 44

Quoted 4 lines
drivers/usb/phy/samsung-usbphy.c new file +4 -0
+
+#define S3C_PHYCLK				(0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL			(1 << 6)

MODE_USB11?

drivers/usb/phy/samsung-usbphy.c line 46

Quoted 2 lines
drivers/usb/phy/samsung-usbphy.c new file +2 -0
+#define S3C_PHYCLK_EXT_OSC			(1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N			(1 << 4)

There are Samsung SoCs which is having two PHYs, so I think, we need to design this with considering it.

drivers/usb/phy/samsung-usbphy.c line 52

Quoted 6 lines
drivers/usb/phy/samsung-usbphy.c new file +6 -0
+#define S3C_PHYCLK_ID_PULL			(1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK			(0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT			(0)
+#define S3C_PHYCLK_CLKSEL_48M			(0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M			(0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M			(0x3 << 0)

As you know, the values for CLKSEL are different on each Samsung SoCs...if we use this patch, we need to implement for other SoCs many things. In addition, this patch says can support EXYNOS4210 but not actually...

Quoted 27 lines
drivers/usb/phy/samsung-usbphy.c new file +27 -0
+
+#define S3C_RSTCON				(0x08)
+
+#define S3C_RSTCON_PHYCLK			(1 << 2)
+#define S3C_RSTCON_HCLK				(1 << 1)
+#define S3C_RSTCON_PHY				(1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+	TYPE_S3C64XX,
+	TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {

drivers/usb/phy/samsung-usbphy.c

Quoted 10 lines
drivers/usb/phy/samsung-usbphy.c new file +10 -0
+	struct usb_phy	phy;
+	struct samsung_usbphy_data *plat;
+	struct device	*dev;
+	struct clk	*clk;
+	void __iomem	*regs;
+	int		ref_clk_freq;
+	int		cpu_type;
+};
+
+#define phy_to_sphy(x)		container_of((x), struct

samsung_usbphy,

drivers/usb/phy/samsung-usbphy.c line 100

Quoted 12 lines

phy)

drivers/usb/phy/samsung-usbphy.c new file +11 -0
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+	struct clk *ref_clk;
+	int refclk_freq = 0;
+
+	ref_clk = clk_get(sphy->dev, "xusbxti");
+	if (IS_ERR(ref_clk)) {

IS_ERR_OR_NULL(ref_clk)?

drivers/usb/phy/samsung-usbphy.c line 107

Quoted 7 lines
drivers/usb/phy/samsung-usbphy.c new file +7 -0
+		dev_err(sphy->dev, "Failed to get reference clock\n");
+		return PTR_ERR(ref_clk);
+	}
+
+	switch (clk_get_rate(ref_clk)) {
+	case 12 * MHZ:
+		refclk_freq |= S3C_PHYCLK_CLKSEL_12M;

Just,

+ refclk_freq = S3C_PHYCLK_CLKSEL_12M;

because its defalut value is 0...BTW, how do you think to support other SoCs such as EXYNOS4210, EXYNOS4X12?

drivers/usb/phy/samsung-usbphy.c line 110

Quoted 3 lines
drivers/usb/phy/samsung-usbphy.c new file +3 -0
+		break;
+	case 24 * MHZ:
+		refclk_freq |= S3C_PHYCLK_CLKSEL_24M;

Ditto.

drivers/usb/phy/samsung-usbphy.c line 115

Quoted 5 lines
drivers/usb/phy/samsung-usbphy.c new file +5 -0
+		break;
+	default:
+	case 48 * MHZ:
+		/* default reference clock */
+		refclk_freq |= S3C_PHYCLK_CLKSEL_48M;

Ditto...and default refernec clock for EXYNOS4 is 24MHz...

drivers/usb/phy/samsung-usbphy.c line 122

Quoted 7 lines
drivers/usb/phy/samsung-usbphy.c new file +7 -0
+		break;
+	}
+	clk_put(ref_clk);
+
+	return refclk_freq;
+}
+

Hmm...I need more time to look at this again...

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#14 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

Hi,

Quoted 113 lines · Kukjin Kim
Quoted 12 lines · Praveen Paneri

platform_set_drvdata() required for driver's remove function, so adding it back.

From v6:
Added TODO for phy bindings with controller
Dropped platform_set_drvdata() from driver probe

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

Quoted 7 lines
---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |   11 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  357

++++++++++++++++++++

drivers/usb/phy/Makefile obj-$(CONFIG_OMAP_USB2) +=

Quoted 47 lines
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 404 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-
usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +10 -0
new file mode 100644
index 0000000..7b26e2d
@@ -0,0 +1,11 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+TODO: Adding the PHY binding with controller(s) according to the under
+developement generic PHY driver.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory

mapped

Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +1 -0
+     region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
      help
        Enable this to support Marvell USB 3.0 phy controller for Marvell
        SoC.
+
+config SAMSUNG_USBPHY
+     bool "Samsung USB PHY controller Driver"
+     depends on USB_S3C_HSOTG
+     select USB_OTG_UTILS
+     help
+       Enable this to support Samsung USB phy controller for samsung
+       SoCs.
drivers/usb/phy/Makefile +0 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)                       +=

omap-usb2.o

drivers/usb/phy/samsung-usbphy.c

Quoted 10 lines
drivers/usb/phy/Makefile +1 -0
 obj-$(CONFIG_USB_ISP1301)            += isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)             += mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)         += samsung-usbphy.o
drivers/usb/phy/samsung- renamed from drivers/usb/phy/samsung-usbphy.c +0 -0

usbphy.c
new file mode 100644
index 0000000..14c182f

drivers/usb/phy/samsung-usbphy.c new file +0 -0

Hi,

Basically I agree and this is a good approach to support usb phy for Samsung stuff...but there are some comments ;)

Quoted 28 lines
drivers/usb/phy/samsung-usbphy.c new file +8 -0
@@ -0,0 +1,357 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG

controller
+ *
+ * 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.
+ *
+ * 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.
+ */

drivers/usb/phy/samsung-usbphy.c new file +8 -0
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
Quoted 8 lines

drivers/usb/phy/samsung-usbphy.c line 33

Quoted 7 lines
drivers/usb/phy/samsung-usbphy.c new file +7 -0
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR                           (0x00)
+

IMHO, according to the file name, samsung-usbphy, SAMSUNG_ is better here?

Sure I will change this for register names and drop S3C_ from bit definitions.

Quoted 10 lines

drivers/usb/phy/samsung-usbphy.c line 39

Quoted 8 lines
drivers/usb/phy/samsung-usbphy.c new file +6 -0
+#define S3C_PHYPWR_NORMAL_MASK                       (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE                       (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN          (1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND             (1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK           (0x39 << 0)

Hmm...is this right? If so, need to use exact name for the definition.

Name should be changed, will do that.

Quoted 5 lines

See arch/arm/mach-exynos/include/mach/regs-usb-phy.h

Quoted 1 line

+#define EXYNOS4_PHYPWR_SLEEP (1 << 5)

Quoted 8 lines

Ditto.

drivers/usb/phy/samsung-usbphy.c line 44

Quoted 4 lines
drivers/usb/phy/samsung-usbphy.c new file +4 -0
+
+#define S3C_PHYCLK                           (0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL                       (1 << 6)

MODE_USB11?

Yes! Will update this as well.

Quoted 6 lines

drivers/usb/phy/samsung-usbphy.c line 46

Quoted 3 lines
drivers/usb/phy/samsung-usbphy.c new file +2 -0
+#define S3C_PHYCLK_EXT_OSC                   (1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N                       (1 << 4)

There are Samsung SoCs which is having two PHYs, so I think, we need to design this with considering it.

Yes! I do plan to add support for other SoCs. We will have to update the register definition accordingly for PHY0 and PHY1.

Quoted 9 lines

drivers/usb/phy/samsung-usbphy.c line 52

Quoted 7 lines
drivers/usb/phy/samsung-usbphy.c new file +6 -0
+#define S3C_PHYCLK_ID_PULL                   (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                       (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                      (0)
+#define S3C_PHYCLK_CLKSEL_48M                        (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                        (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                        (0x3 << 0)

As you know, the values for CLKSEL are different on each Samsung SoCs...if

Yeah those bit definitions have to be added here, just as they are in the file you mentioned.
See arch/arm/mach-exynos/include/mach/regs-usb-phy.h

Quoted 2 lines

we use this patch, we need to implement for other SoCs many things. In addition, this patch says can support EXYNOS4210 but not actually...

I have tested on SMDKV310 and SMDK6410 with s3c-hsotg. So, host phy control support is yet to be added.

Quoted 39 lines
Quoted 28 lines
drivers/usb/phy/samsung-usbphy.c new file +27 -0
+
+#define S3C_RSTCON                           (0x08)
+
+#define S3C_RSTCON_PHYCLK                    (1 << 2)
+#define S3C_RSTCON_HCLK                              (1 << 1)
+#define S3C_RSTCON_PHY                               (1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+     TYPE_S3C64XX,
+     TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {

drivers/usb/phy/samsung-usbphy.c

Quoted 10 lines
drivers/usb/phy/samsung-usbphy.c new file +10 -0
+     struct usb_phy  phy;
+     struct samsung_usbphy_data *plat;
+     struct device   *dev;
+     struct clk      *clk;
+     void __iomem    *regs;
+     int             ref_clk_freq;
+     int             cpu_type;
+};
+
+#define phy_to_sphy(x)               container_of((x), struct

samsung_usbphy,

Quoted 14 lines

drivers/usb/phy/samsung-usbphy.c line 100

Quoted 12 lines

phy)

drivers/usb/phy/samsung-usbphy.c new file +11 -0
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+     struct clk *ref_clk;
+     int refclk_freq = 0;
+
+     ref_clk = clk_get(sphy->dev, "xusbxti");
+     if (IS_ERR(ref_clk)) {

IS_ERR_OR_NULL(ref_clk)?

sure

Quoted 9 lines

drivers/usb/phy/samsung-usbphy.c line 107

Quoted 8 lines
drivers/usb/phy/samsung-usbphy.c new file +7 -0
+             dev_err(sphy->dev, "Failed to get reference clock\n");
+             return PTR_ERR(ref_clk);
+     }
+
+     switch (clk_get_rate(ref_clk)) {
+     case 12 * MHZ:
+             refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
Quoted 6 lines

Just,

+ refclk_freq = S3C_PHYCLK_CLKSEL_12M;

because its defalut value is 0...BTW, how do you think to support other SoCs such as EXYNOS4210, EXYNOS4X12?

Will make use of sphy->cpu_type here. No?

Quoted 7 lines

drivers/usb/phy/samsung-usbphy.c line 110

Quoted 4 lines
drivers/usb/phy/samsung-usbphy.c new file +3 -0
+             break;
+     case 24 * MHZ:
+             refclk_freq |= S3C_PHYCLK_CLKSEL_24M;

Ditto.

Quoted 7 lines

drivers/usb/phy/samsung-usbphy.c line 115

Quoted 5 lines
drivers/usb/phy/samsung-usbphy.c new file +5 -0
+             break;
+     default:
+     case 48 * MHZ:
+             /* default reference clock */
+             refclk_freq |= S3C_PHYCLK_CLKSEL_48M;

Ditto...and default refernec clock for EXYNOS4 is 24MHz...

Okay! So it needs an if statement here then.

Quoted 10 lines

drivers/usb/phy/samsung-usbphy.c line 122

Quoted 8 lines
drivers/usb/phy/samsung-usbphy.c new file +7 -0
+             break;
+     }
+     clk_put(ref_clk);
+
+     return refclk_freq;
+}
+

Hmm...I need more time to look at this again...

Thank you :)
In that case, I will wait for further comments from you and then only send my subsequent patches.

Regards,
Praveen

Quoted 13 lines

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#15 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

In reply to Kukjin Kim
Quoted 9 lines · Kukjin Kim

drivers/usb/phy/samsung-usbphy.c line 100

Quoted 7 lines
drivers/usb/phy/samsung-usbphy.c new file +7 -0
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+	struct clk *ref_clk;
+	int refclk_freq = 0;
+
+	ref_clk = clk_get(sphy->dev, "xusbxti");
+	if (IS_ERR(ref_clk)) {

IS_ERR_OR_NULL(ref_clk)?

For the N'th time, NO. IS_ERR is correct here.

Quoted 2 lines

drivers/usb/phy/samsung-usbphy.c line 102

Quoted 2 lines
drivers/usb/phy/samsung-usbphy.c new file +2 -0
+		dev_err(sphy->dev, "Failed to get reference clock\n");
+		return PTR_ERR(ref_clk);

Look, it's the ABI. Not only that but it's also TOTALLY AND UTTERLY WRONG to use IS_ERR_OR_NULL(foo) and then follow it with return PTR_ERR(foo). You end up returning ZERO.

Stop telling people to use IS_ERR_OR_NULL without properly thinking about it first. Virtually every single one of these done this way is a BUG.

Are we clear on this?

#16 lore raw

PATCH 1/1 usb: phy: samsung: Introducing usb phy driver for hsotg

Quoted 20 lines · Russell King - ARM Linux
Quoted 9 lines · Kukjin Kim

drivers/usb/phy/samsung-usbphy.c line 100

Quoted 7 lines
drivers/usb/phy/samsung-usbphy.c new file +7 -0
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+	struct clk *ref_clk;
+	int refclk_freq = 0;
+
+	ref_clk = clk_get(sphy->dev, "xusbxti");
+	if (IS_ERR(ref_clk)) {

IS_ERR_OR_NULL(ref_clk)?

For the N'th time, NO. IS_ERR is correct here.

Quoted 2 lines

drivers/usb/phy/samsung-usbphy.c line 102

Quoted 2 lines
drivers/usb/phy/samsung-usbphy.c new file +2 -0
+		dev_err(sphy->dev, "Failed to get reference clock\n");
+		return PTR_ERR(ref_clk);

Look, it's the ABI. Not only that but it's also TOTALLY AND UTTERLY WRONG to use IS_ERR_OR_NULL(foo) and then follow it with return PTR_ERR(foo). You end up returning ZERO.

Quoted 4 lines

Stop telling people to use IS_ERR_OR_NULL without properly thinking about it first. Virtually every single one of these done this way is a BUG.

Are we clear on this?

Wouldn't be much easier to define PTR_ERR() to return -Esomething when its argument is NULL?

This would end the whole issue of "should I use IS_ERR*/PTR_ERR or look into the pointer myself?" story. One could simply always use IS_ERR*/PTR_ERR and have the right thing done in whatever case.

Regards,
Domenico

#17 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

In reply to Praveen Paneri
Quoted 476 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360
++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644
Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +8 -0
new file mode 100644
index 0000000..fefd9c8
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory

mapped

Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +1 -0
+	region.
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
 	help
 	  Enable this to support Marvell USB 3.0 phy controller for Marvell
 	  SoC.
+
+config SAMSUNG_USBPHY
+	bool "Samsung USB PHY controller Driver"
+	depends on USB_S3C_HSOTG
+	select USB_OTG_UTILS
+	help
+	  Enable this to support Samsung USB phy controller for samsung
+	  SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)			+= omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +8 -0
new file mode 100644
index 0000000..95ec4d0
@@ -0,0 +1,360 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG

controller
+ *
+ * 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.
+ *
+ * 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.
+ */

drivers/usb/phy/samsung-usbphy.c new file +216 -0
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR				(0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK			(0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE			(1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN		(1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND		(1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK		(0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP			(1 << 5)
+
+#define S3C_PHYCLK				(0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL			(1 << 6)
+#define S3C_PHYCLK_EXT_OSC			(1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N			(1 << 4)
+#define S3C_PHYCLK_ID_PULL			(1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK			(0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT			(0)
+#define S3C_PHYCLK_CLKSEL_48M			(0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M			(0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M			(0x3 << 0)
+
+#define S3C_RSTCON				(0x08)
+
+#define S3C_RSTCON_PHYCLK			(1 << 2)
+#define S3C_RSTCON_HCLK				(1 << 1)
+#define S3C_RSTCON_PHY				(1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+	TYPE_S3C64XX,
+	TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+	struct usb_phy	phy;
+	struct samsung_usbphy_data *plat;
+	struct device	*dev;
+	struct clk	*clk;
+	void __iomem	*regs;
+	int		ref_clk_freq;
+	int		cpu_type;
+};
+
+#define phy_to_sphy(x)		container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+	struct clk *ref_clk;
+	int refclk_freq = 0;
+
+	ref_clk = clk_get(sphy->dev, "xusbxti");
+	if (IS_ERR(ref_clk)) {
+		dev_err(sphy->dev, "Failed to get reference clock\n");
+		return PTR_ERR(ref_clk);
+	}
+
+	switch (clk_get_rate(ref_clk)) {
+	case 12 * MHZ:
+		refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+		break;
+	case 24 * MHZ:
+		refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+		break;
+	default:
+	case 48 * MHZ:
+		/* default reference clock */
+		refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+		break;
+	}
+	clk_put(ref_clk);
+
+	return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+	void __iomem *regs = sphy->regs;
+	u32 phypwr;
+	u32 phyclk;
+	u32 rstcon;
+
+	/* set clock frequency for PLL */
+	phyclk = sphy->ref_clk_freq;
+	phypwr = readl(regs + S3C_PHYPWR);
+	rstcon = readl(regs + S3C_RSTCON);
+
+	switch (sphy->cpu_type) {
+	case TYPE_S3C64XX:
+		phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+		phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+		rstcon |= S3C_RSTCON_PHY;
+		break;
+	case TYPE_EXYNOS4210:
+		phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+		rstcon |= S3C_RSTCON_PHY;
+	default:
+		break;
+	}
+
+	writel(phyclk, regs + S3C_PHYCLK);
+	/* set to normal of PHY0 */
+	writel(phypwr, regs + S3C_PHYPWR);
+	/* reset all ports of PHY and Link */
+	writel(rstcon, regs + S3C_RSTCON);
+	udelay(10);
+	rstcon &= ~S3C_RSTCON_PHY;
+	writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+	void __iomem *regs = sphy->regs;
+	u32 phypwr;
+
+	phypwr = readl(regs + S3C_PHYPWR);
+
+	switch (sphy->cpu_type) {
+	case TYPE_S3C64XX:
+		phypwr |= S3C_PHYPWR_NORMAL_MASK;
+		break;
+	case TYPE_EXYNOS4210:
+		phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+	default:
+		break;
+	}
+
+	/* unset to normal of PHY0 */
+	writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+	struct samsung_usbphy *sphy;
+	int ret = 0;
+
+	sphy = phy_to_sphy(phy);
+
+	/* Enable the phy clock */
+	ret = clk_prepare_enable(sphy->clk);
+	if (ret) {
+		dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+		return ret;
+	}
+
+	/* Disable phy isolation */
+	if (sphy->plat && sphy->plat->pmu_isolation)
+		sphy->plat->pmu_isolation(false);
+
+	/* Initialize usb phy registers */
+	samsung_usbphy_enable(sphy);
+
+	/* Disable the phy clock */
+	clk_disable_unprepare(sphy->clk);
+	return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+	struct samsung_usbphy *sphy;
+
+	sphy = phy_to_sphy(phy);
+
+	if (clk_prepare_enable(sphy->clk)) {
+		dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+		return;
+	}
+
+	/* De-initialize usb phy registers */
+	samsung_usbphy_disable(sphy);
+
+	/* Enable phy isolation */
+	if (sphy->plat && sphy->plat->pmu_isolation)
+		sphy->plat->pmu_isolation(true);
+
+	clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device

*pdev)

drivers/usb/phy/samsung-usbphy.c new file +126 -0
+{
+	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+		int data;
+		const struct of_device_id *match;
+		match = of_match_node(samsung_usbphy_dt_match,
+							pdev->dev.of_node);
+		data = (int) match->data;
+		return data;
+	}
+
+	return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+	struct samsung_usbphy *sphy;
+	struct samsung_usbphy_data *pdata;
+	struct device *dev = &pdev->dev;
+	struct resource *phy_mem;
+	void __iomem	*phy_base;
+	struct clk *clk;
+	int	ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+		return -EINVAL;
+	}
+
+	phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!phy_mem) {
+		dev_err(dev, "%s: missing mem resource\n", __func__);
+		return -ENODEV;
+	}
+
+	phy_base = devm_request_and_ioremap(dev, phy_mem);
+	if (!phy_base) {
+		dev_err(dev, "%s: register mapping failed\n", __func__);
+		return -ENXIO;
+	}
+
+	sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+	if (!sphy)
+		return -ENOMEM;
+
+	clk = devm_clk_get(dev, "otg");
+	if (IS_ERR(clk)) {
+		dev_err(dev, "Failed to get otg clock\n");
+		return PTR_ERR(clk);
+	}
+
+	sphy->dev		= &pdev->dev;
+	sphy->plat		= pdata;
+	sphy->regs		= phy_base;
+	sphy->clk		= clk;
+	sphy->phy.dev		= sphy->dev;
+	sphy->phy.label		= "samsung-usbphy";
+	sphy->phy.init		= samsung_usbphy_init;
+	sphy->phy.shutdown	= samsung_usbphy_shutdown;
+	sphy->cpu_type		= samsung_usbphy_get_driver_data(pdev);
+	sphy->ref_clk_freq	= samsung_usbphy_get_refclk_freq(sphy);
+
+	ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+	if (ret)
+		goto err;
+
+	platform_set_drvdata(pdev, sphy);
+err:
+	return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+	struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+	usb_remove_phy(&sphy->phy);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+	{
+		.compatible = "samsung,s3c64xx-usbphy",
+		.data = (void *)TYPE_S3C64XX,
+	}, {
+		.compatible = "samsung,exynos4210-usbphy",
+		.data = (void *)TYPE_EXYNOS4210,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+	{
+		.name		= "s3c64xx-usbphy",
+		.driver_data	= TYPE_S3C64XX,
+	}, {
+		.name		= "exynos4210-usbphy",
+		.driver_data	= TYPE_EXYNOS4210,
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+	.probe		= samsung_usbphy_probe,
+	.remove		= __devexit_p(samsung_usbphy_remove),
+	.id_table	= samsung_usbphy_driver_ids,
+	.driver		= {
+		.name	= "samsung-usbphy",
+		.owner	= THIS_MODULE,
+		.of_match_table = samsung_usbphy_dt_match,
+	},
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +8 -0
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *		http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify

it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */

include/linux/platform_data/samsung-usbphy.h new file +15 -1
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+	void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
--

1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#18 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

In reply to Praveen Paneri
Quoted 23 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +0 -0
new file mode 100644
index 0000000..fefd9c8

Documentation/devicetree/bindings/usb/samsung-usbphy.txt line 9

Quoted 9 lines
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +9 -0
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+	region.

What's missing here is describing the connection of phys to host controllers. We've got several people adding usb phy bindings and need to define them in a common way.

Rob

Quoted 425 lines
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
 	help
 	  Enable this to support Marvell USB 3.0 phy controller for Marvell
 	  SoC.
+
+config SAMSUNG_USBPHY
+	bool "Samsung USB PHY controller Driver"
+	depends on USB_S3C_HSOTG
+	select USB_OTG_UTILS
+	help
+	  Enable this to support Samsung USB phy controller for samsung
+	  SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)			+= omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +360 -0
new file mode 100644
index 0000000..95ec4d0
@@ -0,0 +1,360 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR				(0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK			(0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE			(1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN		(1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND		(1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK		(0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP			(1 << 5)
+
+#define S3C_PHYCLK				(0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL			(1 << 6)
+#define S3C_PHYCLK_EXT_OSC			(1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N			(1 << 4)
+#define S3C_PHYCLK_ID_PULL			(1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK			(0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT			(0)
+#define S3C_PHYCLK_CLKSEL_48M			(0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M			(0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M			(0x3 << 0)
+
+#define S3C_RSTCON				(0x08)
+
+#define S3C_RSTCON_PHYCLK			(1 << 2)
+#define S3C_RSTCON_HCLK				(1 << 1)
+#define S3C_RSTCON_PHY				(1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+	TYPE_S3C64XX,
+	TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+	struct usb_phy	phy;
+	struct samsung_usbphy_data *plat;
+	struct device	*dev;
+	struct clk	*clk;
+	void __iomem	*regs;
+	int		ref_clk_freq;
+	int		cpu_type;
+};
+
+#define phy_to_sphy(x)		container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+	struct clk *ref_clk;
+	int refclk_freq = 0;
+
+	ref_clk = clk_get(sphy->dev, "xusbxti");
+	if (IS_ERR(ref_clk)) {
+		dev_err(sphy->dev, "Failed to get reference clock\n");
+		return PTR_ERR(ref_clk);
+	}
+
+	switch (clk_get_rate(ref_clk)) {
+	case 12 * MHZ:
+		refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+		break;
+	case 24 * MHZ:
+		refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+		break;
+	default:
+	case 48 * MHZ:
+		/* default reference clock */
+		refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+		break;
+	}
+	clk_put(ref_clk);
+
+	return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+	void __iomem *regs = sphy->regs;
+	u32 phypwr;
+	u32 phyclk;
+	u32 rstcon;
+
+	/* set clock frequency for PLL */
+	phyclk = sphy->ref_clk_freq;
+	phypwr = readl(regs + S3C_PHYPWR);
+	rstcon = readl(regs + S3C_RSTCON);
+
+	switch (sphy->cpu_type) {
+	case TYPE_S3C64XX:
+		phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+		phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+		rstcon |= S3C_RSTCON_PHY;
+		break;
+	case TYPE_EXYNOS4210:
+		phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+		rstcon |= S3C_RSTCON_PHY;
+	default:
+		break;
+	}
+
+	writel(phyclk, regs + S3C_PHYCLK);
+	/* set to normal of PHY0 */
+	writel(phypwr, regs + S3C_PHYPWR);
+	/* reset all ports of PHY and Link */
+	writel(rstcon, regs + S3C_RSTCON);
+	udelay(10);
+	rstcon &= ~S3C_RSTCON_PHY;
+	writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+	void __iomem *regs = sphy->regs;
+	u32 phypwr;
+
+	phypwr = readl(regs + S3C_PHYPWR);
+
+	switch (sphy->cpu_type) {
+	case TYPE_S3C64XX:
+		phypwr |= S3C_PHYPWR_NORMAL_MASK;
+		break;
+	case TYPE_EXYNOS4210:
+		phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+	default:
+		break;
+	}
+
+	/* unset to normal of PHY0 */
+	writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+	struct samsung_usbphy *sphy;
+	int ret = 0;
+
+	sphy = phy_to_sphy(phy);
+
+	/* Enable the phy clock */
+	ret = clk_prepare_enable(sphy->clk);
+	if (ret) {
+		dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+		return ret;
+	}
+
+	/* Disable phy isolation */
+	if (sphy->plat && sphy->plat->pmu_isolation)
+		sphy->plat->pmu_isolation(false);
+
+	/* Initialize usb phy registers */
+	samsung_usbphy_enable(sphy);
+
+	/* Disable the phy clock */
+	clk_disable_unprepare(sphy->clk);
+	return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+	struct samsung_usbphy *sphy;
+
+	sphy = phy_to_sphy(phy);
+
+	if (clk_prepare_enable(sphy->clk)) {
+		dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+		return;
+	}
+
+	/* De-initialize usb phy registers */
+	samsung_usbphy_disable(sphy);
+
+	/* Enable phy isolation */
+	if (sphy->plat && sphy->plat->pmu_isolation)
+		sphy->plat->pmu_isolation(true);
+
+	clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+		int data;
+		const struct of_device_id *match;
+		match = of_match_node(samsung_usbphy_dt_match,
+							pdev->dev.of_node);
+		data = (int) match->data;
+		return data;
+	}
+
+	return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+	struct samsung_usbphy *sphy;
+	struct samsung_usbphy_data *pdata;
+	struct device *dev = &pdev->dev;
+	struct resource *phy_mem;
+	void __iomem	*phy_base;
+	struct clk *clk;
+	int	ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+		return -EINVAL;
+	}
+
+	phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!phy_mem) {
+		dev_err(dev, "%s: missing mem resource\n", __func__);
+		return -ENODEV;
+	}
+
+	phy_base = devm_request_and_ioremap(dev, phy_mem);
+	if (!phy_base) {
+		dev_err(dev, "%s: register mapping failed\n", __func__);
+		return -ENXIO;
+	}
+
+	sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+	if (!sphy)
+		return -ENOMEM;
+
+	clk = devm_clk_get(dev, "otg");
+	if (IS_ERR(clk)) {
+		dev_err(dev, "Failed to get otg clock\n");
+		return PTR_ERR(clk);
+	}
+
+	sphy->dev		= &pdev->dev;
+	sphy->plat		= pdata;
+	sphy->regs		= phy_base;
+	sphy->clk		= clk;
+	sphy->phy.dev		= sphy->dev;
+	sphy->phy.label		= "samsung-usbphy";
+	sphy->phy.init		= samsung_usbphy_init;
+	sphy->phy.shutdown	= samsung_usbphy_shutdown;
+	sphy->cpu_type		= samsung_usbphy_get_driver_data(pdev);
+	sphy->ref_clk_freq	= samsung_usbphy_get_refclk_freq(sphy);
+
+	ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+	if (ret)
+		goto err;
+
+	platform_set_drvdata(pdev, sphy);
+err:
+	return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+	struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+	usb_remove_phy(&sphy->phy);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+	{
+		.compatible = "samsung,s3c64xx-usbphy",
+		.data = (void *)TYPE_S3C64XX,
+	}, {
+		.compatible = "samsung,exynos4210-usbphy",
+		.data = (void *)TYPE_EXYNOS4210,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+	{
+		.name		= "s3c64xx-usbphy",
+		.driver_data	= TYPE_S3C64XX,
+	}, {
+		.name		= "exynos4210-usbphy",
+		.driver_data	= TYPE_EXYNOS4210,
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+	.probe		= samsung_usbphy_probe,
+	.remove		= __devexit_p(samsung_usbphy_remove),
+	.id_table	= samsung_usbphy_driver_ids,
+	.driver		= {
+		.name	= "samsung-usbphy",
+		.owner	= THIS_MODULE,
+		.of_match_table = samsung_usbphy_dt_match,
+	},
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +27 -0
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *		http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+	void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */
#19 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

Hi Rob,

Quoted 29 lines · Rob Herring
Quoted 28 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +5 -0
new file mode 100644
index 0000000..fefd9c8
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
Quoted 8 lines

Documentation/devicetree/bindings/usb/samsung-usbphy.txt line 9

Quoted 4 lines
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +4 -0
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+     region.

What's missing here is describing the connection of phys to host controllers. We've got several people adding usb phy bindings and need to define them in a common way.

yes! it just covers the generic binding. I will update it accordingly as the generic phy framework takes its final shape.

Praveen

Quoted 433 lines

Rob

Quoted 415 lines
drivers/usb/phy/Kconfig +8 -0
index 63c339b..313685f 100644
@@ -32,3 +32,11 @@ config MV_U3D_PHY
      help
        Enable this to support Marvell USB 3.0 phy controller for Marvell
        SoC.
+
+config SAMSUNG_USBPHY
+     bool "Samsung USB PHY controller Driver"
+     depends on USB_S3C_HSOTG
+     select USB_OTG_UTILS
+     help
+       Enable this to support Samsung USB phy controller for samsung
+       SoCs.
drivers/usb/phy/Makefile +1 -0
index b069f29..55dcfc1 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_OMAP_USB2)                       += omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)            += isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)             += mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
+obj-$(CONFIG_SAMSUNG_USBPHY)         += samsung-usbphy.o
drivers/usb/phy/samsung-usbphy.c new file +360 -0
new file mode 100644
index 0000000..95ec4d0
@@ -0,0 +1,360 @@
+/* linux/drivers/usb/phy/samsung-usbphy.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Samsung USB2.0 High-speed OTG transceiver, talks to S3C HS OTG controller
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+/* Register definitions */
+
+#define S3C_PHYPWR                           (0x00)
+
+#define S3C_PHYPWR_NORMAL_MASK                       (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE                       (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN          (1 << 3)
+#define S3C_PHYPWR_FORCE_SUSPEND             (1 << 1)
+/* For Exynos4 */
+#define EXYNOS4_PHYPWR_NORMAL_MASK           (0x39 << 0)
+#define EXYNOS4_PHYPWR_SLEEP                 (1 << 5)
+
+#define S3C_PHYCLK                           (0x04)
+
+#define S3C_PHYCLK_MODE_SERIAL                       (1 << 6)
+#define S3C_PHYCLK_EXT_OSC                   (1 << 5)
+#define S3C_PHYCLK_COMMON_ON_N                       (1 << 4)
+#define S3C_PHYCLK_ID_PULL                   (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                       (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                      (0)
+#define S3C_PHYCLK_CLKSEL_48M                        (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                        (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                        (0x3 << 0)
+
+#define S3C_RSTCON                           (0x08)
+
+#define S3C_RSTCON_PHYCLK                    (1 << 2)
+#define S3C_RSTCON_HCLK                              (1 << 1)
+#define S3C_RSTCON_PHY                               (1 << 0)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+enum samsung_cpu_type {
+     TYPE_S3C64XX,
+     TYPE_EXYNOS4210,
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @cpu_type: machine identifier
+ */
+struct samsung_usbphy {
+     struct usb_phy  phy;
+     struct samsung_usbphy_data *plat;
+     struct device   *dev;
+     struct clk      *clk;
+     void __iomem    *regs;
+     int             ref_clk_freq;
+     int             cpu_type;
+};
+
+#define phy_to_sphy(x)               container_of((x), struct samsung_usbphy, phy)
+
+/*
+ * Returns reference clock frequency selection value
+ */
+static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+     struct clk *ref_clk;
+     int refclk_freq = 0;
+
+     ref_clk = clk_get(sphy->dev, "xusbxti");
+     if (IS_ERR(ref_clk)) {
+             dev_err(sphy->dev, "Failed to get reference clock\n");
+             return PTR_ERR(ref_clk);
+     }
+
+     switch (clk_get_rate(ref_clk)) {
+     case 12 * MHZ:
+             refclk_freq |= S3C_PHYCLK_CLKSEL_12M;
+             break;
+     case 24 * MHZ:
+             refclk_freq |= S3C_PHYCLK_CLKSEL_24M;
+             break;
+     default:
+     case 48 * MHZ:
+             /* default reference clock */
+             refclk_freq |= S3C_PHYCLK_CLKSEL_48M;
+             break;
+     }
+     clk_put(ref_clk);
+
+     return refclk_freq;
+}
+
+static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
+{
+     void __iomem *regs = sphy->regs;
+     u32 phypwr;
+     u32 phyclk;
+     u32 rstcon;
+
+     /* set clock frequency for PLL */
+     phyclk = sphy->ref_clk_freq;
+     phypwr = readl(regs + S3C_PHYPWR);
+     rstcon = readl(regs + S3C_RSTCON);
+
+     switch (sphy->cpu_type) {
+     case TYPE_S3C64XX:
+             phyclk &= ~(S3C_PHYCLK_COMMON_ON_N);
+             phypwr &= ~S3C_PHYPWR_NORMAL_MASK;
+             rstcon |= S3C_RSTCON_PHY;
+             break;
+     case TYPE_EXYNOS4210:
+             phypwr &= ~EXYNOS4_PHYPWR_NORMAL_MASK;
+             rstcon |= S3C_RSTCON_PHY;
+     default:
+             break;
+     }
+
+     writel(phyclk, regs + S3C_PHYCLK);
+     /* set to normal of PHY0 */
+     writel(phypwr, regs + S3C_PHYPWR);
+     /* reset all ports of PHY and Link */
+     writel(rstcon, regs + S3C_RSTCON);
+     udelay(10);
+     rstcon &= ~S3C_RSTCON_PHY;
+     writel(rstcon, regs + S3C_RSTCON);
+}
+
+static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
+{
+     void __iomem *regs = sphy->regs;
+     u32 phypwr;
+
+     phypwr = readl(regs + S3C_PHYPWR);
+
+     switch (sphy->cpu_type) {
+     case TYPE_S3C64XX:
+             phypwr |= S3C_PHYPWR_NORMAL_MASK;
+             break;
+     case TYPE_EXYNOS4210:
+             phypwr |= EXYNOS4_PHYPWR_NORMAL_MASK;
+     default:
+             break;
+     }
+
+     /* unset to normal of PHY0 */
+     writel(phypwr, regs + S3C_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usbphy_init(struct usb_phy *phy)
+{
+     struct samsung_usbphy *sphy;
+     int ret = 0;
+
+     sphy = phy_to_sphy(phy);
+
+     /* Enable the phy clock */
+     ret = clk_prepare_enable(sphy->clk);
+     if (ret) {
+             dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+             return ret;
+     }
+
+     /* Disable phy isolation */
+     if (sphy->plat && sphy->plat->pmu_isolation)
+             sphy->plat->pmu_isolation(false);
+
+     /* Initialize usb phy registers */
+     samsung_usbphy_enable(sphy);
+
+     /* Disable the phy clock */
+     clk_disable_unprepare(sphy->clk);
+     return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usbphy_shutdown(struct usb_phy *phy)
+{
+     struct samsung_usbphy *sphy;
+
+     sphy = phy_to_sphy(phy);
+
+     if (clk_prepare_enable(sphy->clk)) {
+             dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+             return;
+     }
+
+     /* De-initialize usb phy registers */
+     samsung_usbphy_disable(sphy);
+
+     /* Enable phy isolation */
+     if (sphy->plat && sphy->plat->pmu_isolation)
+             sphy->plat->pmu_isolation(true);
+
+     clk_disable_unprepare(sphy->clk);
+}
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline int samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+     if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+             int data;
+             const struct of_device_id *match;
+             match = of_match_node(samsung_usbphy_dt_match,
+                                                     pdev->dev.of_node);
+             data = (int) match->data;
+             return data;
+     }
+
+     return platform_get_device_id(pdev)->driver_data;
+}
+
+static int __devinit samsung_usbphy_probe(struct platform_device *pdev)
+{
+     struct samsung_usbphy *sphy;
+     struct samsung_usbphy_data *pdata;
+     struct device *dev = &pdev->dev;
+     struct resource *phy_mem;
+     void __iomem    *phy_base;
+     struct clk *clk;
+     int     ret;
+
+     pdata = pdev->dev.platform_data;
+     if (!pdata) {
+             dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+             return -EINVAL;
+     }
+
+     phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+     if (!phy_mem) {
+             dev_err(dev, "%s: missing mem resource\n", __func__);
+             return -ENODEV;
+     }
+
+     phy_base = devm_request_and_ioremap(dev, phy_mem);
+     if (!phy_base) {
+             dev_err(dev, "%s: register mapping failed\n", __func__);
+             return -ENXIO;
+     }
+
+     sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+     if (!sphy)
+             return -ENOMEM;
+
+     clk = devm_clk_get(dev, "otg");
+     if (IS_ERR(clk)) {
+             dev_err(dev, "Failed to get otg clock\n");
+             return PTR_ERR(clk);
+     }
+
+     sphy->dev               = &pdev->dev;
+     sphy->plat              = pdata;
+     sphy->regs              = phy_base;
+     sphy->clk               = clk;
+     sphy->phy.dev           = sphy->dev;
+     sphy->phy.label         = "samsung-usbphy";
+     sphy->phy.init          = samsung_usbphy_init;
+     sphy->phy.shutdown      = samsung_usbphy_shutdown;
+     sphy->cpu_type          = samsung_usbphy_get_driver_data(pdev);
+     sphy->ref_clk_freq      = samsung_usbphy_get_refclk_freq(sphy);
+
+     ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+     if (ret)
+             goto err;
+
+     platform_set_drvdata(pdev, sphy);
+err:
+     return ret;
+}
+
+static int __exit samsung_usbphy_remove(struct platform_device *pdev)
+{
+     struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+     usb_remove_phy(&sphy->phy);
+
+     return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+     {
+             .compatible = "samsung,s3c64xx-usbphy",
+             .data = (void *)TYPE_S3C64XX,
+     }, {
+             .compatible = "samsung,exynos4210-usbphy",
+             .data = (void *)TYPE_EXYNOS4210,
+     },
+     {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#else
+#define samsung_usbphy_dt_match NULL
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+     {
+             .name           = "s3c64xx-usbphy",
+             .driver_data    = TYPE_S3C64XX,
+     }, {
+             .name           = "exynos4210-usbphy",
+             .driver_data    = TYPE_EXYNOS4210,
+     },
+     {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usbphy_driver = {
+     .probe          = samsung_usbphy_probe,
+     .remove         = __devexit_p(samsung_usbphy_remove),
+     .id_table       = samsung_usbphy_driver_ids,
+     .driver         = {
+             .name   = "samsung-usbphy",
+             .owner  = THIS_MODULE,
+             .of_match_table = samsung_usbphy_dt_match,
+     },
+};
+
+module_platform_driver(samsung_usbphy_driver);
+
+MODULE_DESCRIPTION("Samsung USB phy controller");
+MODULE_AUTHOR("Praveen Paneri <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usbphy");
include/linux/platform_data/samsung-usbphy.h new file +17 -0
new file mode 100644
index 0000000..1bd24cb
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *           http://www.samsung.com/
+ * Author: Praveen Paneri <[email protected]>
+ *
+ * Defines platform data for samsung usb phy driver.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SAMSUNG_USBPHY_PLATFORM_H
+#define __SAMSUNG_USBPHY_PLATFORM_H
+
+/**

include/linux/platform_data/samsung-usbphy.h line 27

Quoted 10 lines
include/linux/platform_data/samsung-usbphy.h new file +10 -0
+ * samsung_usbphy_data - Platform data for USB PHY driver.
+ * @pmu_isolation: Function to control usb phy isolation in PMU.
+ */
+struct samsung_usbphy_data {
+     void (*pmu_isolation)(int on);
+};
+
+extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd);
+
+#endif /* __SAMSUNG_USBPHY_PLATFORM_H */

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#20 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

Quoted 40 lines · Praveen Paneri

Hi Rob,

Quoted 29 lines · Rob Herring
Quoted 28 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +5 -0
new file mode 100644
index 0000000..fefd9c8
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
Quoted 8 lines

Documentation/devicetree/bindings/usb/samsung-usbphy.txt line 9

Quoted 4 lines
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +4 -0
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+     region.

What's missing here is describing the connection of phys to host controllers. We've got several people adding usb phy bindings and need to define them in a common way.

Quoted 2 lines

yes! it just covers the generic binding. I will update it accordingly as the generic phy framework takes its final shape.

That sounds like the wrong way to define a binding... Figuring out how to describe the h/w should not be dependent on changes in the kernel. Bindings are an ABI and should not be evolving.

Rob

#21 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

Hi,

Quoted 41 lines · Rob Herring
Quoted 40 lines · Praveen Paneri

Hi Rob,

Quoted 37 lines · Rob Herring
Quoted 23 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +0 -0
new file mode 100644
index 0000000..fefd9c8

Documentation/devicetree/bindings/usb/samsung-usbphy.txt line 9

Quoted 9 lines
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +9 -0
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+     region.

What's missing here is describing the connection of phys to host controllers. We've got several people adding usb phy bindings and need to define them in a common way.

Quoted 6 lines
Quoted 2 lines

yes! it just covers the generic binding. I will update it accordingly as the generic phy framework takes its final shape.

That sounds like the wrong way to define a binding... Figuring out how to describe the h/w should not be dependent on changes in the kernel. Bindings are an ABI and should not be evolving.

There can be multiple ways to define the binding. For e.g. We discussed few ways of binding the phys to the controller

controller {
              phy0 = <&phandle1_name>;
              phy1 = <&phandle2_name>;
}

phy0 and phy1 are any name given to obtain a reference to the phy and the controller should send the phandle name like get_phy_by_phandle("phy0");. Then we thought of standardizing that name.

and then finally we settled on something like this

controller {
              phy = <&phandle0_name>, <&phandle1_name>;
}

so that controller can obtain a reference to the PHY using *of_phy_get(struct device *dev, const char *phandle, u8 index)*

Thanks
Kishon

#22 lore raw

PATCH v6 1/5 usb: phy: samsung: Introducing usb phy driver for hsotg

Hi,

Quoted 50 lines · KISHON VIJAY

Hi,

Quoted 47 lines · Rob Herring
Quoted 40 lines · Praveen Paneri

Hi Rob,

Quoted 29 lines · Rob Herring
Quoted 28 lines · Praveen Paneri

This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable phy. Tested with smdk6410 and smdkv310. More SoCs can be brought under later.

---
 .../devicetree/bindings/usb/samsung-usbphy.txt     |    9 +
 drivers/usb/phy/Kconfig                            |    8 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/samsung-usbphy.c                   |  360 ++++++++++++++++++++
 include/linux/platform_data/samsung-usbphy.h       |   27 ++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/usb/samsung-usbphy.txt
 create mode 100644 drivers/usb/phy/samsung-usbphy.c
 create mode 100644 include/linux/platform_data/samsung-usbphy.h
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +5 -0
new file mode 100644
index 0000000..fefd9c8
@@ -0,0 +1,9 @@
+* Samsung's usb phy transceiver
+
+The Samsung's phy transceiver is used for controlling usb otg phy for
+s3c-hsotg usb device controller.
+
Quoted 8 lines

Documentation/devicetree/bindings/usb/samsung-usbphy.txt line 9

Quoted 4 lines
Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file +4 -0
+Required properties:
+- compatible : should be "samsung,exynos4210-usbphy"
+- reg : base physical address of the phy registers and length of memory mapped
+     region.

What's missing here is describing the connection of phys to host controllers. We've got several people adding usb phy bindings and need to define them in a common way.

Quoted 2 lines

yes! it just covers the generic binding. I will update it accordingly as the generic phy framework takes its final shape.

That sounds like the wrong way to define a binding... Figuring out how to describe the h/w should not be dependent on changes in the kernel. Bindings are an ABI and should not be evolving.

But since Kishon is getting the generic bindings ready, I can use them when those are ready. So do we need to hold the merge of this patch until then?

Thanks,
Praveen

Quoted 27 lines

There can be multiple ways to define the binding. For e.g. We discussed few ways of binding the phys to the controller

controller {
              phy0 = <&phandle1_name>;
              phy1 = <&phandle2_name>;
}

phy0 and phy1 are any name given to obtain a reference to the phy and the controller should send the phandle name like get_phy_by_phandle("phy0");. Then we thought of standardizing that name.

and then finally we settled on something like this

controller {
              phy = <&phandle0_name>, <&phandle1_name>;
}

so that controller can obtain a reference to the PHY using *of_phy_get(struct device *dev, const char *phandle, u8 index)*

Thanks
Kishon
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#23 lore raw

PATCH v6 2/5 usb: s3c-hsotg: Adding phy driver support

In reply to Praveen Paneri

Adding the transceiver to hsotg driver. Keeping the platform data for continuing the smooth operation for boards which still uses it

---
 drivers/usb/gadget/s3c-hsotg.c |   37 +++++++++++++++++++++++++++----------
 1 files changed, 27 insertions(+), 10 deletions(-)
drivers/usb/gadget/s3c-hsotg.c +27 -10
index 6f696ee..29815b9 100644
@@ -32,6 +32,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 #include <linux/platform_data/s3c-hsotg.h>
 
 #include <mach/map.h>
@@ -133,7 +134,9 @@ struct s3c_hsotg_ep {
  * struct s3c_hsotg - driver state.
  * @dev: The parent device supplied to the probe function
  * @driver: USB gadget driver
- * @plat: The platform specific configuration data.
+ * @phy: The otg phy transceiver structure for phy control.
+ * @plat: The platform specific configuration data. This can be removed once
+ * all SoCs support usb transceiver.
  * @regs: The memory area mapped for accessing registers.
  * @irq: The IRQ number we are using
  * @supplies: Definition of USB power supplies
@@ -153,6 +156,7 @@ struct s3c_hsotg_ep {
 struct s3c_hsotg {
 	struct device		 *dev;
 	struct usb_gadget_driver *driver;
+	struct usb_phy		*phy;
 	struct s3c_hsotg_plat	 *plat;
 
 	spinlock_t              lock;
@@ -2854,7 +2858,10 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
 	struct platform_device *pdev = to_platform_device(hsotg->dev);
 
 	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
-	if (hsotg->plat->phy_init)
+
+	if (hsotg->phy)
+		usb_phy_init(hsotg->phy);
+	else if (hsotg->plat->phy_init)
 		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
 }
 
@@ -2869,7 +2876,9 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
 {
 	struct platform_device *pdev = to_platform_device(hsotg->dev);
 
-	if (hsotg->plat->phy_exit)
+	if (hsotg->phy)
+		usb_phy_shutdown(hsotg->phy);
+	else if (hsotg->plat->phy_exit)
 		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
 }
 
@@ -3493,6 +3502,7 @@ static void s3c_hsotg_release(struct device *dev)
 static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 {
 	struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
+	struct usb_phy *phy;
 	struct device *dev = &pdev->dev;
 	struct s3c_hsotg_ep *eps;
 	struct s3c_hsotg *hsotg;
@@ -3501,20 +3511,27 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 	int ret;
 	int i;
 
-	plat = pdev->dev.platform_data;
-	if (!plat) {
-		dev_err(&pdev->dev, "no platform data defined\n");
-		return -EINVAL;
-	}
-
 	hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL);
 	if (!hsotg) {
 		dev_err(dev, "cannot get memory\n");
 		return -ENOMEM;
 	}
 
+	plat = pdev->dev.platform_data;
+	if (!plat) {
+		/* Fallback for transceiver */
+		phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+		if (IS_ERR_OR_NULL(phy)) {
+			dev_err(&pdev->dev, "no platform data or transceiver defined\n");
+			return -EPROBE_DEFER;
+		} else {
+			hsotg->phy = phy;
+		}
+	} else {
+		hsotg->plat = plat;
+	}
+
 	hsotg->dev = dev;
-	hsotg->plat = plat;
 
 	hsotg->clk = devm_clk_get(&pdev->dev, "otg");
 	if (IS_ERR(hsotg->clk)) {
Signature · 1 line
1.7.1
#24 lore raw

PATCH v6 3/5 ARM: S3C64XX: Removing old phy setup code

In reply to Praveen Paneri

This patch removes old phy code from platform side. 'setup-usb-phy.c' will be used for providing transceiver platform data in next patch. Not all of the platform data code is removed as there are others making use of platform_data defined for hsotg. That can be removed once all the SoCs start using the new transceiver for usb phy setup.

---
 arch/arm/mach-s3c64xx/mach-crag6410.c |    3 -
 arch/arm/mach-s3c64xx/mach-smartq.c   |    3 -
 arch/arm/mach-s3c64xx/mach-smdk6410.c |    3 -
 arch/arm/mach-s3c64xx/setup-usb-phy.c |   79 ---------------------------------
 4 files changed, 0 insertions(+), 88 deletions(-)
arch/arm/mach-s3c64xx/mach-crag6410.c +0 -3
index 09cd812..b0f5baf 100644
@@ -31,7 +31,6 @@
 #include <linux/spi/spi.h>
 
 #include <linux/i2c/pca953x.h>
-#include <linux/platform_data/s3c-hsotg.h>
 
 #include <video/platform_lcd.h>
 
@@ -766,7 +765,6 @@ static const struct gpio_led_platform_data gpio_leds_pdata = {
 	.num_leds = ARRAY_SIZE(gpio_leds),
 };
 
-static struct s3c_hsotg_plat crag6410_hsotg_pdata;
 
 static void __init crag6410_machine_init(void)
 {
@@ -792,7 +790,6 @@ static void __init crag6410_machine_init(void)
 	s3c_i2c0_set_platdata(&i2c0_pdata);
 	s3c_i2c1_set_platdata(&i2c1_pdata);
 	s3c_fb_set_platdata(&crag6410_lcd_pdata);
-	s3c_hsotg_set_platdata(&crag6410_hsotg_pdata);
 
 	i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
 	i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
arch/arm/mach-s3c64xx/mach-smartq.c +0 -3
index ceeb1de..7400da1 100644
@@ -18,7 +18,6 @@
 #include <linux/serial_core.h>
 #include <linux/spi/spi_gpio.h>
 #include <linux/usb/gpio_vbus.h>
-#include <linux/platform_data/s3c-hsotg.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
@@ -187,7 +186,6 @@ static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = {
 	},
 };
 
-static struct s3c_hsotg_plat smartq_hsotg_pdata;
 
 static int __init smartq_lcd_setup_gpio(void)
 {
@@ -385,7 +383,6 @@ void __init smartq_map_io(void)
 void __init smartq_machine_init(void)
 {
 	s3c_i2c0_set_platdata(NULL);
-	s3c_hsotg_set_platdata(&smartq_hsotg_pdata);
 	s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
 	s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
 	s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);
arch/arm/mach-s3c64xx/mach-smdk6410.c +0 -3
index 0fe4f15..cbdc91b 100644
@@ -30,7 +30,6 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/pwm_backlight.h>
-#include <linux/platform_data/s3c-hsotg.h>
 
 #ifdef CONFIG_SMDK6410_WM1190_EV1
 #include <linux/mfd/wm8350/core.h>
@@ -627,7 +626,6 @@ static struct platform_pwm_backlight_data smdk6410_bl_data = {
 	.pwm_id = 1,
 };
 
-static struct s3c_hsotg_plat smdk6410_hsotg_pdata;
 
 static void __init smdk6410_map_io(void)
 {
@@ -657,7 +655,6 @@ static void __init smdk6410_machine_init(void)
 	s3c_i2c0_set_platdata(NULL);
 	s3c_i2c1_set_platdata(NULL);
 	s3c_fb_set_platdata(&smdk6410_lcd_pdata);
-	s3c_hsotg_set_platdata(&smdk6410_hsotg_pdata);
 
 	samsung_keypad_set_platdata(&smdk6410_keypad_data);
 
arch/arm/mach-s3c64xx/setup-usb-phy.c +0 -79

82 lines not on this page · raw message

Signature · 1 line
1.7.1
#25 lore raw

PATCH v6 4/5 ARM: S3C64XX: Enabling samsung-usbphy driver

In reply to Praveen Paneri

Adding platform device for samsung-usbphy driver. Enabling it for s3c64xx based machines using s3c-hsotg.

---
 arch/arm/mach-s3c64xx/include/mach/map.h     |    2 +
 arch/arm/mach-s3c64xx/mach-crag6410.c        |    7 ++++++
 arch/arm/mach-s3c64xx/mach-smartq.c          |    8 +++++++
 arch/arm/mach-s3c64xx/mach-smdk6410.c        |    7 ++++++
 arch/arm/mach-s3c64xx/setup-usb-phy.c        |   14 +++++++++++++
 arch/arm/plat-samsung/devs.c                 |   28 ++++++++++++++++++++++++++
 arch/arm/plat-samsung/include/plat/devs.h    |    1 +
 arch/arm/plat-samsung/include/plat/usb-phy.h |    1 +
 8 files changed, 68 insertions(+), 0 deletions(-)
arch/arm/mach-s3c64xx/include/mach/map.h +2 -0
index 8e2097b..dc482bb 100644
@@ -65,6 +65,7 @@
 
 #define S3C64XX_PA_NAND		(0x70200000)
 #define S3C64XX_PA_FB		(0x77100000)
+#define S3C64XX_PA_USB_HSPHY	(0x7C100000)
 #define S3C64XX_PA_USB_HSOTG	(0x7C000000)
 #define S3C64XX_PA_WATCHDOG	(0x7E004000)
 #define S3C64XX_PA_RTC		(0x7E005000)
@@ -113,6 +114,7 @@
 #define S3C_PA_FB		S3C64XX_PA_FB
 #define S3C_PA_USBHOST		S3C64XX_PA_USBHOST
 #define S3C_PA_USB_HSOTG	S3C64XX_PA_USB_HSOTG
+#define S3C_PA_USB_PHY		S3C64XX_PA_USB_HSPHY
 #define S3C_PA_RTC		S3C64XX_PA_RTC
 #define S3C_PA_WDT		S3C64XX_PA_WATCHDOG
 #define S3C_PA_SPI0		S3C64XX_PA_SPI0
arch/arm/mach-s3c64xx/mach-crag6410.c +7 -0
index b0f5baf..adc2e15 100644
@@ -31,6 +31,7 @@
 #include <linux/spi/spi.h>
 
 #include <linux/i2c/pca953x.h>
+#include <linux/platform_data/samsung-usbphy.h>
 
 #include <video/platform_lcd.h>
 
@@ -69,6 +70,7 @@
 #include <plat/adc.h>
 #include <plat/iic.h>
 #include <plat/pm.h>
+#include <plat/usb-phy.h>
 
 #include "common.h"
 
@@ -336,6 +338,7 @@ static struct platform_device wallvdd_device = {
 };
 
 static struct platform_device *crag6410_devices[] __initdata = {
+	&samsung_device_usbphy,
 	&s3c_device_hsmmc0,
 	&s3c_device_hsmmc2,
 	&s3c_device_i2c0,
@@ -765,6 +768,9 @@ static const struct gpio_led_platform_data gpio_leds_pdata = {
 	.num_leds = ARRAY_SIZE(gpio_leds),
 };
 
+static struct samsung_usbphy_data crag6410_usbphy_pdata __initdata = {
+	.pmu_isolation = s5p_usb_phy_pmu_isolation,
+};
 
 static void __init crag6410_machine_init(void)
 {
@@ -790,6 +796,7 @@ static void __init crag6410_machine_init(void)
 	s3c_i2c0_set_platdata(&i2c0_pdata);
 	s3c_i2c1_set_platdata(&i2c1_pdata);
 	s3c_fb_set_platdata(&crag6410_lcd_pdata);
+	samsung_usbphy_set_pdata(&crag6410_usbphy_pdata);
 
 	i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
 	i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
arch/arm/mach-s3c64xx/mach-smartq.c +8 -0
index 7400da1..90dc821 100644
@@ -18,6 +18,7 @@
 #include <linux/serial_core.h>
 #include <linux/spi/spi_gpio.h>
 #include <linux/usb/gpio_vbus.h>
+#include <linux/platform_data/samsung-usbphy.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
@@ -36,6 +37,7 @@
 #include <plat/usb-control.h>
 #include <plat/sdhci.h>
 #include <plat/ts.h>
+#include <plat/usb-phy.h>
 
 #include <video/platform_lcd.h>
 
@@ -234,6 +236,7 @@ static struct i2c_board_info smartq_i2c_devs[] __initdata = {
 };
 
 static struct platform_device *smartq_devices[] __initdata = {
+	&samsung_device_usbphy,
 	&s3c_device_hsmmc1,	/* Init iNAND first, ... */
 	&s3c_device_hsmmc0,	/* ... then the external SD card */
 	&s3c_device_hsmmc2,
@@ -380,9 +383,14 @@ void __init smartq_map_io(void)
 	smartq_lcd_mode_set();
 }
 
+static struct samsung_usbphy_data smartq_usbphy_pdata __initdata = {
+	.pmu_isolation = s5p_usb_phy_pmu_isolation,
+};
+
 void __init smartq_machine_init(void)
 {
 	s3c_i2c0_set_platdata(NULL);
+	samsung_usbphy_set_pdata(&smartq_usbphy_pdata);
 	s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
 	s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
 	s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);
arch/arm/mach-s3c64xx/mach-smdk6410.c +7 -0
index cbdc91b..4cf1252 100644
@@ -30,6 +30,7 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/pwm_backlight.h>
+#include <linux/platform_data/samsung-usbphy.h>
 
 #ifdef CONFIG_SMDK6410_WM1190_EV1
 #include <linux/mfd/wm8350/core.h>
@@ -72,6 +73,7 @@
 #include <plat/keypad.h>
 #include <plat/backlight.h>
 #include <plat/regs-fb-v4.h>
+#include <plat/usb-phy.h>
 
 #include "common.h"
 
@@ -263,6 +265,7 @@ static struct samsung_keypad_platdata smdk6410_keypad_data __initdata = {
 static struct map_desc smdk6410_iodesc[] = {};
 
 static struct platform_device *smdk6410_devices[] __initdata = {
+	&samsung_device_usbphy,
 #ifdef CONFIG_SMDK6410_SD_CH0
 	&s3c_device_hsmmc0,
 #endif
@@ -626,6 +629,9 @@ static struct platform_pwm_backlight_data smdk6410_bl_data = {
 	.pwm_id = 1,
 };
 
+static struct samsung_usbphy_data smdk6410_usbphy_pdata __initdata = {
+	.pmu_isolation = s5p_usb_phy_pmu_isolation,
+};
 
 static void __init smdk6410_map_io(void)
 {
@@ -655,6 +661,7 @@ static void __init smdk6410_machine_init(void)
 	s3c_i2c0_set_platdata(NULL);
 	s3c_i2c1_set_platdata(NULL);
 	s3c_fb_set_platdata(&smdk6410_lcd_pdata);
+	samsung_usbphy_set_pdata(&smdk6410_usbphy_pdata);
 
 	samsung_keypad_set_platdata(&smdk6410_keypad_data);
 
arch/arm/mach-s3c64xx/setup-usb-phy.c +14 -0
index 7a09553..3aee778 100644
@@ -9,3 +9,17 @@
  *
  */
 
+#include <linux/io.h>
+#include <mach/map.h>
+#include <mach/regs-sys.h>
+
+void s5p_usb_phy_pmu_isolation(int on)
+{
+	if (on) {
+		writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK,
+			S3C64XX_OTHERS);
+	} else {
+		writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK,
+			S3C64XX_OTHERS);
+	}
+}
arch/arm/plat-samsung/devs.c +28 -0
index fc49f3d..d5d5735 100644
@@ -31,6 +31,7 @@
 #include <linux/ioport.h>
 #include <linux/platform_data/s3c-hsudc.h>
 #include <linux/platform_data/s3c-hsotg.h>
+#include <linux/platform_data/samsung-usbphy.h>
 
 #include <media/s5p_hdmi.h>
 
@@ -1370,6 +1371,30 @@ struct platform_device s5p_device_mixer = {
 
 /* USB */
 
+#ifdef CONFIG_S3C_DEV_USB_HSOTG
+/* USB PHY*/
+static struct resource samsung_usbphy_resource[] = {
+	[0] = {
+		.start = S3C_PA_USB_PHY,
+		.end   = S3C_PA_USB_PHY + SZ_16 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device samsung_device_usbphy = {
+	.name		= "s3c64xx-usbphy",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(samsung_usbphy_resource),
+	.resource	= samsung_usbphy_resource,
+};
+
+void __init samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd)
+{
+	s3c_set_platdata(pd, sizeof(struct samsung_usbphy_data),
+			&samsung_device_usbphy);
+}
+#endif
+
 #ifdef CONFIG_S3C_DEV_USB_HOST
 static struct resource s3c_usb_resource[] = {
 	[0] = DEFINE_RES_MEM(S3C_PA_USBHOST, SZ_256),
@@ -1476,6 +1501,8 @@ struct platform_device s3c_device_usb_hsotg = {
 	},
 };
 
+#ifndef CONFIG_ARCH_S3C64XX
+/* TODO: To be removed later. Currently only S3C64XX is platform data free */
 void __init s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd)
 {
 	struct s3c_hsotg_plat *npd;
@@ -1488,6 +1515,7 @@ void __init s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd)
 	if (!npd->phy_exit)
 		npd->phy_exit = s5p_usb_phy_exit;
 }
+#endif
 #endif /* CONFIG_S3C_DEV_USB_HSOTG */
 
 /* USB High Spped 2.0 Device (Gadget) */
arch/arm/plat-samsung/include/plat/devs.h +1 -0
index 5da4b4f..3849c88 100644
@@ -138,6 +138,7 @@ extern struct platform_device exynos_device_drm;
 extern struct platform_device samsung_asoc_dma;
 extern struct platform_device samsung_asoc_idma;
 extern struct platform_device samsung_device_keypad;
+extern struct platform_device samsung_device_usbphy;
 
 /* s3c2440 specific devices */
 
arch/arm/plat-samsung/include/plat/usb-phy.h +1 -0
index 959bcdb..165ffe7 100644
@@ -18,5 +18,6 @@ enum s5p_usb_phy_type {
 
 extern int s5p_usb_phy_init(struct platform_device *pdev, int type);
 extern int s5p_usb_phy_exit(struct platform_device *pdev, int type);
+extern void s5p_usb_phy_pmu_isolation(int on);
 
 #endif /* __PLAT_SAMSUNG_USB_PHY_H */
Signature · 1 line
1.7.1
#26 lore raw

PATCH v6 5/5 ARM: Exynos4210: Enabling samsung-usbphy driver

In reply to Praveen Paneri

Adding usbphy node for Exynos4210 along with the platform data.

---
 arch/arm/boot/dts/exynos4210.dtsi       |    5 +++++
 arch/arm/mach-exynos/include/mach/map.h |    1 +
 arch/arm/mach-exynos/mach-exynos4-dt.c  |    8 ++++++++
 arch/arm/mach-exynos/setup-usb-phy.c    |   13 +++++++++++++
 4 files changed, 27 insertions(+), 0 deletions(-)
arch/arm/boot/dts/exynos4210.dtsi +5 -0
index 02891fe..e28cf10 100644
@@ -62,6 +62,11 @@
 		interrupts = <0 44 0>, <0 45 0>;
 	};
 
+	usbphy@125B0000 {
+		compatible = "samsung,exynos4210-usbphy";
+		reg = <0x125B0000 0x100>;
+	};
+
 	keypad@100A0000 {
 		compatible = "samsung,s5pv210-keypad";
 		reg = <0x100A0000 0x100>;
arch/arm/mach-exynos/include/mach/map.h +1 -0
index c72b675..0625c0a 100644
@@ -234,6 +234,7 @@
 #define S3C_PA_SPI1			EXYNOS4_PA_SPI1
 #define S3C_PA_SPI2			EXYNOS4_PA_SPI2
 #define S3C_PA_USB_HSOTG		EXYNOS4_PA_HSOTG
+#define S3C_PA_USB_PHY			EXYNOS4_PA_HSPHY
 
 #define S5P_PA_EHCI			EXYNOS4_PA_EHCI
 #define S5P_PA_FIMC0			EXYNOS4_PA_FIMC0
arch/arm/mach-exynos/mach-exynos4-dt.c +8 -0
index b2b5d5f..0739be8 100644
@@ -13,6 +13,7 @@
 
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
+#include <linux/platform_data/samsung-usbphy.h>
 
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -20,9 +21,14 @@
 
 #include <plat/cpu.h>
 #include <plat/regs-serial.h>
+#include <plat/usb-phy.h>
 
 #include "common.h"
 
+static struct samsung_usbphy_data exynos4_usbphy_pdata = {
+	.pmu_isolation = s5p_usb_phy_pmu_isolation,
+};
+
 /*
  * The following lookup table is used to override device names when devices
  * are registered from device tree. This is temporarily added to enable
@@ -63,6 +69,8 @@ static const struct of_dev_auxdata exynos4210_auxdata_lookup[] __initconst = {
 				"exynos4210-spi.2", NULL),
 	OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_PDMA0, "dma-pl330.0", NULL),
 	OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_PDMA1, "dma-pl330.1", NULL),
+	OF_DEV_AUXDATA("samsung,exynos4210-usbphy", EXYNOS4_PA_HSPHY,
+			"s3c-usbphy", &exynos4_usbphy_pdata),
 	{},
 };
 
arch/arm/mach-exynos/setup-usb-phy.c +13 -0
index b81cc56..1c62d20 100644
@@ -221,3 +221,16 @@ int s5p_usb_phy_exit(struct platform_device *pdev, int type)
 
 	return -EINVAL;
 }
+
+void s5p_usb_phy_pmu_isolation(int on)
+{
+	if (on) {
+		writel(readl(S5P_USBDEVICE_PHY_CONTROL)
+			& ~S5P_USBDEVICE_PHY_ENABLE,
+				S5P_USBDEVICE_PHY_CONTROL);
+	} else {
+		writel(readl(S5P_USBDEVICE_PHY_CONTROL)
+			| S5P_USBDEVICE_PHY_ENABLE,
+				S5P_USBDEVICE_PHY_CONTROL);
+	}
+}
Signature · 1 line
1.7.1