All of lore.kernel.org
 help / color / mirror / Atom feed
* [V6 PATCH 00/16] mv-usb phy enhancement patches
@ 2013-02-06  7:23 Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller Chao Xie
                   ` (15 more replies)
  0 siblings, 16 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

The patches are divied into 2 parts

1. PHY driver
To remove the callbacks in the platform data, a usb PHY driver
for marvell udc/otg/ehci is written.
For device tree support, it is not good to pass the callback
pointers by platform data. The PHY driver also removes the
block.

  usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  usb: gadget: mv_udc: use PHY driver for udc
  usb: ehci: ehci-mv: use PHY driver for ehci
  usb: otg: mv_otg: use PHY driver for otg
Above patches are marvell usb PHY driver support.

  arm: mmp2: change the defintion of usb devices
  arm: pxa910: change the defintion of usb devices
  arm: brownstone: add usb support for the board
  arm: ttc_dkb: add usb support
  arm: mmp: remove the usb phy setting
  arm: mmp: remove usb devices from pxa168
Above patches are for SOC/board support for marvell usb PHY
driver.

2. external chip support
The marvell usb controller can detect the vbus/idpin, but it
need PHY and usb clocks to be enabled.
Based on measurement it will import 15mA current, and increase
the power when the usb is not used.
Using a external chip to detect vbus/idpin changes will save
the power.
In fact the marvell PMIC 88pm860x and 88pm80x can do it. The
drivers are located at drivers/mfd.
So add a middle layer in the marvell usb PHY driver.
PMIC call the APIs in middle driver to registers the callback
for vbus/idpin detection/query
udc/otg/ehci driver will call the APIs to get vbus/idpin changes
and query the states of the vbus/idpin.
  usb: phy: mv_usb2_phy: add externel chip support
  usb: gadget: mv_udc: add extern chip support
  usb: ehci: ehci-mv: add extern chip support
  usb: otg: mv_otg: add extern chip support
Above patches are the middle layer suppor for udc/otg/ehci

  arm: mmp: add extern chip support for brownstone
  arm: mmp: add extern chip support for ttc_dkb
Above patches are corresponding board file changes

V2->V1:
  Change the Signed-off-by to be right email address

v3->v2
  re-format the patches to new code base

v4->v3
  1. make mv udc gadget driver depend on ARCH_PXA and ARCH_MMP
  2. remove __devinit and __devexit
  3. make the driver compiled successful if CONFIG_MV_USB2_PHY is not defined.
  The modified patches are
  usb: gadget: mv_udc: make mv_udc depends on ARCH_MMP or ARCH_PXA
  usb: phy: mv_usb2: add PHY driver for marvell usb2 controller

v5->v4
  make the struct mv_usb2_extern_chip member ->head to be
  struct atomic_notifier_head instead of struct atomic_notifier_head *.

v6->v5
  the bug fix patches are merged.
  Removed the dependcy of ARCH_MMP and ARCH_PXA, and make the driver can be
  compiled for x86.
  The device tree support patches need modification, remove them from this
  patch series, and they will be submitted in another series.


Chao Xie (16):
  usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  usb: gadget: mv_udc: use PHY driver for udc
  usb: ehci: ehci-mv: use PHY driver for ehci
  usb: otg: mv_otg: use PHY driver for otg
  arm: mmp2: change the defintion of usb devices
  arm: pxa910: change the defintion of usb devices
  arm: brownstone: add usb support for the board
  arm: ttc_dkb: add usb support
  arm: mmp: remove the usb phy setting
  arm: mmp: remove usb devices from pxa168
  usb: phy: mv_usb2_phy: add externel chip support
  usb: gadget: mv_udc: add extern chip support
  usb: ehci: ehci-mv: add extern chip support
  usb: otg: mv_otg: add extern chip support
  arm: mmp: add extern chip support for brownstone
  arm: mmp: add extern chip support for ttc_dkb

 arch/arm/mach-mmp/brownstone.c            |   45 +++
 arch/arm/mach-mmp/devices.c               |  278 ----------------
 arch/arm/mach-mmp/include/mach/mmp2.h     |    4 +
 arch/arm/mach-mmp/include/mach/pxa910.h   |    7 +-
 arch/arm/mach-mmp/include/mach/regs-usb.h |  253 ---------------
 arch/arm/mach-mmp/mmp2.c                  |    4 +
 arch/arm/mach-mmp/pxa168.c                |   42 ---
 arch/arm/mach-mmp/pxa910.c                |    4 +
 arch/arm/mach-mmp/ttc_dkb.c               |   32 ++-
 drivers/usb/gadget/mv_udc.h               |    5 +-
 drivers/usb/gadget/mv_udc_core.c          |   70 ++--
 drivers/usb/host/ehci-mv.c                |   49 ++--
 drivers/usb/otg/mv_otg.c                  |   96 +++----
 drivers/usb/otg/mv_otg.h                  |    5 +-
 drivers/usb/phy/Kconfig                   |    7 +
 drivers/usb/phy/Makefile                  |    1 +
 drivers/usb/phy/mv_usb2_phy.c             |  503 +++++++++++++++++++++++++++++
 include/linux/platform_data/mv_usb.h      |   22 +-
 include/linux/usb/mv_usb2.h               |  128 ++++++++
 19 files changed, 832 insertions(+), 723 deletions(-)
 delete mode 100644 arch/arm/mach-mmp/include/mach/regs-usb.h
 create mode 100644 drivers/usb/phy/mv_usb2_phy.c
 create mode 100644 include/linux/usb/mv_usb2.h

-- 
1.7.4.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  8:10   ` kishon
  2013-02-06 14:42   ` Mark Rutland
  2013-02-06  7:23 ` [V6 PATCH 02/16] usb: gadget: mv_udc: use PHY driver for udc Chao Xie
                   ` (14 subsequent siblings)
  15 siblings, 2 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

The PHY is seperated from usb controller.
The usb controller used in marvell pxa168/pxa910/mmp2 are same,
but PHY initialization may be different.
the usb controller can support udc/otg/ehci, and for each of
the mode, it need PHY to initialized before use the controller.
Direclty writing the phy driver will make the usb controller
driver to be simple and portable.
The PHY driver will be used by marvell udc/otg/ehci.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 drivers/usb/phy/Kconfig              |    7 +
 drivers/usb/phy/Makefile             |    1 +
 drivers/usb/phy/mv_usb2_phy.c        |  454 ++++++++++++++++++++++++++++++++++
 include/linux/platform_data/mv_usb.h |    9 +-
 include/linux/usb/mv_usb2.h          |   43 ++++
 5 files changed, 511 insertions(+), 3 deletions(-)
 create mode 100644 drivers/usb/phy/mv_usb2_phy.c
 create mode 100644 include/linux/usb/mv_usb2.h

diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 65217a5..5479760 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -73,3 +73,10 @@ config SAMSUNG_USBPHY
 	help
 	  Enable this to support Samsung USB phy controller for samsung
 	  SoCs.
+
+config MV_USB2_PHY
+	tristate "Marvell USB 2.0 PHY Driver"
+	depends on USB || USB_GADGET
+	help
+	  Enable this to support Marvell USB 2.0 phy driver for Marvell
+	  SoC.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index b13faa1..3835316 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
 obj-$(CONFIG_USB_RCAR_PHY)		+= rcar-phy.o
 obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
+obj-$(CONFIG_MV_USB2_PHY)		+= mv_usb2_phy.o
diff --git a/drivers/usb/phy/mv_usb2_phy.c b/drivers/usb/phy/mv_usb2_phy.c
new file mode 100644
index 0000000..c2bccae
--- /dev/null
+++ b/drivers/usb/phy/mv_usb2_phy.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Chao Xie <xiechao.mail@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/resource.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/mv_usb.h>
+#include <linux/usb/mv_usb2.h>
+
+/* phy regs */
+#define UTMI_REVISION		0x0
+#define UTMI_CTRL		0x4
+#define UTMI_PLL		0x8
+#define UTMI_TX			0xc
+#define UTMI_RX			0x10
+#define UTMI_IVREF		0x14
+#define UTMI_T0			0x18
+#define UTMI_T1			0x1c
+#define UTMI_T2			0x20
+#define UTMI_T3			0x24
+#define UTMI_T4			0x28
+#define UTMI_T5			0x2c
+#define UTMI_RESERVE		0x30
+#define UTMI_USB_INT		0x34
+#define UTMI_DBG_CTL		0x38
+#define UTMI_OTG_ADDON		0x3c
+
+/* For UTMICTRL Register */
+#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
+/* pxa168 */
+#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
+#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
+#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
+#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
+
+#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
+#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT		28
+#define UTMI_CTRL_PU_REF_SHIFT			20
+#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
+#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
+#define UTMI_CTRL_PWR_UP_SHIFT                  0
+
+/* For UTMI_PLL Register */
+#define UTMI_PLL_PLLCALI12_SHIFT		29
+#define UTMI_PLL_PLLCALI12_MASK			(0x3 << 29)
+
+#define UTMI_PLL_PLLVDD18_SHIFT			27
+#define UTMI_PLL_PLLVDD18_MASK			(0x3 << 27)
+
+#define UTMI_PLL_PLLVDD12_SHIFT			25
+#define UTMI_PLL_PLLVDD12_MASK			(0x3 << 25)
+
+#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
+#define CLK_BLK_EN                              (0x1 << 24)
+#define PLL_READY                               (0x1 << 23)
+#define KVCO_EXT                                (0x1 << 22)
+#define VCOCAL_START                            (0x1 << 21)
+
+#define UTMI_PLL_KVCO_SHIFT			15
+#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
+
+#define UTMI_PLL_ICP_SHIFT			12
+#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
+
+#define UTMI_PLL_FBDIV_SHIFT                    4
+#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
+
+#define UTMI_PLL_REFDIV_SHIFT                   0
+#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
+
+/* For UTMI_TX Register */
+#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT		27
+#define UTMI_TX_REG_EXT_FS_RCAL_MASK		(0xf << 27)
+
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT	26
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK		(0x1 << 26)
+
+#define UTMI_TX_TXVDD12_SHIFT                   22
+#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
+
+#define UTMI_TX_CK60_PHSEL_SHIFT                17
+#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
+
+#define UTMI_TX_IMPCAL_VTH_SHIFT                14
+#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
+
+#define REG_RCAL_START                          (0x1 << 12)
+
+#define UTMI_TX_LOW_VDD_EN_SHIFT                11
+
+#define UTMI_TX_AMP_SHIFT			0
+#define UTMI_TX_AMP_MASK			(0x7 << 0)
+
+/* For UTMI_RX Register */
+#define UTMI_REG_SQ_LENGTH_SHIFT                15
+#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
+
+#define UTMI_RX_SQ_THRESH_SHIFT                 4
+#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
+
+#define UTMI_OTG_ADDON_OTG_ON			(1 << 0)
+
+enum mv_usb2_phy_type {
+	PXA168_USB,
+	PXA910_USB,
+	MMP2_USB,
+};
+
+static struct mv_usb2_phy *the_phy;
+
+struct mv_usb2_phy *mv_usb2_get_phy(void)
+{
+	return the_phy;
+}
+EXPORT_SYMBOL(mv_usb2_get_phy);
+
+static unsigned int u2o_get(void __iomem *base, unsigned int offset)
+{
+	return readl(base + offset);
+}
+
+static void u2o_set(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	u32 reg;
+
+	reg = readl(base + offset);
+	reg |= value;
+	writel(reg, base + offset);
+	readl(base + offset);
+}
+
+static void u2o_clear(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	u32 reg;
+
+	reg = readl(base + offset);
+	reg &= ~value;
+	writel(reg, base + offset);
+	readl(base + offset);
+}
+
+static void u2o_write(void __iomem *base, unsigned int offset,
+		unsigned int value)
+{
+	writel(value, base + offset);
+	readl(base + offset);
+}
+
+static int _usb_phy_init(struct mv_usb2_phy *mv_phy)
+{
+	struct platform_device *pdev = mv_phy->pdev;
+	unsigned int loops = 0;
+	void __iomem *base = mv_phy->base;
+
+	dev_dbg(&pdev->dev, "phy init\n");
+
+	/* Initialize the USB PHY power */
+	if (mv_phy->type == PXA910_USB) {
+		u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
+			| (1<<UTMI_CTRL_PU_REF_SHIFT));
+	}
+
+	u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
+	u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
+
+	/* UTMI_PLL settings */
+	u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
+		| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
+		| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
+		| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
+
+	u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
+		| 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
+		| 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
+		| 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
+
+	/* UTMI_TX */
+	u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
+		| UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
+		| UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
+		| UTMI_TX_AMP_MASK);
+	u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
+		| 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
+		| 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
+
+	/* UTMI_RX */
+	u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
+		| UTMI_REG_SQ_LENGTH_MASK);
+	u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
+		| 2<<UTMI_REG_SQ_LENGTH_SHIFT);
+
+	/* UTMI_IVREF */
+	if (mv_phy->type == PXA168_USB)
+		/* fixing Microsoft Altair board interface with NEC hub issue -
+		 * Set UTMI_IVREF from 0x4a3 to 0x4bf */
+		u2o_write(base, UTMI_IVREF, 0x4bf);
+
+	/* toggle VCOCAL_START bit of UTMI_PLL */
+	udelay(200);
+	u2o_set(base, UTMI_PLL, VCOCAL_START);
+	udelay(40);
+	u2o_clear(base, UTMI_PLL, VCOCAL_START);
+
+	/* toggle REG_RCAL_START bit of UTMI_TX */
+	udelay(400);
+	u2o_set(base, UTMI_TX, REG_RCAL_START);
+	udelay(40);
+	u2o_clear(base, UTMI_TX, REG_RCAL_START);
+	udelay(400);
+
+	/* Make sure PHY PLL is ready */
+	loops = 0;
+	while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
+		mdelay(1);
+		loops++;
+		if (loops > 100) {
+			dev_warn(&pdev->dev, "calibrate timeout, UTMI_PLL %x\n",
+				u2o_get(base, UTMI_PLL));
+			break;
+		}
+	}
+
+	if (mv_phy->type == PXA168_USB) {
+		u2o_set(base, UTMI_RESERVE, 1 << 5);
+		/* Turn on UTMI PHY OTG extension */
+		u2o_write(base, UTMI_OTG_ADDON, 1);
+	}
+
+	return 0;
+}
+
+static int _usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
+{
+	void __iomem *base = mv_phy->base;
+
+	if (mv_phy->type == PXA168_USB)
+		u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
+
+	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
+	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
+	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
+	u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
+	u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
+
+	return 0;
+}
+
+static int usb_phy_init(struct mv_usb2_phy *mv_phy)
+{
+	int i = 0;
+
+	mutex_lock(&mv_phy->phy_lock);
+	if (mv_phy->refcount++ == 0) {
+		for (i = 0; i < mv_phy->clks_num; i++)
+			clk_prepare_enable(mv_phy->clks[i]);
+		_usb_phy_init(mv_phy);
+	}
+	mutex_unlock(&mv_phy->phy_lock);
+	return 0;
+}
+
+static void usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
+{
+	int i = 0;
+
+	mutex_lock(&mv_phy->phy_lock);
+	if (mv_phy->refcount++ == 0) {
+		_usb_phy_shutdown(mv_phy);
+		for (i = 0; i < mv_phy->clks_num; i++)
+			clk_disable_unprepare(mv_phy->clks[i]);
+	}
+	mutex_unlock(&mv_phy->phy_lock);
+}
+
+static struct of_device_id usb_phy_dt_ids[] = {
+	{ .compatible = "mrvl,pxa168-usb-phy",	.data = (void *)PXA168_USB},
+	{ .compatible = "mrvl,pxa910-usb-phy",	.data = (void *)PXA910_USB},
+	{ .compatible = "mrvl,mmp2-usb-phy",	.data = (void *)MMP2_USB},
+	{}
+};
+MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);
+
+static int usb_phy_parse_dt(struct platform_device *pdev,
+				struct mv_usb2_phy *mv_phy)
+{
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_id =
+			of_match_device(usb_phy_dt_ids, &pdev->dev);
+	unsigned int clks_num;
+	int i, ret;
+	const char *clk_name;
+
+	if (!np)
+		return 1;
+
+	clks_num = of_property_count_strings(np, "clocks");
+	if (clks_num < 0) {
+		dev_err(&pdev->dev, "failed to get clock number\n");
+		return clks_num;
+	}
+
+	mv_phy->clks = devm_kzalloc(&pdev->dev,
+		sizeof(struct clk *) * clks_num, GFP_KERNEL);
+	if (mv_phy->clks == NULL) {
+		dev_err(&pdev->dev,
+			"failed to allocate mempory for clocks");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < clks_num; i++) {
+		ret = of_property_read_string_index(np, "clocks", i,
+			&clk_name);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to read clocks\n");
+			return ret;
+		}
+		mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(mv_phy->clks[i])) {
+			dev_err(&pdev->dev, "failed to get clock %s\n",
+				clk_name);
+			return PTR_ERR(mv_phy->clks[i]);
+		}
+	}
+
+	mv_phy->clks_num = clks_num;
+	mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
+
+	return 0;
+}
+
+static int usb_phy_probe(struct platform_device *pdev)
+{
+	struct mv_usb2_phy *mv_phy;
+	struct resource *r;
+	int ret, i;
+
+	mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
+	if (mv_phy == NULL) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+	mutex_init(&mv_phy->phy_lock);
+
+	ret = usb_phy_parse_dt(pdev, mv_phy);
+	/* no CONFIG_OF */
+	if (ret > 0) {
+		struct mv_usb_phy_platform_data *pdata
+				= pdev->dev.platform_data;
+		const struct platform_device_id *id
+				= platform_get_device_id(pdev);
+
+		if (pdata == NULL || id == NULL) {
+			dev_err(&pdev->dev,
+				"missing platform_data or id_entry\n");
+			return -ENODEV;
+		}
+		mv_phy->type = (unsigned int)(id->driver_data);
+		mv_phy->clks_num = pdata->clknum;
+		mv_phy->clks = devm_kzalloc(&pdev->dev,
+			sizeof(struct clk *) * mv_phy->clks_num, GFP_KERNEL);
+		if (mv_phy->clks == NULL) {
+			dev_err(&pdev->dev,
+				"failed to allocate mempory for clocks");
+			return -ENOMEM;
+		}
+		for (i = 0; i < mv_phy->clks_num; i++)
+			mv_phy->clks[i] = devm_clk_get(&pdev->dev,
+							pdata->clkname[i]);
+			if (IS_ERR(mv_phy->clks[i])) {
+				dev_err(&pdev->dev, "failed to get clock %s\n",
+					pdata->clkname[i]);
+				return PTR_ERR(mv_phy->clks[i]);
+			}
+	} else if (ret < 0) {
+		dev_err(&pdev->dev, "error parse dt\n");
+		return ret;
+	}
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
+		return -ENODEV;
+	}
+	mv_phy->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (mv_phy->base == NULL) {
+		dev_err(&pdev->dev, "error map register base\n");
+		return -EBUSY;
+	}
+	platform_set_drvdata(pdev, mv_phy);
+	mv_phy->pdev = pdev;
+	mv_phy->init = usb_phy_init;
+	mv_phy->shutdown = usb_phy_shutdown;
+
+	platform_set_drvdata(pdev, mv_phy);
+
+	the_phy = mv_phy;
+
+	dev_info(&pdev->dev, "mv usb2 phy initialized\n");
+
+	return 0;
+}
+
+static int usb_phy_remove(struct platform_device *pdev)
+{
+	the_phy = NULL;
+
+	return 0;
+}
+
+static struct platform_device_id usb_phy_ids[] = {
+	{ .name = "pxa168-usb-phy",	.driver_data = PXA168_USB },
+	{ .name = "pxa910-usb-phy",	.driver_data = PXA910_USB },
+	{ .name = "mmp2-usb-phy",	.driver_data = MMP2_USB },
+	{}
+};
+
+static struct platform_driver usb_phy_driver = {
+	.probe	= usb_phy_probe,
+	.remove = usb_phy_remove,
+	.driver = {
+		.name   = "pxa168-usb-phy",
+		.of_match_table = usb_phy_dt_ids,
+	},
+	.id_table = usb_phy_ids,
+};
+
+static int __init mv_usb2_phy_init(void)
+{
+	return platform_driver_register(&usb_phy_driver);
+}
+arch_initcall(mv_usb2_phy_init);
diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h
index 944b01d..fd3d1b4 100644
--- a/include/linux/platform_data/mv_usb.h
+++ b/include/linux/platform_data/mv_usb.h
@@ -47,9 +47,12 @@ struct mv_usb_platform_data {
 	/* Force a_bus_req to be asserted */
 	 unsigned int    otg_force_a_bus_req:1;
 
-	int	(*phy_init)(void __iomem *regbase);
-	void	(*phy_deinit)(void __iomem *regbase);
 	int	(*set_vbus)(unsigned int vbus);
-	int     (*private_init)(void __iomem *opregs, void __iomem *phyregs);
 };
+
+struct mv_usb_phy_platform_data {
+	unsigned int	clknum;
+	char		**clkname;
+};
+
 #endif
diff --git a/include/linux/usb/mv_usb2.h b/include/linux/usb/mv_usb2.h
new file mode 100644
index 0000000..9744a97
--- /dev/null
+++ b/include/linux/usb/mv_usb2.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 Marvell Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MV_USB2_H
+#define __MV_USB2_H
+
+#include <linux/clk.h>
+
+struct mv_usb2_phy {
+	struct platform_device	*pdev;
+	struct mutex		phy_lock;
+	unsigned int		refcount;
+	unsigned int		type;
+	void __iomem		*base;
+	struct clk		**clks;
+	unsigned int		clks_num;
+
+	int	(*init)(struct mv_usb2_phy *mv_phy);
+	void	(*shutdown)(struct mv_usb2_phy *mv_phy);
+};
+
+#if defined(CONFIG_MV_USB2_PHY) || defined(CONFIG_MV_USB2_PHY_MODULE)
+
+extern struct mv_usb2_phy *mv_usb2_get_phy(void);
+
+#else
+
+struct mv_usb2_phy *mv_usb2_get_phy(void) { return NULL; }
+
+#endif
+
+#endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 02/16] usb: gadget: mv_udc: use PHY driver for udc
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 03/16] usb: ehci: ehci-mv: use PHY driver for ehci Chao Xie
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Originaly, udc driver will call the callbacks in platform data
for PHY initialization and shut down.
With PHY driver, it will call the APIs provided by PHY driver
for PHY initialization and shut down. It removes the callbacks
in platform data, and at same time it removes one block in the
way of enabling device tree for udc driver.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 drivers/usb/gadget/mv_udc.h      |    2 +-
 drivers/usb/gadget/mv_udc_core.c |   23 ++++++++---------------
 2 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index 9073436..4851b2b 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -180,7 +180,6 @@ struct mv_udc {
 
 	struct mv_cap_regs __iomem	*cap_regs;
 	struct mv_op_regs __iomem	*op_regs;
-	void __iomem                    *phy_regs;
 	unsigned int			max_eps;
 	struct mv_dqh			*ep_dqh;
 	size_t				ep_dqh_size;
@@ -217,6 +216,7 @@ struct mv_udc {
 	struct work_struct	vbus_work;
 	struct workqueue_struct *qwork;
 
+	struct mv_usb2_phy	*phy;
 	struct usb_phy		*transceiver;
 
 	struct mv_usb_platform_data     *pdata;
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index c8cf959..76fcfc7 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -35,6 +35,7 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/platform_data/mv_usb.h>
+#include <linux/usb/mv_usb2.h>
 #include <asm/unaligned.h>
 
 #include "mv_udc.h"
@@ -1121,8 +1122,8 @@ static int mv_udc_enable_internal(struct mv_udc *udc)
 
 	dev_dbg(&udc->dev->dev, "enable udc\n");
 	udc_clock_enable(udc);
-	if (udc->pdata->phy_init) {
-		retval = udc->pdata->phy_init(udc->phy_regs);
+	if (udc->phy->init) {
+		retval = udc->phy->init(udc->phy);
 		if (retval) {
 			dev_err(&udc->dev->dev,
 				"init phy error %d\n", retval);
@@ -1147,8 +1148,8 @@ static void mv_udc_disable_internal(struct mv_udc *udc)
 {
 	if (udc->active) {
 		dev_dbg(&udc->dev->dev, "disable udc\n");
-		if (udc->pdata->phy_deinit)
-			udc->pdata->phy_deinit(udc->phy_regs);
+		if (udc->phy->shutdown)
+			udc->phy->shutdown(udc->phy);
 		udc_clock_disable(udc);
 		udc->active = 0;
 	}
@@ -2194,7 +2195,7 @@ static int mv_udc_probe(struct platform_device *pdev)
 		}
 	}
 
-	r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
+	r = platform_get_resource(udc->dev, IORESOURCE_MEM, 0);
 	if (r == NULL) {
 		dev_err(&pdev->dev, "no I/O memory resource defined\n");
 		return -ENODEV;
@@ -2207,17 +2208,9 @@ static int mv_udc_probe(struct platform_device *pdev)
 		return -EBUSY;
 	}
 
-	r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs");
-	if (r == NULL) {
-		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
+	udc->phy = mv_usb2_get_phy();
+	if (udc->phy == NULL)
 		return -ENODEV;
-	}
-
-	udc->phy_regs = ioremap(r->start, resource_size(r));
-	if (udc->phy_regs == NULL) {
-		dev_err(&pdev->dev, "failed to map phy I/O memory\n");
-		return -EBUSY;
-	}
 
 	/* we will acces controller register, so enable the clk */
 	retval = mv_udc_enable_internal(udc);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 03/16] usb: ehci: ehci-mv: use PHY driver for ehci
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 02/16] usb: gadget: mv_udc: use PHY driver for udc Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 04/16] usb: otg: mv_otg: use PHY driver for otg Chao Xie
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Originaly, ehci driver will call the callbacks in platform data
for PHY initialization and shut down.
With PHY driver, it will call the APIs provided by PHY driver
for PHY initialization and shut down. It removes the callbacks
in platform data, and at same time it removes one block in the
way of enabling device tree for ehci driver.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
---
 drivers/usb/host/ehci-mv.c |   37 +++++++++++++------------------------
 1 files changed, 13 insertions(+), 24 deletions(-)

diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 3065809..be504fd 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -15,17 +15,18 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/mv_usb2.h>
 #include <linux/platform_data/mv_usb.h>
 
 #define CAPLENGTH_MASK         (0xff)
 
 struct ehci_hcd_mv {
 	struct usb_hcd *hcd;
+	struct mv_usb2_phy *mvphy;
 
 	/* Which mode does this ehci running OTG/Host ? */
 	int mode;
 
-	void __iomem *phy_regs;
 	void __iomem *cap_regs;
 	void __iomem *op_regs;
 
@@ -59,8 +60,8 @@ static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
 	int retval;
 
 	ehci_clock_enable(ehci_mv);
-	if (ehci_mv->pdata->phy_init) {
-		retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs);
+	if (ehci_mv->mvphy->init) {
+		retval = ehci_mv->mvphy->init(ehci_mv->mvphy);
 		if (retval)
 			return retval;
 	}
@@ -70,8 +71,8 @@ static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
 
 static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
 {
-	if (ehci_mv->pdata->phy_deinit)
-		ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs);
+	if (ehci_mv->mvphy->shutdown)
+		ehci_mv->mvphy->shutdown(ehci_mv->mvphy);
 	ehci_clock_disable(ehci_mv);
 }
 
@@ -184,22 +185,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
 		}
 	}
 
-	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
-	if (r == NULL) {
-		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
-		retval = -ENODEV;
-		goto err_clear_drvdata;
-	}
-
-	ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start,
-					 resource_size(r));
-	if (ehci_mv->phy_regs == 0) {
-		dev_err(&pdev->dev, "failed to map phy I/O memory\n");
-		retval = -EFAULT;
-		goto err_clear_drvdata;
-	}
-
-	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!r) {
 		dev_err(&pdev->dev, "no I/O memory resource defined\n");
 		retval = -ENODEV;
@@ -214,6 +200,12 @@ static int mv_ehci_probe(struct platform_device *pdev)
 		goto err_clear_drvdata;
 	}
 
+	ehci_mv->mvphy = mv_usb2_get_phy();
+	if (ehci_mv->mvphy == NULL) {
+		retval = -ENODEV;
+		goto err_clear_drvdata;
+	}
+
 	retval = mv_ehci_enable(ehci_mv);
 	if (retval) {
 		dev_err(&pdev->dev, "init phy error %d\n", retval);
@@ -275,9 +267,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (pdata->private_init)
-		pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs);
-
 	dev_info(&pdev->dev,
 		 "successful find EHCI device with regs 0x%p irq %d"
 		 " working in %s mode\n", hcd->regs, hcd->irq,
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 04/16] usb: otg: mv_otg: use PHY driver for otg
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (2 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 03/16] usb: ehci: ehci-mv: use PHY driver for ehci Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 05/16] arm: mmp2: change the defintion of usb devices Chao Xie
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Originaly, otg driver will call the callbacks in platform data
for PHY initialization and shut down.
With PHY driver, it will call the APIs provided by PHY driver
for PHY initialization and shut down. It removes the callbacks
in platform data, and at same time it removes one block in the
way of enabling device tree for otg driver.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 drivers/usb/otg/mv_otg.c |   33 ++++++++++++---------------------
 drivers/usb/otg/mv_otg.h |    2 +-
 2 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
index b6a9be3..44ddf25 100644
--- a/drivers/usb/otg/mv_otg.c
+++ b/drivers/usb/otg/mv_otg.c
@@ -25,6 +25,7 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/hcd.h>
+#include <linux/usb/mv_usb2.h>
 #include <linux/platform_data/mv_usb.h>
 
 #include "mv_otg.h"
@@ -261,8 +262,8 @@ static int mv_otg_enable_internal(struct mv_otg *mvotg)
 	dev_dbg(&mvotg->pdev->dev, "otg enabled\n");
 
 	otg_clock_enable(mvotg);
-	if (mvotg->pdata->phy_init) {
-		retval = mvotg->pdata->phy_init(mvotg->phy_regs);
+	if (mvotg->mvphy->init) {
+		retval = mvotg->mvphy->init(mvotg->mvphy);
 		if (retval) {
 			dev_err(&mvotg->pdev->dev,
 				"init phy error %d\n", retval);
@@ -288,8 +289,8 @@ static void mv_otg_disable_internal(struct mv_otg *mvotg)
 {
 	if (mvotg->active) {
 		dev_dbg(&mvotg->pdev->dev, "otg disabled\n");
-		if (mvotg->pdata->phy_deinit)
-			mvotg->pdata->phy_deinit(mvotg->phy_regs);
+		if (mvotg->mvphy->shutdown)
+			mvotg->mvphy->shutdown(mvotg->mvphy);
 		otg_clock_disable(mvotg);
 		mvotg->active = 0;
 	}
@@ -741,23 +742,8 @@ static int mv_otg_probe(struct platform_device *pdev)
 	for (i = 0; i < OTG_TIMER_NUM; i++)
 		init_timer(&mvotg->otg_ctrl.timer[i]);
 
-	r = platform_get_resource_byname(mvotg->pdev,
-					 IORESOURCE_MEM, "phyregs");
-	if (r == NULL) {
-		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
-		retval = -ENODEV;
-		goto err_destroy_workqueue;
-	}
-
-	mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
-	if (mvotg->phy_regs == NULL) {
-		dev_err(&pdev->dev, "failed to map phy I/O memory\n");
-		retval = -EFAULT;
-		goto err_destroy_workqueue;
-	}
-
-	r = platform_get_resource_byname(mvotg->pdev,
-					 IORESOURCE_MEM, "capregs");
+	r = platform_get_resource(mvotg->pdev,
+					 IORESOURCE_MEM, 0);
 	if (r == NULL) {
 		dev_err(&pdev->dev, "no I/O memory resource defined\n");
 		retval = -ENODEV;
@@ -770,6 +756,11 @@ static int mv_otg_probe(struct platform_device *pdev)
 		retval = -EFAULT;
 		goto err_destroy_workqueue;
 	}
+	mvotg->mvphy = mv_usb2_get_phy();
+	if (mvotg->mvphy == NULL) {
+		retval = -ENODEV;
+		goto err_destroy_workqueue;
+	}
 
 	/* we will acces controller register, so enable the udc controller */
 	retval = mv_otg_enable_internal(mvotg);
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h
index 8a9e351..7b9629a 100644
--- a/drivers/usb/otg/mv_otg.h
+++ b/drivers/usb/otg/mv_otg.h
@@ -137,10 +137,10 @@ struct mv_otg_regs {
 
 struct mv_otg {
 	struct usb_phy phy;
+	struct mv_usb2_phy *mvphy;
 	struct mv_otg_ctrl otg_ctrl;
 
 	/* base address */
-	void __iomem *phy_regs;
 	void __iomem *cap_regs;
 	struct mv_otg_regs __iomem *op_regs;
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 05/16] arm: mmp2: change the defintion of usb devices
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (3 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 04/16] usb: otg: mv_otg: use PHY driver for otg Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 06/16] arm: pxa910: " Chao Xie
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

add the udc/otg/ehci devices for mmp2

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 arch/arm/mach-mmp/include/mach/mmp2.h |    4 ++++
 arch/arm/mach-mmp/mmp2.c              |    4 ++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mmp/include/mach/mmp2.h b/arch/arm/mach-mmp/include/mach/mmp2.h
index c4ca4d1..58e96b0 100644
--- a/arch/arm/mach-mmp/include/mach/mmp2.h
+++ b/arch/arm/mach-mmp/include/mach/mmp2.h
@@ -31,6 +31,10 @@ extern struct pxa_device_desc mmp2_device_sdh2;
 extern struct pxa_device_desc mmp2_device_sdh3;
 extern struct pxa_device_desc mmp2_device_asram;
 extern struct pxa_device_desc mmp2_device_isram;
+extern struct pxa_device_desc mmp2_device_u2o;
+extern struct pxa_device_desc mmp2_device_u2ootg;
+extern struct pxa_device_desc mmp2_device_u2oehci;
+extern struct pxa_device_desc mmp2_device_u2ophy;
 
 extern struct platform_device mmp2_device_gpio;
 
diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c
index 3a3768c..73edbfc 100644
--- a/arch/arm/mach-mmp/mmp2.c
+++ b/arch/arm/mach-mmp/mmp2.c
@@ -153,6 +153,10 @@ MMP2_DEVICE(sdh3, "sdhci-pxav3", 3, MMC4, 0xd4281800, 0x120);
 MMP2_DEVICE(asram, "asram", -1, NONE, 0xe0000000, 0x4000);
 /* 0xd1000000 ~ 0xd101ffff is reserved for secure processor */
 MMP2_DEVICE(isram, "isram", -1, NONE, 0xd1020000, 0x18000);
+MMP2_DEVICE(u2ophy, "mmp2-usb-phy", -1, NONE, 0xd4207000, 0x1ff);
+MMP2_DEVICE(u2o, "mv-udc", -1, USB_OTG, 0xd4208100, 0x1ff);
+MMP2_DEVICE(u2ootg, "mv-otg", -1, USB_OTG, 0xd4208100, 0x1ff);
+MMP2_DEVICE(u2oehci, "mv-ehci", -1, USB_OTG, 0xd4208100, 0x1ff);
 
 struct resource mmp2_resource_gpio[] = {
 	{
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 06/16] arm: pxa910: change the defintion of usb devices
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (4 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 05/16] arm: mmp2: change the defintion of usb devices Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 07/16] arm: brownstone: add usb support for the board Chao Xie
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

because phy is seperated from the usb controller driver,
we can use the common pxa_device_desc for device register.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 arch/arm/mach-mmp/include/mach/pxa910.h |    7 ++++---
 arch/arm/mach-mmp/pxa910.c              |    4 ++++
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h
index 3b58a3b..26ea4fe 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/pxa910.h
@@ -20,9 +20,10 @@ extern struct pxa_device_desc pxa910_device_pwm2;
 extern struct pxa_device_desc pxa910_device_pwm3;
 extern struct pxa_device_desc pxa910_device_pwm4;
 extern struct pxa_device_desc pxa910_device_nand;
-extern struct platform_device pxa168_device_u2o;
-extern struct platform_device pxa168_device_u2ootg;
-extern struct platform_device pxa168_device_u2oehci;
+extern struct pxa_device_desc pxa910_device_u2o;
+extern struct pxa_device_desc pxa910_device_u2ootg;
+extern struct pxa_device_desc pxa910_device_u2oehci;
+extern struct pxa_device_desc pxa910_device_u2ophy;
 
 extern struct platform_device pxa910_device_gpio;
 extern struct platform_device pxa910_device_rtc;
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 8b1e16f..65174f7 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -138,6 +138,10 @@ PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10);
 PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10);
 PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10);
 PXA910_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
+PXA910_DEVICE(u2ophy, "pxa910-usb-phy", -1, NONE, 0xd4207000, 0x1ff);
+PXA910_DEVICE(u2o, "mv-udc", -1, USB1, 0xd4208100, 0x1ff);
+PXA910_DEVICE(u2ootg, "mv-otg", -1, USB1, 0xd4208100, 0x1ff);
+PXA910_DEVICE(u2oehci, "mv-ehci", -1, USB1, 0xd4208100, 0x1ff);
 
 struct resource pxa910_resource_gpio[] = {
 	{
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 07/16] arm: brownstone: add usb support for the board
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (5 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 06/16] arm: pxa910: " Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 08/16] arm: ttc_dkb: add usb support Chao Xie
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

for brownstone board, add the udc/otg/ehci support

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 arch/arm/mach-mmp/brownstone.c |   47 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
index 5cb769c..90c0340 100644
--- a/arch/arm/mach-mmp/brownstone.c
+++ b/arch/arm/mach-mmp/brownstone.c
@@ -18,6 +18,7 @@
 #include <linux/regulator/max8649.h>
 #include <linux/regulator/fixed.h>
 #include <linux/mfd/max8925.h>
+#include <linux/platform_data/mv_usb.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -195,6 +196,31 @@ static struct sram_platdata mmp2_isram_platdata = {
 	.granularity	= SRAM_GRANULARITY,
 };
 
+#ifdef CONFIG_USB_SUPPORT
+
+static char *mmp2_usb_clock_name[] = {
+	[0] = "usb_clk",
+};
+
+static struct mv_usb_phy_platform_data brownstone_usb_phy_pdata = {
+	.clknum		= 1,
+	.clkname	= mmp2_usb_clock_name,
+};
+
+#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O)
+
+static struct mv_usb_platform_data brownstone_usb_pdata = {
+	.clknum		= 1,
+	.clkname	= mmp2_usb_clock_name,
+	.vbus		= NULL,
+	.mode		= MV_USB_MODE_OTG,
+	.otg_force_a_bus_req = 1,
+	.set_vbus	= NULL,
+};
+#endif
+#endif
+
+
 static void __init brownstone_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(brownstone_pin_config));
@@ -211,6 +237,27 @@ static void __init brownstone_init(void)
 
 	/* enable 5v regulator */
 	platform_device_register(&brownstone_v_5vp_device);
+
+#ifdef CONFIG_USB_SUPPORT
+	pxa_register_device(&mmp2_device_u2ophy, &brownstone_usb_phy_pdata,
+				sizeof(brownstone_usb_phy_pdata));
+#endif
+
+#ifdef CONFIG_USB_MV_UDC
+	pxa_register_device(&mmp2_device_u2o, &brownstone_usb_pdata,
+				sizeof(brownstone_usb_pdata));
+#endif
+
+#ifdef CONFIG_USB_EHCI_MV_U2O
+	pxa_register_device(&mmp2_device_u2oehci, &brownstone_usb_pdata,
+				sizeof(brownstone_usb_pdata));
+#endif
+
+#ifdef CONFIG_USB_MV_OTG
+	pxa_register_device(&mmp2_device_u2ootg, &brownstone_usb_pdata,
+				sizeof(brownstone_usb_pdata));
+#endif
+
 }
 
 MACHINE_START(BROWNSTONE, "Brownstone Development Platform")
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 08/16] arm: ttc_dkb: add usb support
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (6 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 07/16] arm: brownstone: add usb support for the board Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 09/16] arm: mmp: remove the usb phy setting Chao Xie
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

for ttc_dkb board, add udc/otg/ehci support

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 arch/arm/mach-mmp/ttc_dkb.c |   30 +++++++++++++++++++-----------
 1 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index ce55fd8..0962791 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -27,7 +27,6 @@
 #include <mach/mfp-pxa910.h>
 #include <mach/pxa910.h>
 #include <mach/irqs.h>
-#include <mach/regs-usb.h>
 
 #include "common.h"
 
@@ -158,20 +157,24 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = {
 };
 
 #ifdef CONFIG_USB_SUPPORT
-#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O)
 
 static char *pxa910_usb_clock_name[] = {
-	[0] = "U2OCLK",
+	[0] = "usb_clk",
+};
+
+static struct mv_usb_phy_platform_data ttc_usb_phy_pdata = {
+	.clknum		= 1,
+	.clkname	= pxa910_usb_clock_name,
 };
 
+#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O)
+
 static struct mv_usb_platform_data ttc_usb_pdata = {
 	.clknum		= 1,
 	.clkname	= pxa910_usb_clock_name,
 	.vbus		= NULL,
 	.mode		= MV_USB_MODE_OTG,
 	.otg_force_a_bus_req = 1,
-	.phy_init	= pxa_usb_phy_init,
-	.phy_deinit	= pxa_usb_phy_deinit,
 	.set_vbus	= NULL,
 };
 #endif
@@ -198,19 +201,24 @@ static void __init ttc_dkb_init(void)
 	pxa910_add_twsi(0, NULL, ARRAY_AND_SIZE(ttc_dkb_i2c_info));
 	platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
 
+#ifdef CONFIG_USB_SUPPORT
+	pxa_register_device(&pxa910_device_u2ophy, &ttc_usb_phy_pdata,
+				sizeof(ttc_usb_phy_pdata));
+#endif
+
 #ifdef CONFIG_USB_MV_UDC
-	pxa168_device_u2o.dev.platform_data = &ttc_usb_pdata;
-	platform_device_register(&pxa168_device_u2o);
+	pxa_register_device(&pxa910_device_u2o, &ttc_usb_pdata,
+				sizeof(ttc_usb_pdata));
 #endif
 
 #ifdef CONFIG_USB_EHCI_MV_U2O
-	pxa168_device_u2oehci.dev.platform_data = &ttc_usb_pdata;
-	platform_device_register(&pxa168_device_u2oehci);
+	pxa_register_device(&pxa910_device_u2oehci, &ttc_usb_pdata,
+				sizeof(ttc_usb_pdata));
 #endif
 
 #ifdef CONFIG_USB_MV_OTG
-	pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata;
-	platform_device_register(&pxa168_device_u2ootg);
+	pxa_register_device(&pxa910_device_u2ootg, &ttc_usb_pdata,
+				sizeof(ttc_usb_pdata));
 #endif
 }
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 09/16] arm: mmp: remove the usb phy setting
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (7 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 08/16] arm: ttc_dkb: add usb support Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 10/16] arm: mmp: remove usb devices from pxa168 Chao Xie
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

phy setting are formatted into a phy driver at drivers/usb/phy,
we do not need do the setting in SOC files.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 arch/arm/mach-mmp/devices.c               |  278 -----------------------------
 arch/arm/mach-mmp/include/mach/regs-usb.h |  253 --------------------------
 2 files changed, 0 insertions(+), 531 deletions(-)
 delete mode 100644 arch/arm/mach-mmp/include/mach/regs-usb.h

diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c
index dd2d8b1..af341e5 100644
--- a/arch/arm/mach-mmp/devices.c
+++ b/arch/arm/mach-mmp/devices.c
@@ -15,7 +15,6 @@
 #include <mach/irqs.h>
 #include <mach/devices.h>
 #include <mach/cputype.h>
-#include <mach/regs-usb.h>
 
 int __init pxa_register_device(struct pxa_device_desc *desc,
 				void *data, size_t size)
@@ -72,280 +71,3 @@ int __init pxa_register_device(struct pxa_device_desc *desc,
 	return platform_device_add(pdev);
 }
 
-#if defined(CONFIG_USB) || defined(CONFIG_USB_GADGET)
-
-/*****************************************************************************
- * The registers read/write routines
- *****************************************************************************/
-
-static unsigned int u2o_get(void __iomem *base, unsigned int offset)
-{
-	return readl_relaxed(base + offset);
-}
-
-static void u2o_set(void __iomem *base, unsigned int offset,
-		unsigned int value)
-{
-	u32 reg;
-
-	reg = readl_relaxed(base + offset);
-	reg |= value;
-	writel_relaxed(reg, base + offset);
-	readl_relaxed(base + offset);
-}
-
-static void u2o_clear(void __iomem *base, unsigned int offset,
-		unsigned int value)
-{
-	u32 reg;
-
-	reg = readl_relaxed(base + offset);
-	reg &= ~value;
-	writel_relaxed(reg, base + offset);
-	readl_relaxed(base + offset);
-}
-
-static void u2o_write(void __iomem *base, unsigned int offset,
-		unsigned int value)
-{
-	writel_relaxed(value, base + offset);
-	readl_relaxed(base + offset);
-}
-
-#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV)
-
-#if defined(CONFIG_CPU_PXA910) || defined(CONFIG_CPU_PXA168)
-
-static DEFINE_MUTEX(phy_lock);
-static int phy_init_cnt;
-
-static int usb_phy_init_internal(void __iomem *base)
-{
-	int loops;
-
-	pr_info("Init usb phy!!!\n");
-
-	/* Initialize the USB PHY power */
-	if (cpu_is_pxa910()) {
-		u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
-			| (1<<UTMI_CTRL_PU_REF_SHIFT));
-	}
-
-	u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
-	u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
-
-	/* UTMI_PLL settings */
-	u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
-		| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
-		| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
-		| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
-
-	u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
-		| 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
-		| 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
-		| 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
-
-	/* UTMI_TX */
-	u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
-		| UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
-		| UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
-		| UTMI_TX_AMP_MASK);
-	u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
-		| 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
-		| 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
-
-	/* UTMI_RX */
-	u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
-		| UTMI_REG_SQ_LENGTH_MASK);
-	u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
-		| 2<<UTMI_REG_SQ_LENGTH_SHIFT);
-
-	/* UTMI_IVREF */
-	if (cpu_is_pxa168())
-		/* fixing Microsoft Altair board interface with NEC hub issue -
-		 * Set UTMI_IVREF from 0x4a3 to 0x4bf */
-		u2o_write(base, UTMI_IVREF, 0x4bf);
-
-	/* toggle VCOCAL_START bit of UTMI_PLL */
-	udelay(200);
-	u2o_set(base, UTMI_PLL, VCOCAL_START);
-	udelay(40);
-	u2o_clear(base, UTMI_PLL, VCOCAL_START);
-
-	/* toggle REG_RCAL_START bit of UTMI_TX */
-	udelay(400);
-	u2o_set(base, UTMI_TX, REG_RCAL_START);
-	udelay(40);
-	u2o_clear(base, UTMI_TX, REG_RCAL_START);
-	udelay(400);
-
-	/* Make sure PHY PLL is ready */
-	loops = 0;
-	while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
-		mdelay(1);
-		loops++;
-		if (loops > 100) {
-			printk(KERN_WARNING "calibrate timeout, UTMI_PLL %x\n",
-				u2o_get(base, UTMI_PLL));
-			break;
-		}
-	}
-
-	if (cpu_is_pxa168()) {
-		u2o_set(base, UTMI_RESERVE, 1 << 5);
-		/* Turn on UTMI PHY OTG extension */
-		u2o_write(base, UTMI_OTG_ADDON, 1);
-	}
-
-	return 0;
-}
-
-static int usb_phy_deinit_internal(void __iomem *base)
-{
-	pr_info("Deinit usb phy!!!\n");
-
-	if (cpu_is_pxa168())
-		u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
-
-	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
-	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
-	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
-	u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
-	u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
-
-	return 0;
-}
-
-int pxa_usb_phy_init(void __iomem *phy_reg)
-{
-	mutex_lock(&phy_lock);
-	if (phy_init_cnt++ == 0)
-		usb_phy_init_internal(phy_reg);
-	mutex_unlock(&phy_lock);
-	return 0;
-}
-
-void pxa_usb_phy_deinit(void __iomem *phy_reg)
-{
-	WARN_ON(phy_init_cnt == 0);
-
-	mutex_lock(&phy_lock);
-	if (--phy_init_cnt == 0)
-		usb_phy_deinit_internal(phy_reg);
-	mutex_unlock(&phy_lock);
-}
-#endif
-#endif
-#endif
-
-#ifdef CONFIG_USB_SUPPORT
-static u64 usb_dma_mask = ~(u32)0;
-
-#ifdef CONFIG_USB_MV_UDC
-struct resource pxa168_u2o_resources[] = {
-	/* regbase */
-	[0] = {
-		.start	= PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
-		.end	= PXA168_U2O_REGBASE + USB_REG_RANGE,
-		.flags	= IORESOURCE_MEM,
-		.name	= "capregs",
-	},
-	/* phybase */
-	[1] = {
-		.start	= PXA168_U2O_PHYBASE,
-		.end	= PXA168_U2O_PHYBASE + USB_PHY_RANGE,
-		.flags	= IORESOURCE_MEM,
-		.name	= "phyregs",
-	},
-	[2] = {
-		.start	= IRQ_PXA168_USB1,
-		.end	= IRQ_PXA168_USB1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device pxa168_device_u2o = {
-	.name		= "mv-udc",
-	.id		= -1,
-	.resource	= pxa168_u2o_resources,
-	.num_resources	= ARRAY_SIZE(pxa168_u2o_resources),
-	.dev		=  {
-		.dma_mask	= &usb_dma_mask,
-		.coherent_dma_mask = 0xffffffff,
-	}
-};
-#endif /* CONFIG_USB_MV_UDC */
-
-#ifdef CONFIG_USB_EHCI_MV_U2O
-struct resource pxa168_u2oehci_resources[] = {
-	/* regbase */
-	[0] = {
-		.start	= PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
-		.end	= PXA168_U2O_REGBASE + USB_REG_RANGE,
-		.flags	= IORESOURCE_MEM,
-		.name	= "capregs",
-	},
-	/* phybase */
-	[1] = {
-		.start	= PXA168_U2O_PHYBASE,
-		.end	= PXA168_U2O_PHYBASE + USB_PHY_RANGE,
-		.flags	= IORESOURCE_MEM,
-		.name	= "phyregs",
-	},
-	[2] = {
-		.start	= IRQ_PXA168_USB1,
-		.end	= IRQ_PXA168_USB1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device pxa168_device_u2oehci = {
-	.name		= "pxa-u2oehci",
-	.id		= -1,
-	.dev		= {
-		.dma_mask		= &usb_dma_mask,
-		.coherent_dma_mask	= 0xffffffff,
-	},
-
-	.num_resources	= ARRAY_SIZE(pxa168_u2oehci_resources),
-	.resource	= pxa168_u2oehci_resources,
-};
-#endif
-
-#if defined(CONFIG_USB_MV_OTG)
-struct resource pxa168_u2ootg_resources[] = {
-	/* regbase */
-	[0] = {
-		.start	= PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
-		.end	= PXA168_U2O_REGBASE + USB_REG_RANGE,
-		.flags	= IORESOURCE_MEM,
-		.name	= "capregs",
-	},
-	/* phybase */
-	[1] = {
-		.start	= PXA168_U2O_PHYBASE,
-		.end	= PXA168_U2O_PHYBASE + USB_PHY_RANGE,
-		.flags	= IORESOURCE_MEM,
-		.name	= "phyregs",
-	},
-	[2] = {
-		.start	= IRQ_PXA168_USB1,
-		.end	= IRQ_PXA168_USB1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device pxa168_device_u2ootg = {
-	.name		= "mv-otg",
-	.id		= -1,
-	.dev  = {
-		.dma_mask          = &usb_dma_mask,
-		.coherent_dma_mask = 0xffffffff,
-	},
-
-	.num_resources	= ARRAY_SIZE(pxa168_u2ootg_resources),
-	.resource      = pxa168_u2ootg_resources,
-};
-#endif /* CONFIG_USB_MV_OTG */
-
-#endif
diff --git a/arch/arm/mach-mmp/include/mach/regs-usb.h b/arch/arm/mach-mmp/include/mach/regs-usb.h
deleted file mode 100644
index b047bf4..0000000
--- a/arch/arm/mach-mmp/include/mach/regs-usb.h
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
- *
- * 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 __ASM_ARCH_REGS_USB_H
-#define __ASM_ARCH_REGS_USB_H
-
-#define PXA168_U2O_REGBASE	(0xd4208000)
-#define PXA168_U2O_PHYBASE	(0xd4207000)
-
-#define PXA168_U2H_REGBASE      (0xd4209000)
-#define PXA168_U2H_PHYBASE      (0xd4206000)
-
-#define MMP3_HSIC1_REGBASE	(0xf0001000)
-#define MMP3_HSIC1_PHYBASE	(0xf0001800)
-
-#define MMP3_HSIC2_REGBASE	(0xf0002000)
-#define MMP3_HSIC2_PHYBASE	(0xf0002800)
-
-#define MMP3_FSIC_REGBASE	(0xf0003000)
-#define MMP3_FSIC_PHYBASE	(0xf0003800)
-
-
-#define USB_REG_RANGE		(0x1ff)
-#define USB_PHY_RANGE		(0xff)
-
-/* registers */
-#define U2x_CAPREGS_OFFSET       0x100
-
-/* phy regs */
-#define UTMI_REVISION		0x0
-#define UTMI_CTRL		0x4
-#define UTMI_PLL		0x8
-#define UTMI_TX			0xc
-#define UTMI_RX			0x10
-#define UTMI_IVREF		0x14
-#define UTMI_T0			0x18
-#define UTMI_T1			0x1c
-#define UTMI_T2			0x20
-#define UTMI_T3			0x24
-#define UTMI_T4			0x28
-#define UTMI_T5			0x2c
-#define UTMI_RESERVE		0x30
-#define UTMI_USB_INT		0x34
-#define UTMI_DBG_CTL		0x38
-#define UTMI_OTG_ADDON		0x3c
-
-/* For UTMICTRL Register */
-#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
-/* pxa168 */
-#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
-#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
-#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
-#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
-
-#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
-#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT		28
-#define UTMI_CTRL_PU_REF_SHIFT			20
-#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
-#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
-#define UTMI_CTRL_PWR_UP_SHIFT                  0
-
-/* For UTMI_PLL Register */
-#define UTMI_PLL_PLLCALI12_SHIFT		29
-#define UTMI_PLL_PLLCALI12_MASK			(0x3 << 29)
-
-#define UTMI_PLL_PLLVDD18_SHIFT			27
-#define UTMI_PLL_PLLVDD18_MASK			(0x3 << 27)
-
-#define UTMI_PLL_PLLVDD12_SHIFT			25
-#define UTMI_PLL_PLLVDD12_MASK			(0x3 << 25)
-
-#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
-#define CLK_BLK_EN                              (0x1 << 24)
-#define PLL_READY                               (0x1 << 23)
-#define KVCO_EXT                                (0x1 << 22)
-#define VCOCAL_START                            (0x1 << 21)
-
-#define UTMI_PLL_KVCO_SHIFT			15
-#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
-
-#define UTMI_PLL_ICP_SHIFT			12
-#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
-
-#define UTMI_PLL_FBDIV_SHIFT                    4
-#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
-
-#define UTMI_PLL_REFDIV_SHIFT                   0
-#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
-
-/* For UTMI_TX Register */
-#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT		27
-#define UTMI_TX_REG_EXT_FS_RCAL_MASK		(0xf << 27)
-
-#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT	26
-#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK		(0x1 << 26)
-
-#define UTMI_TX_TXVDD12_SHIFT                   22
-#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
-
-#define UTMI_TX_CK60_PHSEL_SHIFT                17
-#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
-
-#define UTMI_TX_IMPCAL_VTH_SHIFT                14
-#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
-
-#define REG_RCAL_START                          (0x1 << 12)
-
-#define UTMI_TX_LOW_VDD_EN_SHIFT                11
-
-#define UTMI_TX_AMP_SHIFT			0
-#define UTMI_TX_AMP_MASK			(0x7 << 0)
-
-/* For UTMI_RX Register */
-#define UTMI_REG_SQ_LENGTH_SHIFT                15
-#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
-
-#define UTMI_RX_SQ_THRESH_SHIFT                 4
-#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
-
-#define UTMI_OTG_ADDON_OTG_ON			(1 << 0)
-
-/* For MMP3 USB Phy */
-#define USB2_PLL_REG0		0x4
-#define USB2_PLL_REG1		0x8
-#define USB2_TX_REG0		0x10
-#define USB2_TX_REG1		0x14
-#define USB2_TX_REG2		0x18
-#define USB2_RX_REG0		0x20
-#define USB2_RX_REG1		0x24
-#define USB2_RX_REG2		0x28
-#define USB2_ANA_REG0		0x30
-#define USB2_ANA_REG1		0x34
-#define USB2_ANA_REG2		0x38
-#define USB2_DIG_REG0		0x3C
-#define USB2_DIG_REG1		0x40
-#define USB2_DIG_REG2		0x44
-#define USB2_DIG_REG3		0x48
-#define USB2_TEST_REG0		0x4C
-#define USB2_TEST_REG1		0x50
-#define USB2_TEST_REG2		0x54
-#define USB2_CHARGER_REG0	0x58
-#define USB2_OTG_REG0		0x5C
-#define USB2_PHY_MON0		0x60
-#define USB2_RESETVE_REG0	0x64
-#define USB2_ICID_REG0		0x78
-#define USB2_ICID_REG1		0x7C
-
-/* USB2_PLL_REG0 */
-/* This is for Ax stepping */
-#define USB2_PLL_FBDIV_SHIFT_MMP3		0
-#define USB2_PLL_FBDIV_MASK_MMP3		(0xFF << 0)
-
-#define USB2_PLL_REFDIV_SHIFT_MMP3		8
-#define USB2_PLL_REFDIV_MASK_MMP3		(0xF << 8)
-
-#define USB2_PLL_VDD12_SHIFT_MMP3		12
-#define USB2_PLL_VDD18_SHIFT_MMP3		14
-
-/* This is for B0 stepping */
-#define USB2_PLL_FBDIV_SHIFT_MMP3_B0		0
-#define USB2_PLL_REFDIV_SHIFT_MMP3_B0		9
-#define USB2_PLL_VDD18_SHIFT_MMP3_B0		14
-#define USB2_PLL_FBDIV_MASK_MMP3_B0		0x01FF
-#define USB2_PLL_REFDIV_MASK_MMP3_B0		0x3E00
-
-#define USB2_PLL_CAL12_SHIFT_MMP3		0
-#define USB2_PLL_CALI12_MASK_MMP3		(0x3 << 0)
-
-#define USB2_PLL_VCOCAL_START_SHIFT_MMP3	2
-
-#define USB2_PLL_KVCO_SHIFT_MMP3		4
-#define USB2_PLL_KVCO_MASK_MMP3			(0x7<<4)
-
-#define USB2_PLL_ICP_SHIFT_MMP3			8
-#define USB2_PLL_ICP_MASK_MMP3			(0x7<<8)
-
-#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3		12
-
-#define USB2_PLL_PU_PLL_SHIFT_MMP3		13
-#define USB2_PLL_PU_PLL_MASK			(0x1 << 13)
-
-#define USB2_PLL_READY_MASK_MMP3		(0x1 << 15)
-
-/* USB2_TX_REG0 */
-#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3		8
-#define USB2_TX_IMPCAL_VTH_MASK_MMP3		(0x7 << 8)
-
-#define USB2_TX_RCAL_START_SHIFT_MMP3		13
-
-/* USB2_TX_REG1 */
-#define USB2_TX_CK60_PHSEL_SHIFT_MMP3		0
-#define USB2_TX_CK60_PHSEL_MASK_MMP3		(0xf << 0)
-
-#define USB2_TX_AMP_SHIFT_MMP3			4
-#define USB2_TX_AMP_MASK_MMP3			(0x7 << 4)
-
-#define USB2_TX_VDD12_SHIFT_MMP3		8
-#define USB2_TX_VDD12_MASK_MMP3			(0x3 << 8)
-
-/* USB2_TX_REG2 */
-#define USB2_TX_DRV_SLEWRATE_SHIFT		10
-
-/* USB2_RX_REG0 */
-#define USB2_RX_SQ_THRESH_SHIFT_MMP3		4
-#define USB2_RX_SQ_THRESH_MASK_MMP3		(0xf << 4)
-
-#define USB2_RX_SQ_LENGTH_SHIFT_MMP3		10
-#define USB2_RX_SQ_LENGTH_MASK_MMP3		(0x3 << 10)
-
-/* USB2_ANA_REG1*/
-#define USB2_ANA_PU_ANA_SHIFT_MMP3		14
-
-/* USB2_OTG_REG0 */
-#define USB2_OTG_PU_OTG_SHIFT_MMP3		3
-
-/* fsic registers */
-#define FSIC_MISC			0x4
-#define FSIC_INT			0x28
-#define FSIC_CTRL			0x30
-
-/* HSIC registers */
-#define HSIC_PAD_CTRL			0x4
-
-#define HSIC_CTRL			0x8
-#define HSIC_CTRL_HSIC_ENABLE		(1<<7)
-#define HSIC_CTRL_PLL_BYPASS		(1<<4)
-
-#define TEST_GRP_0			0xc
-#define TEST_GRP_1			0x10
-
-#define HSIC_INT			0x14
-#define HSIC_INT_READY_INT_EN		(1<<10)
-#define HSIC_INT_CONNECT_INT_EN		(1<<9)
-#define HSIC_INT_CORE_INT_EN		(1<<8)
-#define HSIC_INT_HS_READY		(1<<2)
-#define HSIC_INT_CONNECT		(1<<1)
-#define HSIC_INT_CORE			(1<<0)
-
-#define HSIC_CONFIG			0x18
-#define USBHSIC_CTRL			0x20
-
-#define HSIC_USB_CTRL			0x28
-#define HSIC_USB_CTRL_CLKEN		1
-#define	HSIC_USB_CLK_PHY		0x0
-#define HSIC_USB_CLK_PMU		0x1
-
-#endif /* __ASM_ARCH_PXA_U2O_H */
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 10/16] arm: mmp: remove usb devices from pxa168
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (8 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 09/16] arm: mmp: remove the usb phy setting Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 11/16] usb: phy: mv_usb2_phy: add externel chip support Chao Xie
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 arch/arm/mach-mmp/pxa168.c |   42 ------------------------------------------
 1 files changed, 0 insertions(+), 42 deletions(-)

diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index b7f074f..dd3a68b 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -28,7 +28,6 @@
 #include <mach/mfp.h>
 #include <linux/dma-mapping.h>
 #include <mach/pxa168.h>
-#include <mach/regs-usb.h>
 
 #include "common.h"
 #include "clock.h"
@@ -135,47 +134,6 @@ struct platform_device pxa168_device_gpio = {
 	.resource	= pxa168_resource_gpio,
 };
 
-struct resource pxa168_usb_host_resources[] = {
-	/* USB Host conroller register base */
-	[0] = {
-		.start	= PXA168_U2H_REGBASE + U2x_CAPREGS_OFFSET,
-		.end	= PXA168_U2H_REGBASE + USB_REG_RANGE,
-		.flags	= IORESOURCE_MEM,
-		.name	= "capregs",
-	},
-	/* USB PHY register base */
-	[1] = {
-		.start	= PXA168_U2H_PHYBASE,
-		.end	= PXA168_U2H_PHYBASE + USB_PHY_RANGE,
-		.flags	= IORESOURCE_MEM,
-		.name	= "phyregs",
-	},
-	[2] = {
-		.start	= IRQ_PXA168_USB2,
-		.end	= IRQ_PXA168_USB2,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32);
-struct platform_device pxa168_device_usb_host = {
-	.name = "pxa-sph",
-	.id   = -1,
-	.dev  = {
-		.dma_mask = &pxa168_usb_host_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-	},
-
-	.num_resources = ARRAY_SIZE(pxa168_usb_host_resources),
-	.resource      = pxa168_usb_host_resources,
-};
-
-int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata)
-{
-	pxa168_device_usb_host.dev.platform_data = pdata;
-	return platform_device_register(&pxa168_device_usb_host);
-}
-
 void pxa168_restart(char mode, const char *cmd)
 {
 	soft_restart(0xffff0000);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 11/16] usb: phy: mv_usb2_phy: add externel chip support
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (9 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 10/16] arm: mmp: remove usb devices from pxa168 Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 12/16] usb: gadget: mv_udc: add extern " Chao Xie
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

For the vbus and idpin detection. It may be completed by some
external chip, for example the pmic chip 88pm860x in driver/mfd
can do it.
Although the usb controller can detect the vbus and id pin, but
it need clock on and PHY enabled to detect the
vbus/idpin. It will increase the power.
Using the external chip to detect vbus/idpin can save the power.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 drivers/usb/phy/mv_usb2_phy.c        |   49 +++++++++++++++++++
 include/linux/platform_data/mv_usb.h |   15 ++----
 include/linux/usb/mv_usb2.h          |   85 ++++++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/phy/mv_usb2_phy.c b/drivers/usb/phy/mv_usb2_phy.c
index c2bccae..78ddeff 100644
--- a/drivers/usb/phy/mv_usb2_phy.c
+++ b/drivers/usb/phy/mv_usb2_phy.c
@@ -136,6 +136,53 @@ struct mv_usb2_phy *mv_usb2_get_phy(void)
 }
 EXPORT_SYMBOL(mv_usb2_get_phy);
 
+int mv_usb2_register_notifier(struct mv_usb2_phy *phy,
+		struct notifier_block *nb)
+{
+	int ret;
+
+	if (!phy)
+		return -ENODEV;
+
+	ret = atomic_notifier_chain_register(&phy->extern_chip.head, nb);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(mv_usb2_register_notifier);
+
+int mv_usb2_unregister_notifier(struct mv_usb2_phy *phy,
+		struct notifier_block *nb)
+{
+	int ret;
+
+	if (!phy)
+		return -ENODEV;
+
+	ret = atomic_notifier_chain_unregister(&phy->extern_chip.head, nb);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(mv_usb2_unregister_notifier);
+
+int mv_usb2_notify(struct mv_usb2_phy *phy, unsigned long val, void *v)
+{
+	int ret;
+
+	if (!phy)
+		return -ENODEV;
+
+	ret = atomic_notifier_call_chain(&phy->extern_chip.head, val, v);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(mv_usb2_notify);
+
 static unsigned int u2o_get(void __iomem *base, unsigned int offset)
 {
 	return readl(base + offset);
@@ -414,6 +461,8 @@ static int usb_phy_probe(struct platform_device *pdev)
 	mv_phy->init = usb_phy_init;
 	mv_phy->shutdown = usb_phy_shutdown;
 
+	ATOMIC_INIT_NOTIFIER_HEAD(&mv_phy->extern_chip.head);
+
 	platform_set_drvdata(pdev, mv_phy);
 
 	the_phy = mv_phy;
diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h
index fd3d1b4..dc25d60 100644
--- a/include/linux/platform_data/mv_usb.h
+++ b/include/linux/platform_data/mv_usb.h
@@ -28,16 +28,13 @@ enum {
 	VBUS_HIGH	= 1 << 0,
 };
 
-struct mv_usb_addon_irq {
-	unsigned int	irq;
-	int		(*poll)(void);
-};
-
+#define MV_USB_HAS_VBUS_DETECTION	(1 << 0)
+#define MV_USB_HAS_IDPIN_DETECTION	(1 << 1)
 struct mv_usb_platform_data {
 	unsigned int		clknum;
 	char			**clkname;
-	struct mv_usb_addon_irq	*id;	/* Only valid for OTG. ID pin change*/
-	struct mv_usb_addon_irq	*vbus;	/* valid for OTG/UDC. VBUS change*/
+
+	unsigned int		extern_attr;
 
 	/* only valid for HCD. OTG or Host only*/
 	unsigned int		mode;
@@ -45,9 +42,7 @@ struct mv_usb_platform_data {
 	/* This flag is used for that needs id pin checked by otg */
 	unsigned int    disable_otg_clock_gating:1;
 	/* Force a_bus_req to be asserted */
-	 unsigned int    otg_force_a_bus_req:1;
-
-	int	(*set_vbus)(unsigned int vbus);
+	unsigned int    otg_force_a_bus_req:1;
 };
 
 struct mv_usb_phy_platform_data {
diff --git a/include/linux/usb/mv_usb2.h b/include/linux/usb/mv_usb2.h
index 9744a97..f76fa06 100644
--- a/include/linux/usb/mv_usb2.h
+++ b/include/linux/usb/mv_usb2.h
@@ -17,6 +17,33 @@
 
 #include <linux/clk.h>
 
+enum {
+	EVENT_VBUS,
+	EVENT_ID,
+};
+
+struct pxa_usb_vbus_ops {
+	int (*get_vbus)(unsigned int *level);
+	int (*set_vbus)(unsigned int level);
+	int (*init)(void);
+};
+
+struct pxa_usb_idpin_ops {
+	int (*get_idpin)(unsigned int *level);
+	int (*init)(void);
+};
+
+struct pxa_usb_extern_ops {
+	struct pxa_usb_vbus_ops		vbus;
+	struct pxa_usb_idpin_ops	idpin;
+};
+
+struct mv_usb2_extern_chip {
+	unsigned int id;
+	struct pxa_usb_extern_ops ops;
+	struct atomic_notifier_head head;
+};
+
 struct mv_usb2_phy {
 	struct platform_device	*pdev;
 	struct mutex		phy_lock;
@@ -26,6 +53,8 @@ struct mv_usb2_phy {
 	struct clk		**clks;
 	unsigned int		clks_num;
 
+	struct mv_usb2_extern_chip extern_chip;
+
 	int	(*init)(struct mv_usb2_phy *mv_phy);
 	void	(*shutdown)(struct mv_usb2_phy *mv_phy);
 };
@@ -34,10 +63,66 @@ struct mv_usb2_phy {
 
 extern struct mv_usb2_phy *mv_usb2_get_phy(void);
 
+#define mv_usb2_has_extern_call(phy, o, f, arg...)( \
+{ \
+	int ret;					\
+	ret = (!phy ? 0 : ((phy->extern_chip.ops.o.f) ?	\
+		1 : 0));				\
+	ret;						\
+} \
+)
+
+#define mv_usb2_extern_call(phy, o, f, args...)( \
+{ \
+	int ret;						\
+	ret = (!phy ? -ENODEV : ((phy->extern_chip.ops.o.f) ?	\
+		phy->extern_chip.ops.o.f(args) : -ENOIOCTLCMD));\
+	ret;							\
+} \
+)
+
+#define mv_usb2_set_extern_call(phy, o, f, p)( \
+{ \
+	int ret;							\
+	ret = !phy ? -ENODEV : ((phy->extern_chip.ops.o.f) ?		\
+		-EINVAL : ({phy->extern_chip.ops.o.f = p; 0; }));	\
+	ret;								\
+} \
+)
+
+extern int mv_usb2_register_notifier(struct mv_usb2_phy *phy,
+					struct notifier_block *nb);
+extern int mv_usb2_unregister_notifier(struct mv_usb2_phy *phy,
+					struct notifier_block *nb);
+extern int mv_usb2_notify(struct mv_usb2_phy *phy, unsigned long val, void *v);
+
 #else
 
 struct mv_usb2_phy *mv_usb2_get_phy(void) { return NULL; }
 
+#define mv_usb2_has_extern_call(phy, o, f, arg...)(0)
+
+#define mv_usb2_extern_call(phy, o, f, args...)(0)
+
+#define mv_usb2_set_extern_call(phy, o, f, p)(0)
+
+int mv_usb2_register_notifier(struct mv_usb2_phy *phy,
+					struct notifier_block *nb)
+{
+	return -EINVAL;
+}
+
+int mv_usb2_unregister_notifier(struct mv_usb2_phy *phy,
+					struct notifier_block *nb)
+{
+	return -EINVAL;
+}
+
+int mv_usb2_notify(struct mv_usb2_phy *phy, unsigned long val, void *v)
+{
+	return 0;
+}
+
 #endif
 
 #endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 12/16] usb: gadget: mv_udc: add extern chip support
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (10 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 11/16] usb: phy: mv_usb2_phy: add externel chip support Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 13/16] usb: ehci: ehci-mv: " Chao Xie
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Because arch-mmp will make use of irq domain for irq
allocation, the irqs allocated for PMIC is dynamical.
The vbus/idpin irqs from PMIC can not be passed by platform data.
Using the extern chip APIs provides by PHY driver can solve this
problem.
Marvell usb PHY driver provides a middle layer.
The PMIC usb drivers will help to register the callbacks in the
marvell usb PHY driver.
udc/otg/ehci driver will call the callbacks.
Then we do not need pass the information in platform data. It will
remove another block in the way of enabling device tree for usb.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 drivers/usb/gadget/mv_udc.h      |    3 ++
 drivers/usb/gadget/mv_udc_core.c |   47 ++++++++++++++++++++++---------------
 2 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index 4851b2b..50ae7c7 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -178,6 +178,9 @@ struct mv_udc {
 	struct platform_device		*dev;
 	int				irq;
 
+	unsigned int			extern_attr;
+	struct notifier_block		notifier;
+
 	struct mv_cap_regs __iomem	*cap_regs;
 	struct mv_op_regs __iomem	*op_regs;
 	unsigned int			max_eps;
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 76fcfc7..2e5907f 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -2077,27 +2077,30 @@ static irqreturn_t mv_udc_irq(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t mv_udc_vbus_irq(int irq, void *dev)
+static int mv_udc_vbus_notifier_call(struct notifier_block *nb,
+				unsigned long val, void *v)
 {
-	struct mv_udc *udc = (struct mv_udc *)dev;
+	struct mv_udc *udc = container_of(nb, struct mv_udc, notifier);
 
 	/* polling VBUS and init phy may cause too much time*/
-	if (udc->qwork)
+	if (udc->qwork && val == EVENT_VBUS)
 		queue_work(udc->qwork, &udc->vbus_work);
 
-	return IRQ_HANDLED;
+	return 0;
 }
 
 static void mv_udc_vbus_work(struct work_struct *work)
 {
 	struct mv_udc *udc;
-	unsigned int vbus;
+	unsigned int vbus = VBUS_LOW;
 
 	udc = container_of(work, struct mv_udc, vbus_work);
-	if (!udc->pdata->vbus)
+	if (!(udc->extern_attr & MV_USB_HAS_VBUS_DETECTION))
+		return;
+
+	if (mv_usb2_extern_call(udc->phy, vbus, get_vbus, &vbus))
 		return;
 
-	vbus = udc->pdata->vbus->poll();
 	dev_info(&udc->dev->dev, "vbus is %d\n", vbus);
 
 	if (vbus == VBUS_HIGH)
@@ -2124,6 +2127,9 @@ static int mv_udc_remove(struct platform_device *pdev)
 
 	usb_del_gadget_udc(&udc->gadget);
 
+	if (udc->extern_attr & MV_USB_HAS_VBUS_DETECTION)
+		mv_usb2_unregister_notifier(udc->phy, &udc->notifier);
+
 	if (udc->qwork) {
 		flush_workqueue(udc->qwork);
 		destroy_workqueue(udc->qwork);
@@ -2169,6 +2175,7 @@ static int mv_udc_probe(struct platform_device *pdev)
 	}
 
 	udc->done = &release_done;
+	udc->extern_attr = pdata->extern_attr;
 	udc->pdata = pdev->dev.platform_data;
 	spin_lock_init(&udc->lock);
 
@@ -2319,17 +2326,8 @@ static int mv_udc_probe(struct platform_device *pdev)
 	/* VBUS detect: we can disable/enable clock on demand.*/
 	if (udc->transceiver)
 		udc->clock_gating = 1;
-	else if (pdata->vbus) {
+	else if (udc->extern_attr & MV_USB_HAS_VBUS_DETECTION) {
 		udc->clock_gating = 1;
-		retval = devm_request_threaded_irq(&pdev->dev,
-				pdata->vbus->irq, NULL,
-				mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
-		if (retval) {
-			dev_info(&pdev->dev,
-				"Can not request irq for VBUS, "
-				"disable clock gating\n");
-			udc->clock_gating = 0;
-		}
 
 		udc->qwork = create_singlethread_workqueue("mv_udc_queue");
 		if (!udc->qwork) {
@@ -2339,6 +2337,8 @@ static int mv_udc_probe(struct platform_device *pdev)
 		}
 
 		INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
+		udc->notifier.notifier_call = mv_udc_vbus_notifier_call;
+		mv_usb2_register_notifier(udc->phy, &udc->notifier);
 	}
 
 	/*
@@ -2362,6 +2362,9 @@ static int mv_udc_probe(struct platform_device *pdev)
 	return 0;
 
 err_create_workqueue:
+	if (!udc->transceiver
+		&& (udc->extern_attr & MV_USB_HAS_VBUS_DETECTION))
+		mv_usb2_unregister_notifier(udc->phy, &udc->notifier);
 	destroy_workqueue(udc->qwork);
 err_unregister:
 	device_unregister(&udc->gadget.dev);
@@ -2380,6 +2383,7 @@ err_disable_clock:
 static int mv_udc_suspend(struct device *dev)
 {
 	struct mv_udc *udc;
+	unsigned int vbus;
 
 	udc = dev_get_drvdata(dev);
 
@@ -2387,11 +2391,16 @@ static int mv_udc_suspend(struct device *dev)
 	if (udc->transceiver)
 		return 0;
 
-	if (udc->pdata->vbus && udc->pdata->vbus->poll)
-		if (udc->pdata->vbus->poll() == VBUS_HIGH) {
+	if ((udc->extern_attr & MV_USB_HAS_VBUS_DETECTION) &&
+		mv_usb2_has_extern_call(udc->phy, vbus, get_vbus)) {
+		if (mv_usb2_extern_call(udc->phy, vbus, get_vbus, &vbus))
+			return -EAGAIN;
+
+		if (vbus == VBUS_HIGH) {
 			dev_info(&udc->dev->dev, "USB cable is connected!\n");
 			return -EAGAIN;
 		}
+	}
 
 	/*
 	 * only cable is unplugged, udc can suspend.
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 13/16] usb: ehci: ehci-mv: add extern chip support
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (11 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 12/16] usb: gadget: mv_udc: add extern " Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 14/16] usb: otg: mv_otg: " Chao Xie
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

It does the similar things as what we do for udc driver.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
---
 drivers/usb/host/ehci-mv.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index be504fd..171e145 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -256,8 +256,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
 		goto err_disable_clk;
 #endif
 	} else {
-		if (pdata->set_vbus)
-			pdata->set_vbus(1);
+		if (mv_usb2_has_extern_call(ehci_mv->mvphy, vbus, set_vbus))
+			mv_usb2_extern_call(ehci_mv->mvphy, vbus, set_vbus, 1);
 
 		retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
 		if (retval) {
@@ -275,8 +275,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
 	return 0;
 
 err_set_vbus:
-	if (pdata->set_vbus)
-		pdata->set_vbus(0);
+	if (mv_usb2_has_extern_call(ehci_mv->mvphy, vbus, set_vbus))
+		mv_usb2_extern_call(ehci_mv->mvphy, vbus, set_vbus, 0);
 err_disable_clk:
 	mv_ehci_disable(ehci_mv);
 err_clear_drvdata:
@@ -299,8 +299,8 @@ static int mv_ehci_remove(struct platform_device *pdev)
 		otg_set_host(ehci_mv->otg->otg, NULL);
 
 	if (ehci_mv->mode == MV_USB_MODE_HOST) {
-		if (ehci_mv->pdata->set_vbus)
-			ehci_mv->pdata->set_vbus(0);
+		if (mv_usb2_has_extern_call(ehci_mv->mvphy, vbus, set_vbus))
+			mv_usb2_extern_call(ehci_mv->mvphy, vbus, set_vbus, 1);
 
 		mv_ehci_disable(ehci_mv);
 	}
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 14/16] usb: otg: mv_otg: add extern chip support
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (12 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 13/16] usb: ehci: ehci-mv: " Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 15/16] arm: mmp: add extern chip support for brownstone Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 16/16] arm: mmp: add extern chip support for ttc_dkb Chao Xie
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

It does the similar things as what we do for udc driver.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 drivers/usb/otg/mv_otg.c |   63 ++++++++++++++++++++-------------------------
 drivers/usb/otg/mv_otg.h |    3 ++
 2 files changed, 31 insertions(+), 35 deletions(-)

diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
index 44ddf25..d2e38a6 100644
--- a/drivers/usb/otg/mv_otg.c
+++ b/drivers/usb/otg/mv_otg.c
@@ -59,10 +59,10 @@ static char *state_string[] = {
 static int mv_otg_set_vbus(struct usb_otg *otg, bool on)
 {
 	struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy);
-	if (mvotg->pdata->set_vbus == NULL)
+	if (!mv_usb2_has_extern_call(mvotg->mvphy, vbus, set_vbus))
 		return -ENODEV;
 
-	return mvotg->pdata->set_vbus(on);
+	return mv_usb2_extern_call(mvotg->mvphy, vbus, set_vbus, on);
 }
 
 static int mv_otg_set_host(struct usb_otg *otg,
@@ -184,14 +184,14 @@ static void mv_otg_init_irq(struct mv_otg *mvotg)
 	mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID
 	    | OTGSC_INTSTS_A_VBUS_VALID;
 
-	if (mvotg->pdata->vbus == NULL) {
+	if (!(mvotg->extern_attr & MV_USB_HAS_VBUS_DETECTION)) {
 		mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID
 		    | OTGSC_INTR_B_SESSION_END;
 		mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID
 		    | OTGSC_INTSTS_B_SESSION_END;
 	}
 
-	if (mvotg->pdata->id == NULL) {
+	if (!(mvotg->extern_attr & MV_USB_HAS_IDPIN_DETECTION)) {
 		mvotg->irq_en |= OTGSC_INTR_USB_ID;
 		mvotg->irq_status |= OTGSC_INTSTS_USB_ID;
 	}
@@ -306,11 +306,14 @@ static void mv_otg_update_inputs(struct mv_otg *mvotg)
 {
 	struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
 	u32 otgsc;
+	unsigned int vbus, idpin;
 
 	otgsc = readl(&mvotg->op_regs->otgsc);
 
-	if (mvotg->pdata->vbus) {
-		if (mvotg->pdata->vbus->poll() == VBUS_HIGH) {
+	if (mvotg->extern_attr & MV_USB_HAS_VBUS_DETECTION) {
+		if (mv_usb2_extern_call(mvotg->mvphy, vbus, get_vbus, &vbus))
+			return;
+		if (vbus == VBUS_HIGH) {
 			otg_ctrl->b_sess_vld = 1;
 			otg_ctrl->b_sess_end = 0;
 		} else {
@@ -322,8 +325,11 @@ static void mv_otg_update_inputs(struct mv_otg *mvotg)
 		otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END);
 	}
 
-	if (mvotg->pdata->id)
-		otg_ctrl->id = !!mvotg->pdata->id->poll();
+	if (mvotg->extern_attr & MV_USB_HAS_IDPIN_DETECTION) {
+		if (mv_usb2_extern_call(mvotg->mvphy, idpin, get_idpin, &idpin))
+			return;
+		otg_ctrl->id = !!idpin;
+	}
 	else
 		otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID);
 
@@ -505,7 +511,7 @@ static irqreturn_t mv_otg_irq(int irq, void *dev)
 	 * if we have vbus, then the vbus detection for B-device
 	 * will be done by mv_otg_inputs_irq().
 	 */
-	if (mvotg->pdata->vbus)
+	if (mvotg->extern_attr & MV_USB_HAS_VBUS_DETECTION)
 		if ((otgsc & OTGSC_STS_USB_ID) &&
 		    !(otgsc & OTGSC_INTSTS_USB_ID))
 			return IRQ_NONE;
@@ -518,9 +524,10 @@ static irqreturn_t mv_otg_irq(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t mv_otg_inputs_irq(int irq, void *dev)
+static int mv_otg_notifier_call(struct notifier_block *nb,
+				unsigned long val, void *v)
 {
-	struct mv_otg *mvotg = dev;
+	struct mv_otg *mvotg = container_of(nb, struct mv_otg, notifier);
 
 	/* The clock may disabled at this time */
 	if (!mvotg->active) {
@@ -530,7 +537,7 @@ static irqreturn_t mv_otg_inputs_irq(int irq, void *dev)
 
 	mv_otg_run_state_machine(mvotg, 0);
 
-	return IRQ_HANDLED;
+	return 0;
 }
 
 static ssize_t
@@ -666,6 +673,10 @@ int mv_otg_remove(struct platform_device *pdev)
 
 	sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group);
 
+	if ((mvotg->extern_attr & MV_USB_HAS_VBUS_DETECTION) ||
+		(mvotg->extern_attr & MV_USB_HAS_IDPIN_DETECTION))
+		mv_usb2_unregister_notifier(mvotg->mvphy, &mvotg->notifier);
+
 	if (mvotg->qwork) {
 		flush_workqueue(mvotg->qwork);
 		destroy_workqueue(mvotg->qwork);
@@ -707,6 +718,7 @@ static int mv_otg_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, mvotg);
 
 	mvotg->pdev = pdev;
+	mvotg->extern_attr = pdata->extern_attr;
 	mvotg->pdata = pdata;
 
 	mvotg->clknum = pdata->clknum;
@@ -773,29 +785,10 @@ static int mv_otg_probe(struct platform_device *pdev)
 		(struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs
 			+ (readl(mvotg->cap_regs) & CAPLENGTH_MASK));
 
-	if (pdata->id) {
-		retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq,
-						NULL, mv_otg_inputs_irq,
-						IRQF_ONESHOT, "id", mvotg);
-		if (retval) {
-			dev_info(&pdev->dev,
-				 "Failed to request irq for ID\n");
-			pdata->id = NULL;
-		}
-	}
-
-	if (pdata->vbus) {
-		mvotg->clock_gating = 1;
-		retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq,
-						NULL, mv_otg_inputs_irq,
-						IRQF_ONESHOT, "vbus", mvotg);
-		if (retval) {
-			dev_info(&pdev->dev,
-				 "Failed to request irq for VBUS, "
-				 "disable clock gating\n");
-			mvotg->clock_gating = 0;
-			pdata->vbus = NULL;
-		}
+	if ((mvotg->extern_attr & MV_USB_HAS_VBUS_DETECTION) ||
+		(mvotg->extern_attr & MV_USB_HAS_IDPIN_DETECTION)) {
+		mvotg->notifier.notifier_call = mv_otg_notifier_call;
+		mv_usb2_register_notifier(mvotg->mvphy, &mvotg->notifier);
 	}
 
 	if (pdata->disable_otg_clock_gating)
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h
index 7b9629a..f5bc7dd 100644
--- a/drivers/usb/otg/mv_otg.h
+++ b/drivers/usb/otg/mv_otg.h
@@ -149,6 +149,9 @@ struct mv_otg {
 	u32 irq_status;
 	u32 irq_en;
 
+	unsigned int extern_attr;
+	struct notifier_block notifier;
+
 	struct delayed_work work;
 	struct workqueue_struct *qwork;
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 15/16] arm: mmp: add extern chip support for brownstone
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (13 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 14/16] usb: otg: mv_otg: " Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  2013-02-06  7:23 ` [V6 PATCH 16/16] arm: mmp: add extern chip support for ttc_dkb Chao Xie
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Change the board support for usb as extern chip is supported
in marvell usb PHY driver

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 arch/arm/mach-mmp/brownstone.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c
index 90c0340..3dcf38f 100644
--- a/arch/arm/mach-mmp/brownstone.c
+++ b/arch/arm/mach-mmp/brownstone.c
@@ -212,10 +212,8 @@ static struct mv_usb_phy_platform_data brownstone_usb_phy_pdata = {
 static struct mv_usb_platform_data brownstone_usb_pdata = {
 	.clknum		= 1,
 	.clkname	= mmp2_usb_clock_name,
-	.vbus		= NULL,
 	.mode		= MV_USB_MODE_OTG,
 	.otg_force_a_bus_req = 1,
-	.set_vbus	= NULL,
 };
 #endif
 #endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 16/16] arm: mmp: add extern chip support for ttc_dkb
  2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
                   ` (14 preceding siblings ...)
  2013-02-06  7:23 ` [V6 PATCH 15/16] arm: mmp: add extern chip support for brownstone Chao Xie
@ 2013-02-06  7:23 ` Chao Xie
  15 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Change the board support for usb as extern chip is supported
in marvell usb PHY driver.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
---
 arch/arm/mach-mmp/ttc_dkb.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 0962791..eb34608 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -172,10 +172,8 @@ static struct mv_usb_phy_platform_data ttc_usb_phy_pdata = {
 static struct mv_usb_platform_data ttc_usb_pdata = {
 	.clknum		= 1,
 	.clkname	= pxa910_usb_clock_name,
-	.vbus		= NULL,
 	.mode		= MV_USB_MODE_OTG,
 	.otg_force_a_bus_req = 1,
-	.set_vbus	= NULL,
 };
 #endif
 #endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-06  7:23 ` [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller Chao Xie
@ 2013-02-06  8:10   ` kishon
  2013-02-06  8:18     ` Chao Xie
  2013-02-06 14:42   ` Mark Rutland
  1 sibling, 1 reply; 25+ messages in thread
From: kishon @ 2013-02-06  8:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wednesday 06 February 2013 12:53 PM, Chao Xie wrote:
> The PHY is seperated from usb controller.
> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
> but PHY initialization may be different.
> the usb controller can support udc/otg/ehci, and for each of
> the mode, it need PHY to initialized before use the controller.
> Direclty writing the phy driver will make the usb controller
> driver to be simple and portable.
> The PHY driver will be used by marvell udc/otg/ehci.
>
> Signed-off-by: Chao Xie <chao.xie@marvell.com>
> ---
>   drivers/usb/phy/Kconfig              |    7 +
>   drivers/usb/phy/Makefile             |    1 +
>   drivers/usb/phy/mv_usb2_phy.c        |  454 ++++++++++++++++++++++++++++++++++
>   include/linux/platform_data/mv_usb.h |    9 +-
>   include/linux/usb/mv_usb2.h          |   43 ++++
>   5 files changed, 511 insertions(+), 3 deletions(-)
>   create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>   create mode 100644 include/linux/usb/mv_usb2.h
>
> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
> index 65217a5..5479760 100644
> --- a/drivers/usb/phy/Kconfig
> +++ b/drivers/usb/phy/Kconfig
> @@ -73,3 +73,10 @@ config SAMSUNG_USBPHY
>   	help
>   	  Enable this to support Samsung USB phy controller for samsung
>   	  SoCs.
> +
> +config MV_USB2_PHY
> +	tristate "Marvell USB 2.0 PHY Driver"
> +	depends on USB || USB_GADGET
> +	help
> +	  Enable this to support Marvell USB 2.0 phy driver for Marvell
> +	  SoC.
> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
> index b13faa1..3835316 100644
> --- a/drivers/usb/phy/Makefile
> +++ b/drivers/usb/phy/Makefile
> @@ -12,3 +12,4 @@ obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
>   obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
>   obj-$(CONFIG_USB_RCAR_PHY)		+= rcar-phy.o
>   obj-$(CONFIG_SAMSUNG_USBPHY)		+= samsung-usbphy.o
> +obj-$(CONFIG_MV_USB2_PHY)		+= mv_usb2_phy.o
> diff --git a/drivers/usb/phy/mv_usb2_phy.c b/drivers/usb/phy/mv_usb2_phy.c
> new file mode 100644
> index 0000000..c2bccae
> --- /dev/null
> +++ b/drivers/usb/phy/mv_usb2_phy.c
> @@ -0,0 +1,454 @@
> +/*
> + * Copyright (C) 2010 Google, Inc.
> + *
> + * Author:
> + *	Chao Xie <xiechao.mail@gmail.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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/resource.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/export.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/platform_data/mv_usb.h>
> +#include <linux/usb/mv_usb2.h>
> +
> +/* phy regs */
> +#define UTMI_REVISION		0x0
> +#define UTMI_CTRL		0x4
> +#define UTMI_PLL		0x8
> +#define UTMI_TX			0xc
> +#define UTMI_RX			0x10
> +#define UTMI_IVREF		0x14
> +#define UTMI_T0			0x18
> +#define UTMI_T1			0x1c
> +#define UTMI_T2			0x20
> +#define UTMI_T3			0x24
> +#define UTMI_T4			0x28
> +#define UTMI_T5			0x2c
> +#define UTMI_RESERVE		0x30
> +#define UTMI_USB_INT		0x34
> +#define UTMI_DBG_CTL		0x38
> +#define UTMI_OTG_ADDON		0x3c
> +
> +/* For UTMICTRL Register */
> +#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
> +/* pxa168 */
> +#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
> +#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
> +#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
> +#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
> +
> +#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
> +#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT		28
> +#define UTMI_CTRL_PU_REF_SHIFT			20
> +#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
> +#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
> +#define UTMI_CTRL_PWR_UP_SHIFT                  0
> +
> +/* For UTMI_PLL Register */
> +#define UTMI_PLL_PLLCALI12_SHIFT		29
> +#define UTMI_PLL_PLLCALI12_MASK			(0x3 << 29)
> +
> +#define UTMI_PLL_PLLVDD18_SHIFT			27
> +#define UTMI_PLL_PLLVDD18_MASK			(0x3 << 27)
> +
> +#define UTMI_PLL_PLLVDD12_SHIFT			25
> +#define UTMI_PLL_PLLVDD12_MASK			(0x3 << 25)
> +
> +#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
> +#define CLK_BLK_EN                              (0x1 << 24)
> +#define PLL_READY                               (0x1 << 23)
> +#define KVCO_EXT                                (0x1 << 22)
> +#define VCOCAL_START                            (0x1 << 21)
> +
> +#define UTMI_PLL_KVCO_SHIFT			15
> +#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
> +
> +#define UTMI_PLL_ICP_SHIFT			12
> +#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
> +
> +#define UTMI_PLL_FBDIV_SHIFT                    4
> +#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
> +
> +#define UTMI_PLL_REFDIV_SHIFT                   0
> +#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
> +
> +/* For UTMI_TX Register */
> +#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT		27
> +#define UTMI_TX_REG_EXT_FS_RCAL_MASK		(0xf << 27)
> +
> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT	26
> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK		(0x1 << 26)
> +
> +#define UTMI_TX_TXVDD12_SHIFT                   22
> +#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
> +
> +#define UTMI_TX_CK60_PHSEL_SHIFT                17
> +#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
> +
> +#define UTMI_TX_IMPCAL_VTH_SHIFT                14
> +#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
> +
> +#define REG_RCAL_START                          (0x1 << 12)
> +
> +#define UTMI_TX_LOW_VDD_EN_SHIFT                11
> +
> +#define UTMI_TX_AMP_SHIFT			0
> +#define UTMI_TX_AMP_MASK			(0x7 << 0)
> +
> +/* For UTMI_RX Register */
> +#define UTMI_REG_SQ_LENGTH_SHIFT                15
> +#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
> +
> +#define UTMI_RX_SQ_THRESH_SHIFT                 4
> +#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
> +
> +#define UTMI_OTG_ADDON_OTG_ON			(1 << 0)
> +
> +enum mv_usb2_phy_type {
> +	PXA168_USB,
> +	PXA910_USB,
> +	MMP2_USB,
> +};
> +
> +static struct mv_usb2_phy *the_phy;
> +
> +struct mv_usb2_phy *mv_usb2_get_phy(void)
> +{
> +	return the_phy;
> +}
> +EXPORT_SYMBOL(mv_usb2_get_phy);
> +
> +static unsigned int u2o_get(void __iomem *base, unsigned int offset)
> +{
> +	return readl(base + offset);
> +}
> +
> +static void u2o_set(void __iomem *base, unsigned int offset,
> +		unsigned int value)
> +{
> +	u32 reg;
> +
> +	reg = readl(base + offset);
> +	reg |= value;
> +	writel(reg, base + offset);
> +	readl(base + offset);
> +}
> +
> +static void u2o_clear(void __iomem *base, unsigned int offset,
> +		unsigned int value)
> +{
> +	u32 reg;
> +
> +	reg = readl(base + offset);
> +	reg &= ~value;
> +	writel(reg, base + offset);
> +	readl(base + offset);
> +}
> +
> +static void u2o_write(void __iomem *base, unsigned int offset,
> +		unsigned int value)
> +{
> +	writel(value, base + offset);
> +	readl(base + offset);
> +}
> +
> +static int _usb_phy_init(struct mv_usb2_phy *mv_phy)
> +{
> +	struct platform_device *pdev = mv_phy->pdev;
> +	unsigned int loops = 0;
> +	void __iomem *base = mv_phy->base;
> +
> +	dev_dbg(&pdev->dev, "phy init\n");
> +
> +	/* Initialize the USB PHY power */
> +	if (mv_phy->type == PXA910_USB) {
> +		u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
> +			| (1<<UTMI_CTRL_PU_REF_SHIFT));
> +	}
> +
> +	u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
> +	u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
> +
> +	/* UTMI_PLL settings */
> +	u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
> +		| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
> +		| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
> +		| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
> +
> +	u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
> +		| 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
> +		| 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
> +		| 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
> +
> +	/* UTMI_TX */
> +	u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
> +		| UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
> +		| UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
> +		| UTMI_TX_AMP_MASK);
> +	u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
> +		| 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
> +		| 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
> +
> +	/* UTMI_RX */
> +	u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
> +		| UTMI_REG_SQ_LENGTH_MASK);
> +	u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
> +		| 2<<UTMI_REG_SQ_LENGTH_SHIFT);
> +
> +	/* UTMI_IVREF */
> +	if (mv_phy->type == PXA168_USB)
> +		/* fixing Microsoft Altair board interface with NEC hub issue -
> +		 * Set UTMI_IVREF from 0x4a3 to 0x4bf */
> +		u2o_write(base, UTMI_IVREF, 0x4bf);
> +
> +	/* toggle VCOCAL_START bit of UTMI_PLL */
> +	udelay(200);
> +	u2o_set(base, UTMI_PLL, VCOCAL_START);
> +	udelay(40);
> +	u2o_clear(base, UTMI_PLL, VCOCAL_START);
> +
> +	/* toggle REG_RCAL_START bit of UTMI_TX */
> +	udelay(400);
> +	u2o_set(base, UTMI_TX, REG_RCAL_START);
> +	udelay(40);
> +	u2o_clear(base, UTMI_TX, REG_RCAL_START);
> +	udelay(400);
> +
> +	/* Make sure PHY PLL is ready */
> +	loops = 0;
> +	while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
> +		mdelay(1);
> +		loops++;
> +		if (loops > 100) {
> +			dev_warn(&pdev->dev, "calibrate timeout, UTMI_PLL %x\n",
> +				u2o_get(base, UTMI_PLL));
> +			break;
> +		}
> +	}
> +
> +	if (mv_phy->type == PXA168_USB) {
> +		u2o_set(base, UTMI_RESERVE, 1 << 5);
> +		/* Turn on UTMI PHY OTG extension */
> +		u2o_write(base, UTMI_OTG_ADDON, 1);
> +	}
> +
> +	return 0;
> +}
> +
> +static int _usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
> +{
> +	void __iomem *base = mv_phy->base;
> +
> +	if (mv_phy->type == PXA168_USB)
> +		u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
> +
> +	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
> +	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
> +	u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
> +	u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
> +	u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
> +
> +	return 0;
> +}
> +
> +static int usb_phy_init(struct mv_usb2_phy *mv_phy)
> +{
> +	int i = 0;
> +
> +	mutex_lock(&mv_phy->phy_lock);
> +	if (mv_phy->refcount++ == 0) {
> +		for (i = 0; i < mv_phy->clks_num; i++)
> +			clk_prepare_enable(mv_phy->clks[i]);
> +		_usb_phy_init(mv_phy);
> +	}
> +	mutex_unlock(&mv_phy->phy_lock);
> +	return 0;
> +}
> +
> +static void usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
> +{
> +	int i = 0;
> +
> +	mutex_lock(&mv_phy->phy_lock);
> +	if (mv_phy->refcount++ == 0) {
> +		_usb_phy_shutdown(mv_phy);
> +		for (i = 0; i < mv_phy->clks_num; i++)
> +			clk_disable_unprepare(mv_phy->clks[i]);
> +	}
> +	mutex_unlock(&mv_phy->phy_lock);
> +}
> +
> +static struct of_device_id usb_phy_dt_ids[] = {
> +	{ .compatible = "mrvl,pxa168-usb-phy",	.data = (void *)PXA168_USB},
> +	{ .compatible = "mrvl,pxa910-usb-phy",	.data = (void *)PXA910_USB},
> +	{ .compatible = "mrvl,mmp2-usb-phy",	.data = (void *)MMP2_USB},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);
> +
> +static int usb_phy_parse_dt(struct platform_device *pdev,
> +				struct mv_usb2_phy *mv_phy)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	const struct of_device_id *of_id =
> +			of_match_device(usb_phy_dt_ids, &pdev->dev);
> +	unsigned int clks_num;
> +	int i, ret;
> +	const char *clk_name;
> +
> +	if (!np)
> +		return 1;
> +
> +	clks_num = of_property_count_strings(np, "clocks");
> +	if (clks_num < 0) {
> +		dev_err(&pdev->dev, "failed to get clock number\n");
> +		return clks_num;
> +	}
> +
> +	mv_phy->clks = devm_kzalloc(&pdev->dev,
> +		sizeof(struct clk *) * clks_num, GFP_KERNEL);
> +	if (mv_phy->clks == NULL) {
> +		dev_err(&pdev->dev,
> +			"failed to allocate mempory for clocks");
> +		return -ENOMEM;
> +	}
> +
> +	for (i = 0; i < clks_num; i++) {
> +		ret = of_property_read_string_index(np, "clocks", i,
> +			&clk_name);
> +		if (ret) {
> +			dev_err(&pdev->dev, "failed to read clocks\n");
> +			return ret;
> +		}
> +		mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
> +		if (IS_ERR(mv_phy->clks[i])) {
> +			dev_err(&pdev->dev, "failed to get clock %s\n",
> +				clk_name);
> +			return PTR_ERR(mv_phy->clks[i]);
> +		}
> +	}
> +
> +	mv_phy->clks_num = clks_num;
> +	mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
> +
> +	return 0;
> +}
> +
> +static int usb_phy_probe(struct platform_device *pdev)
> +{
> +	struct mv_usb2_phy *mv_phy;
> +	struct resource *r;
> +	int ret, i;
> +
> +	mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
> +	if (mv_phy == NULL) {
> +		dev_err(&pdev->dev, "failed to allocate memory\n");
> +		return -ENOMEM;
> +	}
> +	mutex_init(&mv_phy->phy_lock);
> +
> +	ret = usb_phy_parse_dt(pdev, mv_phy);
> +	/* no CONFIG_OF */
> +	if (ret > 0) {
> +		struct mv_usb_phy_platform_data *pdata
> +				= pdev->dev.platform_data;
> +		const struct platform_device_id *id
> +				= platform_get_device_id(pdev);
> +
> +		if (pdata == NULL || id == NULL) {
> +			dev_err(&pdev->dev,
> +				"missing platform_data or id_entry\n");
> +			return -ENODEV;
> +		}
> +		mv_phy->type = (unsigned int)(id->driver_data);
> +		mv_phy->clks_num = pdata->clknum;
> +		mv_phy->clks = devm_kzalloc(&pdev->dev,
> +			sizeof(struct clk *) * mv_phy->clks_num, GFP_KERNEL);
> +		if (mv_phy->clks == NULL) {
> +			dev_err(&pdev->dev,
> +				"failed to allocate mempory for clocks");
> +			return -ENOMEM;
> +		}
> +		for (i = 0; i < mv_phy->clks_num; i++)
> +			mv_phy->clks[i] = devm_clk_get(&pdev->dev,
> +							pdata->clkname[i]);
> +			if (IS_ERR(mv_phy->clks[i])) {
> +				dev_err(&pdev->dev, "failed to get clock %s\n",
> +					pdata->clkname[i]);
> +				return PTR_ERR(mv_phy->clks[i]);
> +			}
> +	} else if (ret < 0) {
> +		dev_err(&pdev->dev, "error parse dt\n");
> +		return ret;
> +	}
> +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (r == NULL) {
> +		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
> +		return -ENODEV;
> +	}
> +	mv_phy->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
> +	if (mv_phy->base == NULL) {
> +		dev_err(&pdev->dev, "error map register base\n");
> +		return -EBUSY;
> +	}
> +	platform_set_drvdata(pdev, mv_phy);
> +	mv_phy->pdev = pdev;
> +	mv_phy->init = usb_phy_init;
> +	mv_phy->shutdown = usb_phy_shutdown;
> +
> +	platform_set_drvdata(pdev, mv_phy);
> +
> +	the_phy = mv_phy;

Is there any specific reason for not using the usb phy library?
Please use the APIs provided in drivers/usb/otg/otg.c.
These APIs will be moved to phy.c soon.

Thanks
Kishon

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-06  8:10   ` kishon
@ 2013-02-06  8:18     ` Chao Xie
  2013-02-06 10:35       ` kishon
  0 siblings, 1 reply; 25+ messages in thread
From: Chao Xie @ 2013-02-06  8:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 6, 2013 at 4:10 PM, kishon <kishon@ti.com> wrote:
> Hi,
>
>
> On Wednesday 06 February 2013 12:53 PM, Chao Xie wrote:
>>
>> The PHY is seperated from usb controller.
>> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
>> but PHY initialization may be different.
>> the usb controller can support udc/otg/ehci, and for each of
>> the mode, it need PHY to initialized before use the controller.
>> Direclty writing the phy driver will make the usb controller
>> driver to be simple and portable.
>> The PHY driver will be used by marvell udc/otg/ehci.
>>
>> Signed-off-by: Chao Xie <chao.xie@marvell.com>
>> ---
>>   drivers/usb/phy/Kconfig              |    7 +
>>   drivers/usb/phy/Makefile             |    1 +
>>   drivers/usb/phy/mv_usb2_phy.c        |  454
>> ++++++++++++++++++++++++++++++++++
>>   include/linux/platform_data/mv_usb.h |    9 +-
>>   include/linux/usb/mv_usb2.h          |   43 ++++
>>   5 files changed, 511 insertions(+), 3 deletions(-)
>>   create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>>   create mode 100644 include/linux/usb/mv_usb2.h
>>
>> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
>> index 65217a5..5479760 100644
>> --- a/drivers/usb/phy/Kconfig
>> +++ b/drivers/usb/phy/Kconfig
>> @@ -73,3 +73,10 @@ config SAMSUNG_USBPHY
>>         help
>>           Enable this to support Samsung USB phy controller for samsung
>>           SoCs.
>> +
>> +config MV_USB2_PHY
>> +       tristate "Marvell USB 2.0 PHY Driver"
>> +       depends on USB || USB_GADGET
>> +       help
>> +         Enable this to support Marvell USB 2.0 phy driver for Marvell
>> +         SoC.
>> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
>> index b13faa1..3835316 100644
>> --- a/drivers/usb/phy/Makefile
>> +++ b/drivers/usb/phy/Makefile
>> @@ -12,3 +12,4 @@ obj-$(CONFIG_MV_U3D_PHY)              += mv_u3d_phy.o
>>   obj-$(CONFIG_USB_EHCI_TEGRA)  += tegra_usb_phy.o
>>   obj-$(CONFIG_USB_RCAR_PHY)            += rcar-phy.o
>>   obj-$(CONFIG_SAMSUNG_USBPHY)          += samsung-usbphy.o
>> +obj-$(CONFIG_MV_USB2_PHY)              += mv_usb2_phy.o
>> diff --git a/drivers/usb/phy/mv_usb2_phy.c b/drivers/usb/phy/mv_usb2_phy.c
>> new file mode 100644
>> index 0000000..c2bccae
>> --- /dev/null
>> +++ b/drivers/usb/phy/mv_usb2_phy.c
>> @@ -0,0 +1,454 @@
>> +/*
>> + * Copyright (C) 2010 Google, Inc.
>> + *
>> + * Author:
>> + *     Chao Xie <xiechao.mail@gmail.com>
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * 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/resource.h>
>> +#include <linux/delay.h>
>> +#include <linux/slab.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/io.h>
>> +#include <linux/err.h>
>> +#include <linux/clk.h>
>> +#include <linux/export.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/platform_data/mv_usb.h>
>> +#include <linux/usb/mv_usb2.h>
>> +
>> +/* phy regs */
>> +#define UTMI_REVISION          0x0
>> +#define UTMI_CTRL              0x4
>> +#define UTMI_PLL               0x8
>> +#define UTMI_TX                        0xc
>> +#define UTMI_RX                        0x10
>> +#define UTMI_IVREF             0x14
>> +#define UTMI_T0                        0x18
>> +#define UTMI_T1                        0x1c
>> +#define UTMI_T2                        0x20
>> +#define UTMI_T3                        0x24
>> +#define UTMI_T4                        0x28
>> +#define UTMI_T5                        0x2c
>> +#define UTMI_RESERVE           0x30
>> +#define UTMI_USB_INT           0x34
>> +#define UTMI_DBG_CTL           0x38
>> +#define UTMI_OTG_ADDON         0x3c
>> +
>> +/* For UTMICTRL Register */
>> +#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
>> +/* pxa168 */
>> +#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
>> +#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
>> +#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
>> +#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
>> +
>> +#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
>> +#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT                28
>> +#define UTMI_CTRL_PU_REF_SHIFT                 20
>> +#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
>> +#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
>> +#define UTMI_CTRL_PWR_UP_SHIFT                  0
>> +
>> +/* For UTMI_PLL Register */
>> +#define UTMI_PLL_PLLCALI12_SHIFT               29
>> +#define UTMI_PLL_PLLCALI12_MASK                        (0x3 << 29)
>> +
>> +#define UTMI_PLL_PLLVDD18_SHIFT                        27
>> +#define UTMI_PLL_PLLVDD18_MASK                 (0x3 << 27)
>> +
>> +#define UTMI_PLL_PLLVDD12_SHIFT                        25
>> +#define UTMI_PLL_PLLVDD12_MASK                 (0x3 << 25)
>> +
>> +#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
>> +#define CLK_BLK_EN                              (0x1 << 24)
>> +#define PLL_READY                               (0x1 << 23)
>> +#define KVCO_EXT                                (0x1 << 22)
>> +#define VCOCAL_START                            (0x1 << 21)
>> +
>> +#define UTMI_PLL_KVCO_SHIFT                    15
>> +#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
>> +
>> +#define UTMI_PLL_ICP_SHIFT                     12
>> +#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
>> +
>> +#define UTMI_PLL_FBDIV_SHIFT                    4
>> +#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
>> +
>> +#define UTMI_PLL_REFDIV_SHIFT                   0
>> +#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
>> +
>> +/* For UTMI_TX Register */
>> +#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT          27
>> +#define UTMI_TX_REG_EXT_FS_RCAL_MASK           (0xf << 27)
>> +
>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT       26
>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK                (0x1 << 26)
>> +
>> +#define UTMI_TX_TXVDD12_SHIFT                   22
>> +#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
>> +
>> +#define UTMI_TX_CK60_PHSEL_SHIFT                17
>> +#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
>> +
>> +#define UTMI_TX_IMPCAL_VTH_SHIFT                14
>> +#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
>> +
>> +#define REG_RCAL_START                          (0x1 << 12)
>> +
>> +#define UTMI_TX_LOW_VDD_EN_SHIFT                11
>> +
>> +#define UTMI_TX_AMP_SHIFT                      0
>> +#define UTMI_TX_AMP_MASK                       (0x7 << 0)
>> +
>> +/* For UTMI_RX Register */
>> +#define UTMI_REG_SQ_LENGTH_SHIFT                15
>> +#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
>> +
>> +#define UTMI_RX_SQ_THRESH_SHIFT                 4
>> +#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
>> +
>> +#define UTMI_OTG_ADDON_OTG_ON                  (1 << 0)
>> +
>> +enum mv_usb2_phy_type {
>> +       PXA168_USB,
>> +       PXA910_USB,
>> +       MMP2_USB,
>> +};
>> +
>> +static struct mv_usb2_phy *the_phy;
>> +
>> +struct mv_usb2_phy *mv_usb2_get_phy(void)
>> +{
>> +       return the_phy;
>> +}
>> +EXPORT_SYMBOL(mv_usb2_get_phy);
>> +
>> +static unsigned int u2o_get(void __iomem *base, unsigned int offset)
>> +{
>> +       return readl(base + offset);
>> +}
>> +
>> +static void u2o_set(void __iomem *base, unsigned int offset,
>> +               unsigned int value)
>> +{
>> +       u32 reg;
>> +
>> +       reg = readl(base + offset);
>> +       reg |= value;
>> +       writel(reg, base + offset);
>> +       readl(base + offset);
>> +}
>> +
>> +static void u2o_clear(void __iomem *base, unsigned int offset,
>> +               unsigned int value)
>> +{
>> +       u32 reg;
>> +
>> +       reg = readl(base + offset);
>> +       reg &= ~value;
>> +       writel(reg, base + offset);
>> +       readl(base + offset);
>> +}
>> +
>> +static void u2o_write(void __iomem *base, unsigned int offset,
>> +               unsigned int value)
>> +{
>> +       writel(value, base + offset);
>> +       readl(base + offset);
>> +}
>> +
>> +static int _usb_phy_init(struct mv_usb2_phy *mv_phy)
>> +{
>> +       struct platform_device *pdev = mv_phy->pdev;
>> +       unsigned int loops = 0;
>> +       void __iomem *base = mv_phy->base;
>> +
>> +       dev_dbg(&pdev->dev, "phy init\n");
>> +
>> +       /* Initialize the USB PHY power */
>> +       if (mv_phy->type == PXA910_USB) {
>> +               u2o_set(base, UTMI_CTRL,
>> (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
>> +                       | (1<<UTMI_CTRL_PU_REF_SHIFT));
>> +       }
>> +
>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>> +
>> +       /* UTMI_PLL settings */
>> +       u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
>> +               | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
>> +               | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
>> +               | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
>> +
>> +       u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
>> +               | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
>> +               | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
>> +               | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
>> +
>> +       /* UTMI_TX */
>> +       u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
>> +               | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
>> +               | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
>> +               | UTMI_TX_AMP_MASK);
>> +       u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
>> +               | 4<<UTMI_TX_CK60_PHSEL_SHIFT |
>> 4<<UTMI_TX_IMPCAL_VTH_SHIFT
>> +               | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT |
>> 3<<UTMI_TX_AMP_SHIFT);
>> +
>> +       /* UTMI_RX */
>> +       u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
>> +               | UTMI_REG_SQ_LENGTH_MASK);
>> +       u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
>> +               | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
>> +
>> +       /* UTMI_IVREF */
>> +       if (mv_phy->type == PXA168_USB)
>> +               /* fixing Microsoft Altair board interface with NEC hub
>> issue -
>> +                * Set UTMI_IVREF from 0x4a3 to 0x4bf */
>> +               u2o_write(base, UTMI_IVREF, 0x4bf);
>> +
>> +       /* toggle VCOCAL_START bit of UTMI_PLL */
>> +       udelay(200);
>> +       u2o_set(base, UTMI_PLL, VCOCAL_START);
>> +       udelay(40);
>> +       u2o_clear(base, UTMI_PLL, VCOCAL_START);
>> +
>> +       /* toggle REG_RCAL_START bit of UTMI_TX */
>> +       udelay(400);
>> +       u2o_set(base, UTMI_TX, REG_RCAL_START);
>> +       udelay(40);
>> +       u2o_clear(base, UTMI_TX, REG_RCAL_START);
>> +       udelay(400);
>> +
>> +       /* Make sure PHY PLL is ready */
>> +       loops = 0;
>> +       while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
>> +               mdelay(1);
>> +               loops++;
>> +               if (loops > 100) {
>> +                       dev_warn(&pdev->dev, "calibrate timeout, UTMI_PLL
>> %x\n",
>> +                               u2o_get(base, UTMI_PLL));
>> +                       break;
>> +               }
>> +       }
>> +
>> +       if (mv_phy->type == PXA168_USB) {
>> +               u2o_set(base, UTMI_RESERVE, 1 << 5);
>> +               /* Turn on UTMI PHY OTG extension */
>> +               u2o_write(base, UTMI_OTG_ADDON, 1);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int _usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>> +{
>> +       void __iomem *base = mv_phy->base;
>> +
>> +       if (mv_phy->type == PXA168_USB)
>> +               u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
>> +
>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>> +
>> +       return 0;
>> +}
>> +
>> +static int usb_phy_init(struct mv_usb2_phy *mv_phy)
>> +{
>> +       int i = 0;
>> +
>> +       mutex_lock(&mv_phy->phy_lock);
>> +       if (mv_phy->refcount++ == 0) {
>> +               for (i = 0; i < mv_phy->clks_num; i++)
>> +                       clk_prepare_enable(mv_phy->clks[i]);
>> +               _usb_phy_init(mv_phy);
>> +       }
>> +       mutex_unlock(&mv_phy->phy_lock);
>> +       return 0;
>> +}
>> +
>> +static void usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>> +{
>> +       int i = 0;
>> +
>> +       mutex_lock(&mv_phy->phy_lock);
>> +       if (mv_phy->refcount++ == 0) {
>> +               _usb_phy_shutdown(mv_phy);
>> +               for (i = 0; i < mv_phy->clks_num; i++)
>> +                       clk_disable_unprepare(mv_phy->clks[i]);
>> +       }
>> +       mutex_unlock(&mv_phy->phy_lock);
>> +}
>> +
>> +static struct of_device_id usb_phy_dt_ids[] = {
>> +       { .compatible = "mrvl,pxa168-usb-phy",  .data = (void
>> *)PXA168_USB},
>> +       { .compatible = "mrvl,pxa910-usb-phy",  .data = (void
>> *)PXA910_USB},
>> +       { .compatible = "mrvl,mmp2-usb-phy",    .data = (void *)MMP2_USB},
>> +       {}
>> +};
>> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);
>> +
>> +static int usb_phy_parse_dt(struct platform_device *pdev,
>> +                               struct mv_usb2_phy *mv_phy)
>> +{
>> +       struct device_node *np = pdev->dev.of_node;
>> +       const struct of_device_id *of_id =
>> +                       of_match_device(usb_phy_dt_ids, &pdev->dev);
>> +       unsigned int clks_num;
>> +       int i, ret;
>> +       const char *clk_name;
>> +
>> +       if (!np)
>> +               return 1;
>> +
>> +       clks_num = of_property_count_strings(np, "clocks");
>> +       if (clks_num < 0) {
>> +               dev_err(&pdev->dev, "failed to get clock number\n");
>> +               return clks_num;
>> +       }
>> +
>> +       mv_phy->clks = devm_kzalloc(&pdev->dev,
>> +               sizeof(struct clk *) * clks_num, GFP_KERNEL);
>> +       if (mv_phy->clks == NULL) {
>> +               dev_err(&pdev->dev,
>> +                       "failed to allocate mempory for clocks");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       for (i = 0; i < clks_num; i++) {
>> +               ret = of_property_read_string_index(np, "clocks", i,
>> +                       &clk_name);
>> +               if (ret) {
>> +                       dev_err(&pdev->dev, "failed to read clocks\n");
>> +                       return ret;
>> +               }
>> +               mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
>> +               if (IS_ERR(mv_phy->clks[i])) {
>> +                       dev_err(&pdev->dev, "failed to get clock %s\n",
>> +                               clk_name);
>> +                       return PTR_ERR(mv_phy->clks[i]);
>> +               }
>> +       }
>> +
>> +       mv_phy->clks_num = clks_num;
>> +       mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
>> +
>> +       return 0;
>> +}
>> +
>> +static int usb_phy_probe(struct platform_device *pdev)
>> +{
>> +       struct mv_usb2_phy *mv_phy;
>> +       struct resource *r;
>> +       int ret, i;
>> +
>> +       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
>> +       if (mv_phy == NULL) {
>> +               dev_err(&pdev->dev, "failed to allocate memory\n");
>> +               return -ENOMEM;
>> +       }
>> +       mutex_init(&mv_phy->phy_lock);
>> +
>> +       ret = usb_phy_parse_dt(pdev, mv_phy);
>> +       /* no CONFIG_OF */
>> +       if (ret > 0) {
>> +               struct mv_usb_phy_platform_data *pdata
>> +                               = pdev->dev.platform_data;
>> +               const struct platform_device_id *id
>> +                               = platform_get_device_id(pdev);
>> +
>> +               if (pdata == NULL || id == NULL) {
>> +                       dev_err(&pdev->dev,
>> +                               "missing platform_data or id_entry\n");
>> +                       return -ENODEV;
>> +               }
>> +               mv_phy->type = (unsigned int)(id->driver_data);
>> +               mv_phy->clks_num = pdata->clknum;
>> +               mv_phy->clks = devm_kzalloc(&pdev->dev,
>> +                       sizeof(struct clk *) * mv_phy->clks_num,
>> GFP_KERNEL);
>> +               if (mv_phy->clks == NULL) {
>> +                       dev_err(&pdev->dev,
>> +                               "failed to allocate mempory for clocks");
>> +                       return -ENOMEM;
>> +               }
>> +               for (i = 0; i < mv_phy->clks_num; i++)
>> +                       mv_phy->clks[i] = devm_clk_get(&pdev->dev,
>> +
>> pdata->clkname[i]);
>> +                       if (IS_ERR(mv_phy->clks[i])) {
>> +                               dev_err(&pdev->dev, "failed to get clock
>> %s\n",
>> +                                       pdata->clkname[i]);
>> +                               return PTR_ERR(mv_phy->clks[i]);
>> +                       }
>> +       } else if (ret < 0) {
>> +               dev_err(&pdev->dev, "error parse dt\n");
>> +               return ret;
>> +       }
>> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       if (r == NULL) {
>> +               dev_err(&pdev->dev, "no phy I/O memory resource
>> defined\n");
>> +               return -ENODEV;
>> +       }
>> +       mv_phy->base = devm_ioremap(&pdev->dev, r->start,
>> resource_size(r));
>> +       if (mv_phy->base == NULL) {
>> +               dev_err(&pdev->dev, "error map register base\n");
>> +               return -EBUSY;
>> +       }
>> +       platform_set_drvdata(pdev, mv_phy);
>> +       mv_phy->pdev = pdev;
>> +       mv_phy->init = usb_phy_init;
>> +       mv_phy->shutdown = usb_phy_shutdown;
>> +
>> +       platform_set_drvdata(pdev, mv_phy);
>> +
>> +       the_phy = mv_phy;
>
>
> Is there any specific reason for not using the usb phy library?
> Please use the APIs provided in drivers/usb/otg/otg.c.
> These APIs will be moved to phy.c soon.
>
> Thanks
> Kishon

The phy in driver/usb/otg/otg.c is bound to OTG. The major target of
this APIs in OTG is help functions for OTG support.
I have used it and implemented it at mv_otg.c for OTG support. The
APIs only allow one phy driver register to it.
For the some USB chip, it need the PHY circus outside of the USB IP block.
So when usb work at EHCI mode or Client mode or OTG mode, we need
enable the PHY circus. This is one reason that
I add usb_phy_init and usb_phy_shutdown.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-06  8:18     ` Chao Xie
@ 2013-02-06 10:35       ` kishon
  2013-02-07  2:26         ` Chao Xie
  0 siblings, 1 reply; 25+ messages in thread
From: kishon @ 2013-02-06 10:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wednesday 06 February 2013 01:48 PM, Chao Xie wrote:
> On Wed, Feb 6, 2013 at 4:10 PM, kishon <kishon@ti.com> wrote:
>> Hi,
>>
>>
>> On Wednesday 06 February 2013 12:53 PM, Chao Xie wrote:
>>>
>>> The PHY is seperated from usb controller.
>>> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
>>> but PHY initialization may be different.
>>> the usb controller can support udc/otg/ehci, and for each of
>>> the mode, it need PHY to initialized before use the controller.
>>> Direclty writing the phy driver will make the usb controller
>>> driver to be simple and portable.
>>> The PHY driver will be used by marvell udc/otg/ehci.
>>>
>>> Signed-off-by: Chao Xie <chao.xie@marvell.com>
>>> ---
>>>    drivers/usb/phy/Kconfig              |    7 +
>>>    drivers/usb/phy/Makefile             |    1 +
>>>    drivers/usb/phy/mv_usb2_phy.c        |  454
>>> ++++++++++++++++++++++++++++++++++
>>>    include/linux/platform_data/mv_usb.h |    9 +-
>>>    include/linux/usb/mv_usb2.h          |   43 ++++
>>>    5 files changed, 511 insertions(+), 3 deletions(-)
>>>    create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>>>    create mode 100644 include/linux/usb/mv_usb2.h
>>>
>>> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
>>> index 65217a5..5479760 100644
>>> --- a/drivers/usb/phy/Kconfig
>>> +++ b/drivers/usb/phy/Kconfig
>>> @@ -73,3 +73,10 @@ config SAMSUNG_USBPHY
>>>          help
>>>            Enable this to support Samsung USB phy controller for samsung
>>>            SoCs.
>>> +
>>> +config MV_USB2_PHY
>>> +       tristate "Marvell USB 2.0 PHY Driver"
>>> +       depends on USB || USB_GADGET
>>> +       help
>>> +         Enable this to support Marvell USB 2.0 phy driver for Marvell
>>> +         SoC.
>>> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
>>> index b13faa1..3835316 100644
>>> --- a/drivers/usb/phy/Makefile
>>> +++ b/drivers/usb/phy/Makefile
>>> @@ -12,3 +12,4 @@ obj-$(CONFIG_MV_U3D_PHY)              += mv_u3d_phy.o
>>>    obj-$(CONFIG_USB_EHCI_TEGRA)  += tegra_usb_phy.o
>>>    obj-$(CONFIG_USB_RCAR_PHY)            += rcar-phy.o
>>>    obj-$(CONFIG_SAMSUNG_USBPHY)          += samsung-usbphy.o
>>> +obj-$(CONFIG_MV_USB2_PHY)              += mv_usb2_phy.o
>>> diff --git a/drivers/usb/phy/mv_usb2_phy.c b/drivers/usb/phy/mv_usb2_phy.c
>>> new file mode 100644
>>> index 0000000..c2bccae
>>> --- /dev/null
>>> +++ b/drivers/usb/phy/mv_usb2_phy.c
>>> @@ -0,0 +1,454 @@
>>> +/*
>>> + * Copyright (C) 2010 Google, Inc.
>>> + *
>>> + * Author:
>>> + *     Chao Xie <xiechao.mail@gmail.com>
>>> + *
>>> + * This software is licensed under the terms of the GNU General Public
>>> + * License version 2, as published by the Free Software Foundation, and
>>> + * may be copied, distributed, and modified under those terms.
>>> + *
>>> + * 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/resource.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/io.h>
>>> +#include <linux/err.h>
>>> +#include <linux/clk.h>
>>> +#include <linux/export.h>
>>> +#include <linux/module.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/platform_data/mv_usb.h>
>>> +#include <linux/usb/mv_usb2.h>
>>> +
>>> +/* phy regs */
>>> +#define UTMI_REVISION          0x0
>>> +#define UTMI_CTRL              0x4
>>> +#define UTMI_PLL               0x8
>>> +#define UTMI_TX                        0xc
>>> +#define UTMI_RX                        0x10
>>> +#define UTMI_IVREF             0x14
>>> +#define UTMI_T0                        0x18
>>> +#define UTMI_T1                        0x1c
>>> +#define UTMI_T2                        0x20
>>> +#define UTMI_T3                        0x24
>>> +#define UTMI_T4                        0x28
>>> +#define UTMI_T5                        0x2c
>>> +#define UTMI_RESERVE           0x30
>>> +#define UTMI_USB_INT           0x34
>>> +#define UTMI_DBG_CTL           0x38
>>> +#define UTMI_OTG_ADDON         0x3c
>>> +
>>> +/* For UTMICTRL Register */
>>> +#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
>>> +/* pxa168 */
>>> +#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
>>> +#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
>>> +#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
>>> +#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
>>> +
>>> +#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
>>> +#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT                28
>>> +#define UTMI_CTRL_PU_REF_SHIFT                 20
>>> +#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
>>> +#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
>>> +#define UTMI_CTRL_PWR_UP_SHIFT                  0
>>> +
>>> +/* For UTMI_PLL Register */
>>> +#define UTMI_PLL_PLLCALI12_SHIFT               29
>>> +#define UTMI_PLL_PLLCALI12_MASK                        (0x3 << 29)
>>> +
>>> +#define UTMI_PLL_PLLVDD18_SHIFT                        27
>>> +#define UTMI_PLL_PLLVDD18_MASK                 (0x3 << 27)
>>> +
>>> +#define UTMI_PLL_PLLVDD12_SHIFT                        25
>>> +#define UTMI_PLL_PLLVDD12_MASK                 (0x3 << 25)
>>> +
>>> +#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
>>> +#define CLK_BLK_EN                              (0x1 << 24)
>>> +#define PLL_READY                               (0x1 << 23)
>>> +#define KVCO_EXT                                (0x1 << 22)
>>> +#define VCOCAL_START                            (0x1 << 21)
>>> +
>>> +#define UTMI_PLL_KVCO_SHIFT                    15
>>> +#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
>>> +
>>> +#define UTMI_PLL_ICP_SHIFT                     12
>>> +#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
>>> +
>>> +#define UTMI_PLL_FBDIV_SHIFT                    4
>>> +#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
>>> +
>>> +#define UTMI_PLL_REFDIV_SHIFT                   0
>>> +#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
>>> +
>>> +/* For UTMI_TX Register */
>>> +#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT          27
>>> +#define UTMI_TX_REG_EXT_FS_RCAL_MASK           (0xf << 27)
>>> +
>>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT       26
>>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK                (0x1 << 26)
>>> +
>>> +#define UTMI_TX_TXVDD12_SHIFT                   22
>>> +#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
>>> +
>>> +#define UTMI_TX_CK60_PHSEL_SHIFT                17
>>> +#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
>>> +
>>> +#define UTMI_TX_IMPCAL_VTH_SHIFT                14
>>> +#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
>>> +
>>> +#define REG_RCAL_START                          (0x1 << 12)
>>> +
>>> +#define UTMI_TX_LOW_VDD_EN_SHIFT                11
>>> +
>>> +#define UTMI_TX_AMP_SHIFT                      0
>>> +#define UTMI_TX_AMP_MASK                       (0x7 << 0)
>>> +
>>> +/* For UTMI_RX Register */
>>> +#define UTMI_REG_SQ_LENGTH_SHIFT                15
>>> +#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
>>> +
>>> +#define UTMI_RX_SQ_THRESH_SHIFT                 4
>>> +#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
>>> +
>>> +#define UTMI_OTG_ADDON_OTG_ON                  (1 << 0)
>>> +
>>> +enum mv_usb2_phy_type {
>>> +       PXA168_USB,
>>> +       PXA910_USB,
>>> +       MMP2_USB,
>>> +};
>>> +
>>> +static struct mv_usb2_phy *the_phy;
>>> +
>>> +struct mv_usb2_phy *mv_usb2_get_phy(void)
>>> +{
>>> +       return the_phy;
>>> +}
>>> +EXPORT_SYMBOL(mv_usb2_get_phy);
>>> +
>>> +static unsigned int u2o_get(void __iomem *base, unsigned int offset)
>>> +{
>>> +       return readl(base + offset);
>>> +}
>>> +
>>> +static void u2o_set(void __iomem *base, unsigned int offset,
>>> +               unsigned int value)
>>> +{
>>> +       u32 reg;
>>> +
>>> +       reg = readl(base + offset);
>>> +       reg |= value;
>>> +       writel(reg, base + offset);
>>> +       readl(base + offset);
>>> +}
>>> +
>>> +static void u2o_clear(void __iomem *base, unsigned int offset,
>>> +               unsigned int value)
>>> +{
>>> +       u32 reg;
>>> +
>>> +       reg = readl(base + offset);
>>> +       reg &= ~value;
>>> +       writel(reg, base + offset);
>>> +       readl(base + offset);
>>> +}
>>> +
>>> +static void u2o_write(void __iomem *base, unsigned int offset,
>>> +               unsigned int value)
>>> +{
>>> +       writel(value, base + offset);
>>> +       readl(base + offset);
>>> +}
>>> +
>>> +static int _usb_phy_init(struct mv_usb2_phy *mv_phy)
>>> +{
>>> +       struct platform_device *pdev = mv_phy->pdev;
>>> +       unsigned int loops = 0;
>>> +       void __iomem *base = mv_phy->base;
>>> +
>>> +       dev_dbg(&pdev->dev, "phy init\n");
>>> +
>>> +       /* Initialize the USB PHY power */
>>> +       if (mv_phy->type == PXA910_USB) {
>>> +               u2o_set(base, UTMI_CTRL,
>>> (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
>>> +                       | (1<<UTMI_CTRL_PU_REF_SHIFT));
>>> +       }
>>> +
>>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>>> +
>>> +       /* UTMI_PLL settings */
>>> +       u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
>>> +               | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
>>> +               | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
>>> +               | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
>>> +
>>> +       u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
>>> +               | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
>>> +               | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
>>> +               | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
>>> +
>>> +       /* UTMI_TX */
>>> +       u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
>>> +               | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
>>> +               | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
>>> +               | UTMI_TX_AMP_MASK);
>>> +       u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
>>> +               | 4<<UTMI_TX_CK60_PHSEL_SHIFT |
>>> 4<<UTMI_TX_IMPCAL_VTH_SHIFT
>>> +               | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT |
>>> 3<<UTMI_TX_AMP_SHIFT);
>>> +
>>> +       /* UTMI_RX */
>>> +       u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
>>> +               | UTMI_REG_SQ_LENGTH_MASK);
>>> +       u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
>>> +               | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
>>> +
>>> +       /* UTMI_IVREF */
>>> +       if (mv_phy->type == PXA168_USB)
>>> +               /* fixing Microsoft Altair board interface with NEC hub
>>> issue -
>>> +                * Set UTMI_IVREF from 0x4a3 to 0x4bf */
>>> +               u2o_write(base, UTMI_IVREF, 0x4bf);
>>> +
>>> +       /* toggle VCOCAL_START bit of UTMI_PLL */
>>> +       udelay(200);
>>> +       u2o_set(base, UTMI_PLL, VCOCAL_START);
>>> +       udelay(40);
>>> +       u2o_clear(base, UTMI_PLL, VCOCAL_START);
>>> +
>>> +       /* toggle REG_RCAL_START bit of UTMI_TX */
>>> +       udelay(400);
>>> +       u2o_set(base, UTMI_TX, REG_RCAL_START);
>>> +       udelay(40);
>>> +       u2o_clear(base, UTMI_TX, REG_RCAL_START);
>>> +       udelay(400);
>>> +
>>> +       /* Make sure PHY PLL is ready */
>>> +       loops = 0;
>>> +       while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
>>> +               mdelay(1);
>>> +               loops++;
>>> +               if (loops > 100) {
>>> +                       dev_warn(&pdev->dev, "calibrate timeout, UTMI_PLL
>>> %x\n",
>>> +                               u2o_get(base, UTMI_PLL));
>>> +                       break;
>>> +               }
>>> +       }
>>> +
>>> +       if (mv_phy->type == PXA168_USB) {
>>> +               u2o_set(base, UTMI_RESERVE, 1 << 5);
>>> +               /* Turn on UTMI PHY OTG extension */
>>> +               u2o_write(base, UTMI_OTG_ADDON, 1);
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int _usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>>> +{
>>> +       void __iomem *base = mv_phy->base;
>>> +
>>> +       if (mv_phy->type == PXA168_USB)
>>> +               u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
>>> +
>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
>>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int usb_phy_init(struct mv_usb2_phy *mv_phy)
>>> +{
>>> +       int i = 0;
>>> +
>>> +       mutex_lock(&mv_phy->phy_lock);
>>> +       if (mv_phy->refcount++ == 0) {
>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>> +                       clk_prepare_enable(mv_phy->clks[i]);
>>> +               _usb_phy_init(mv_phy);
>>> +       }
>>> +       mutex_unlock(&mv_phy->phy_lock);
>>> +       return 0;
>>> +}
>>> +
>>> +static void usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>>> +{
>>> +       int i = 0;
>>> +
>>> +       mutex_lock(&mv_phy->phy_lock);
>>> +       if (mv_phy->refcount++ == 0) {
>>> +               _usb_phy_shutdown(mv_phy);
>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>> +                       clk_disable_unprepare(mv_phy->clks[i]);
>>> +       }
>>> +       mutex_unlock(&mv_phy->phy_lock);
>>> +}
>>> +
>>> +static struct of_device_id usb_phy_dt_ids[] = {
>>> +       { .compatible = "mrvl,pxa168-usb-phy",  .data = (void
>>> *)PXA168_USB},
>>> +       { .compatible = "mrvl,pxa910-usb-phy",  .data = (void
>>> *)PXA910_USB},
>>> +       { .compatible = "mrvl,mmp2-usb-phy",    .data = (void *)MMP2_USB},
>>> +       {}
>>> +};
>>> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);
>>> +
>>> +static int usb_phy_parse_dt(struct platform_device *pdev,
>>> +                               struct mv_usb2_phy *mv_phy)
>>> +{
>>> +       struct device_node *np = pdev->dev.of_node;
>>> +       const struct of_device_id *of_id =
>>> +                       of_match_device(usb_phy_dt_ids, &pdev->dev);
>>> +       unsigned int clks_num;
>>> +       int i, ret;
>>> +       const char *clk_name;
>>> +
>>> +       if (!np)
>>> +               return 1;
>>> +
>>> +       clks_num = of_property_count_strings(np, "clocks");
>>> +       if (clks_num < 0) {
>>> +               dev_err(&pdev->dev, "failed to get clock number\n");
>>> +               return clks_num;
>>> +       }
>>> +
>>> +       mv_phy->clks = devm_kzalloc(&pdev->dev,
>>> +               sizeof(struct clk *) * clks_num, GFP_KERNEL);
>>> +       if (mv_phy->clks == NULL) {
>>> +               dev_err(&pdev->dev,
>>> +                       "failed to allocate mempory for clocks");
>>> +               return -ENOMEM;
>>> +       }
>>> +
>>> +       for (i = 0; i < clks_num; i++) {
>>> +               ret = of_property_read_string_index(np, "clocks", i,
>>> +                       &clk_name);
>>> +               if (ret) {
>>> +                       dev_err(&pdev->dev, "failed to read clocks\n");
>>> +                       return ret;
>>> +               }
>>> +               mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
>>> +               if (IS_ERR(mv_phy->clks[i])) {
>>> +                       dev_err(&pdev->dev, "failed to get clock %s\n",
>>> +                               clk_name);
>>> +                       return PTR_ERR(mv_phy->clks[i]);
>>> +               }
>>> +       }
>>> +
>>> +       mv_phy->clks_num = clks_num;
>>> +       mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int usb_phy_probe(struct platform_device *pdev)
>>> +{
>>> +       struct mv_usb2_phy *mv_phy;
>>> +       struct resource *r;
>>> +       int ret, i;
>>> +
>>> +       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
>>> +       if (mv_phy == NULL) {
>>> +               dev_err(&pdev->dev, "failed to allocate memory\n");
>>> +               return -ENOMEM;
>>> +       }
>>> +       mutex_init(&mv_phy->phy_lock);
>>> +
>>> +       ret = usb_phy_parse_dt(pdev, mv_phy);
>>> +       /* no CONFIG_OF */
>>> +       if (ret > 0) {
>>> +               struct mv_usb_phy_platform_data *pdata
>>> +                               = pdev->dev.platform_data;
>>> +               const struct platform_device_id *id
>>> +                               = platform_get_device_id(pdev);
>>> +
>>> +               if (pdata == NULL || id == NULL) {
>>> +                       dev_err(&pdev->dev,
>>> +                               "missing platform_data or id_entry\n");
>>> +                       return -ENODEV;
>>> +               }
>>> +               mv_phy->type = (unsigned int)(id->driver_data);
>>> +               mv_phy->clks_num = pdata->clknum;
>>> +               mv_phy->clks = devm_kzalloc(&pdev->dev,
>>> +                       sizeof(struct clk *) * mv_phy->clks_num,
>>> GFP_KERNEL);
>>> +               if (mv_phy->clks == NULL) {
>>> +                       dev_err(&pdev->dev,
>>> +                               "failed to allocate mempory for clocks");
>>> +                       return -ENOMEM;
>>> +               }
>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>> +                       mv_phy->clks[i] = devm_clk_get(&pdev->dev,
>>> +
>>> pdata->clkname[i]);
>>> +                       if (IS_ERR(mv_phy->clks[i])) {
>>> +                               dev_err(&pdev->dev, "failed to get clock
>>> %s\n",
>>> +                                       pdata->clkname[i]);
>>> +                               return PTR_ERR(mv_phy->clks[i]);
>>> +                       }
>>> +       } else if (ret < 0) {
>>> +               dev_err(&pdev->dev, "error parse dt\n");
>>> +               return ret;
>>> +       }
>>> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +       if (r == NULL) {
>>> +               dev_err(&pdev->dev, "no phy I/O memory resource
>>> defined\n");
>>> +               return -ENODEV;
>>> +       }
>>> +       mv_phy->base = devm_ioremap(&pdev->dev, r->start,
>>> resource_size(r));
>>> +       if (mv_phy->base == NULL) {
>>> +               dev_err(&pdev->dev, "error map register base\n");
>>> +               return -EBUSY;
>>> +       }
>>> +       platform_set_drvdata(pdev, mv_phy);
>>> +       mv_phy->pdev = pdev;
>>> +       mv_phy->init = usb_phy_init;
>>> +       mv_phy->shutdown = usb_phy_shutdown;
>>> +
>>> +       platform_set_drvdata(pdev, mv_phy);
>>> +
>>> +       the_phy = mv_phy;
>>
>>
>> Is there any specific reason for not using the usb phy library?
>> Please use the APIs provided in drivers/usb/otg/otg.c.
>> These APIs will be moved to phy.c soon.
>>
>> Thanks
>> Kishon
>
> The phy in driver/usb/otg/otg.c is bound to OTG. The major target of
> this APIs in OTG is help functions for OTG support.

Not really. Much of what's in otg.c is related to PHY and we have an 
action item to rename otg.c to phy.c. Sascha hauer has already sent a 
patch for it.
> I have used it and implemented it at mv_otg.c for OTG support. The
> APIs only allow one phy driver register to it.

PHY library has changed quite a bit since then. You might want to have a 
look at usb/otg/otg.c again in usb-next.

Thanks
Kishon

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-06  7:23 ` [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller Chao Xie
  2013-02-06  8:10   ` kishon
@ 2013-02-06 14:42   ` Mark Rutland
  2013-02-07  2:00     ` Chao Xie
  1 sibling, 1 reply; 25+ messages in thread
From: Mark Rutland @ 2013-02-06 14:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

I have a few comments on the devicetree binding and the way it's parsed.

I note many are similar to those I commented on for the mv_udc and ehci-mv
devicetree code.

On Wed, Feb 06, 2013 at 07:23:36AM +0000, Chao Xie wrote:
> The PHY is seperated from usb controller.
> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
> but PHY initialization may be different.
> the usb controller can support udc/otg/ehci, and for each of
> the mode, it need PHY to initialized before use the controller.
> Direclty writing the phy driver will make the usb controller
> driver to be simple and portable.
> The PHY driver will be used by marvell udc/otg/ehci.
> 
> Signed-off-by: Chao Xie <chao.xie@marvell.com>
> ---
>  drivers/usb/phy/Kconfig              |    7 +
>  drivers/usb/phy/Makefile             |    1 +
>  drivers/usb/phy/mv_usb2_phy.c        |  454 ++++++++++++++++++++++++++++++++++
>  include/linux/platform_data/mv_usb.h |    9 +-
>  include/linux/usb/mv_usb2.h          |   43 ++++
>  5 files changed, 511 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>  create mode 100644 include/linux/usb/mv_usb2.h


[...]

> +static struct of_device_id usb_phy_dt_ids[] = {
> +       { .compatible = "mrvl,pxa168-usb-phy",  .data = (void *)PXA168_USB},
> +       { .compatible = "mrvl,pxa910-usb-phy",  .data = (void *)PXA910_USB},
> +       { .compatible = "mrvl,mmp2-usb-phy",    .data = (void *)MMP2_USB},
> +       {}
> +};
> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);

The binding (including these compatible string) needs to be documented.

> +
> +static int usb_phy_parse_dt(struct platform_device *pdev,
> +                               struct mv_usb2_phy *mv_phy)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       const struct of_device_id *of_id =
> +                       of_match_device(usb_phy_dt_ids, &pdev->dev);
> +       unsigned int clks_num;
> +       int i, ret;
> +       const char *clk_name;
> +
> +       if (!np)
> +               return 1;

An actual error code please.

-ENODEV? -EINVAL?

> +
> +       clks_num = of_property_count_strings(np, "clocks");
> +       if (clks_num < 0) {
> +               dev_err(&pdev->dev, "failed to get clock number\n");
> +               return clks_num;
> +       }

The common clock bindings use "clocks" as a list of phandle and clock-specifier
pairs. It seems bad to reuse that name in a different sense for this binding.

I'd recommend you use the common clock binding. There doesn't seem to be an
of_clk_count, but it should be a relatively simple addition, and it'd make this
code clearer and more consistent with other drivers.

See Documentation/devicetree/bindings/clock/clock-bindings.txt

> +
> +       mv_phy->clks = devm_kzalloc(&pdev->dev,
> +               sizeof(struct clk *) * clks_num, GFP_KERNEL);
> +       if (mv_phy->clks == NULL) {
> +               dev_err(&pdev->dev,
> +                       "failed to allocate mempory for clocks");

s/mempory/memory/

> +               return -ENOMEM;
> +       }
> +
> +       for (i = 0; i < clks_num; i++) {
> +               ret = of_property_read_string_index(np, "clocks", i,
> +                       &clk_name);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "failed to read clocks\n");
> +                       return ret;
> +               }
> +               mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
> +               if (IS_ERR(mv_phy->clks[i])) {
> +                       dev_err(&pdev->dev, "failed to get clock %s\n",
> +                               clk_name);
> +                       return PTR_ERR(mv_phy->clks[i]);
> +               }
> +       }
> +
> +       mv_phy->clks_num = clks_num;
> +       mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
> +
> +       return 0;
> +}

There's probably a need for something like devm_of_clk_get to make it easier to
write of-backed drivers.

> +
> +static int usb_phy_probe(struct platform_device *pdev)
> +{
> +       struct mv_usb2_phy *mv_phy;
> +       struct resource *r;
> +       int ret, i;
> +
> +       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
> +       if (mv_phy == NULL) {
> +               dev_err(&pdev->dev, "failed to allocate memory\n");
> +               return -ENOMEM;
> +       }
> +       mutex_init(&mv_phy->phy_lock);
> +
> +       ret = usb_phy_parse_dt(pdev, mv_phy);
> +       /* no CONFIG_OF */
> +       if (ret > 0) {

Reorganise this so you test for pdev->dev.of_node, and based of that you either
call usb_phy_parse_dt or do this stuff in the block below. That way you don't need
the positive return code from usb_phy_parse_dt.

> +               struct mv_usb_phy_platform_data *pdata
> +                               = pdev->dev.platform_data;
> +               const struct platform_device_id *id
> +                               = platform_get_device_id(pdev);
> +
> +               if (pdata == NULL || id == NULL) {
> +                       dev_err(&pdev->dev,
> +                               "missing platform_data or id_entry\n");
> +                       return -ENODEV;
> +               }
> +               mv_phy->type = (unsigned int)(id->driver_data);
> +               mv_phy->clks_num = pdata->clknum;
> +               mv_phy->clks = devm_kzalloc(&pdev->dev,
> +                       sizeof(struct clk *) * mv_phy->clks_num, GFP_KERNEL);
> +               if (mv_phy->clks == NULL) {
> +                       dev_err(&pdev->dev,
> +                               "failed to allocate mempory for clocks");

s/mempory/memory/

> +                       return -ENOMEM;
> +               }
> +               for (i = 0; i < mv_phy->clks_num; i++)
> +                       mv_phy->clks[i] = devm_clk_get(&pdev->dev,
> +                                                       pdata->clkname[i]);
> +                       if (IS_ERR(mv_phy->clks[i])) {
> +                               dev_err(&pdev->dev, "failed to get clock %s\n",
> +                                       pdata->clkname[i]);
> +                               return PTR_ERR(mv_phy->clks[i]);
> +                       }
> +       } else if (ret < 0) {
> +               dev_err(&pdev->dev, "error parse dt\n");

s/parse/parsing/

> +               return ret;
> +       }
> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (r == NULL) {
> +               dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
> +               return -ENODEV;
> +       }
> +       mv_phy->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
> +       if (mv_phy->base == NULL) {
> +               dev_err(&pdev->dev, "error map register base\n");

s/map/mapping/

> +               return -EBUSY;
> +       }
> +       platform_set_drvdata(pdev, mv_phy);
> +       mv_phy->pdev = pdev;
> +       mv_phy->init = usb_phy_init;
> +       mv_phy->shutdown = usb_phy_shutdown;
> +
> +       platform_set_drvdata(pdev, mv_phy);
> +
> +       the_phy = mv_phy;
> +
> +       dev_info(&pdev->dev, "mv usb2 phy initialized\n");
> +
> +       return 0;
> +}
> +
> +static int usb_phy_remove(struct platform_device *pdev)
> +{
> +       the_phy = NULL;
> +
> +       return 0;
> +}

Is mv_usb2_phy large? Why does it need to be dynamically allocated / freed at
all given it's treated as a singleton?

[...]

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-06 14:42   ` Mark Rutland
@ 2013-02-07  2:00     ` Chao Xie
  0 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-07  2:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 6, 2013 at 10:42 PM, Mark Rutland <mark.rutland@arm.com> wrote:
> Hi,
>
> I have a few comments on the devicetree binding and the way it's parsed.
>
> I note many are similar to those I commented on for the mv_udc and ehci-mv
> devicetree code.
>
> On Wed, Feb 06, 2013 at 07:23:36AM +0000, Chao Xie wrote:
>> The PHY is seperated from usb controller.
>> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
>> but PHY initialization may be different.
>> the usb controller can support udc/otg/ehci, and for each of
>> the mode, it need PHY to initialized before use the controller.
>> Direclty writing the phy driver will make the usb controller
>> driver to be simple and portable.
>> The PHY driver will be used by marvell udc/otg/ehci.
>>
>> Signed-off-by: Chao Xie <chao.xie@marvell.com>
>> ---
>>  drivers/usb/phy/Kconfig              |    7 +
>>  drivers/usb/phy/Makefile             |    1 +
>>  drivers/usb/phy/mv_usb2_phy.c        |  454 ++++++++++++++++++++++++++++++++++
>>  include/linux/platform_data/mv_usb.h |    9 +-
>>  include/linux/usb/mv_usb2.h          |   43 ++++
>>  5 files changed, 511 insertions(+), 3 deletions(-)
>>  create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>>  create mode 100644 include/linux/usb/mv_usb2.h
>
>
> [...]
>
>> +static struct of_device_id usb_phy_dt_ids[] = {
>> +       { .compatible = "mrvl,pxa168-usb-phy",  .data = (void *)PXA168_USB},
>> +       { .compatible = "mrvl,pxa910-usb-phy",  .data = (void *)PXA910_USB},
>> +       { .compatible = "mrvl,mmp2-usb-phy",    .data = (void *)MMP2_USB},
>> +       {}
>> +};
>> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);
>
> The binding (including these compatible string) needs to be documented.
>
>> +
>> +static int usb_phy_parse_dt(struct platform_device *pdev,
>> +                               struct mv_usb2_phy *mv_phy)
>> +{
>> +       struct device_node *np = pdev->dev.of_node;
>> +       const struct of_device_id *of_id =
>> +                       of_match_device(usb_phy_dt_ids, &pdev->dev);
>> +       unsigned int clks_num;
>> +       int i, ret;
>> +       const char *clk_name;
>> +
>> +       if (!np)
>> +               return 1;
>
> An actual error code please.
>
> -ENODEV? -EINVAL?
>
>> +
>> +       clks_num = of_property_count_strings(np, "clocks");
>> +       if (clks_num < 0) {
>> +               dev_err(&pdev->dev, "failed to get clock number\n");
>> +               return clks_num;
>> +       }
>
> The common clock bindings use "clocks" as a list of phandle and clock-specifier
> pairs. It seems bad to reuse that name in a different sense for this binding.
>
> I'd recommend you use the common clock binding. There doesn't seem to be an
> of_clk_count, but it should be a relatively simple addition, and it'd make this
> code clearer and more consistent with other drivers.
>
> See Documentation/devicetree/bindings/clock/clock-bindings.txt
>
>> +
>> +       mv_phy->clks = devm_kzalloc(&pdev->dev,
>> +               sizeof(struct clk *) * clks_num, GFP_KERNEL);
>> +       if (mv_phy->clks == NULL) {
>> +               dev_err(&pdev->dev,
>> +                       "failed to allocate mempory for clocks");
>
> s/mempory/memory/
>
>> +               return -ENOMEM;
>> +       }
>> +
>> +       for (i = 0; i < clks_num; i++) {
>> +               ret = of_property_read_string_index(np, "clocks", i,
>> +                       &clk_name);
>> +               if (ret) {
>> +                       dev_err(&pdev->dev, "failed to read clocks\n");
>> +                       return ret;
>> +               }
>> +               mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
>> +               if (IS_ERR(mv_phy->clks[i])) {
>> +                       dev_err(&pdev->dev, "failed to get clock %s\n",
>> +                               clk_name);
>> +                       return PTR_ERR(mv_phy->clks[i]);
>> +               }
>> +       }
>> +
>> +       mv_phy->clks_num = clks_num;
>> +       mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
>> +
>> +       return 0;
>> +}
>
> There's probably a need for something like devm_of_clk_get to make it easier to
> write of-backed drivers.
>
>> +
>> +static int usb_phy_probe(struct platform_device *pdev)
>> +{
>> +       struct mv_usb2_phy *mv_phy;
>> +       struct resource *r;
>> +       int ret, i;
>> +
>> +       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
>> +       if (mv_phy == NULL) {
>> +               dev_err(&pdev->dev, "failed to allocate memory\n");
>> +               return -ENOMEM;
>> +       }
>> +       mutex_init(&mv_phy->phy_lock);
>> +
>> +       ret = usb_phy_parse_dt(pdev, mv_phy);
>> +       /* no CONFIG_OF */
>> +       if (ret > 0) {
>
> Reorganise this so you test for pdev->dev.of_node, and based of that you either
> call usb_phy_parse_dt or do this stuff in the block below. That way you don't need
> the positive return code from usb_phy_parse_dt.
>
>> +               struct mv_usb_phy_platform_data *pdata
>> +                               = pdev->dev.platform_data;
>> +               const struct platform_device_id *id
>> +                               = platform_get_device_id(pdev);
>> +
>> +               if (pdata == NULL || id == NULL) {
>> +                       dev_err(&pdev->dev,
>> +                               "missing platform_data or id_entry\n");
>> +                       return -ENODEV;
>> +               }
>> +               mv_phy->type = (unsigned int)(id->driver_data);
>> +               mv_phy->clks_num = pdata->clknum;
>> +               mv_phy->clks = devm_kzalloc(&pdev->dev,
>> +                       sizeof(struct clk *) * mv_phy->clks_num, GFP_KERNEL);
>> +               if (mv_phy->clks == NULL) {
>> +                       dev_err(&pdev->dev,
>> +                               "failed to allocate mempory for clocks");
>
> s/mempory/memory/
>
>> +                       return -ENOMEM;
>> +               }
>> +               for (i = 0; i < mv_phy->clks_num; i++)
>> +                       mv_phy->clks[i] = devm_clk_get(&pdev->dev,
>> +                                                       pdata->clkname[i]);
>> +                       if (IS_ERR(mv_phy->clks[i])) {
>> +                               dev_err(&pdev->dev, "failed to get clock %s\n",
>> +                                       pdata->clkname[i]);
>> +                               return PTR_ERR(mv_phy->clks[i]);
>> +                       }
>> +       } else if (ret < 0) {
>> +               dev_err(&pdev->dev, "error parse dt\n");
>
> s/parse/parsing/
>
>> +               return ret;
>> +       }
>> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       if (r == NULL) {
>> +               dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
>> +               return -ENODEV;
>> +       }
>> +       mv_phy->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
>> +       if (mv_phy->base == NULL) {
>> +               dev_err(&pdev->dev, "error map register base\n");
>
> s/map/mapping/
>
>> +               return -EBUSY;
>> +       }
>> +       platform_set_drvdata(pdev, mv_phy);
>> +       mv_phy->pdev = pdev;
>> +       mv_phy->init = usb_phy_init;
>> +       mv_phy->shutdown = usb_phy_shutdown;
>> +
>> +       platform_set_drvdata(pdev, mv_phy);
>> +
>> +       the_phy = mv_phy;
>> +
>> +       dev_info(&pdev->dev, "mv usb2 phy initialized\n");
>> +
>> +       return 0;
>> +}
>> +
>> +static int usb_phy_remove(struct platform_device *pdev)
>> +{
>> +       the_phy = NULL;
>> +
>> +       return 0;
>> +}
>
> Is mv_usb2_phy large? Why does it need to be dynamically allocated / freed at
> all given it's treated as a singleton?
>
First i am sorry about the device tree support.
I will remove the device tree support and make it in another series
together with the patches for device tree support
for client/otg/host driver.

the mv_usb2_phy is bound it to the usb phy device, as a usually way we
will allocate it when probe the usb phy device, and
make it as a private data structure to usb phy device.


> [...]
>
> Thanks,
> Mark.
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-06 10:35       ` kishon
@ 2013-02-07  2:26         ` Chao Xie
  2013-02-07  5:57           ` kishon
  0 siblings, 1 reply; 25+ messages in thread
From: Chao Xie @ 2013-02-07  2:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 6, 2013 at 6:35 PM, kishon <kishon@ti.com> wrote:
> Hi,
>
>
> On Wednesday 06 February 2013 01:48 PM, Chao Xie wrote:
>>
>> On Wed, Feb 6, 2013 at 4:10 PM, kishon <kishon@ti.com> wrote:
>>>
>>> Hi,
>>>
>>>
>>> On Wednesday 06 February 2013 12:53 PM, Chao Xie wrote:
>>>>
>>>>
>>>> The PHY is seperated from usb controller.
>>>> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
>>>> but PHY initialization may be different.
>>>> the usb controller can support udc/otg/ehci, and for each of
>>>> the mode, it need PHY to initialized before use the controller.
>>>> Direclty writing the phy driver will make the usb controller
>>>> driver to be simple and portable.
>>>> The PHY driver will be used by marvell udc/otg/ehci.
>>>>
>>>> Signed-off-by: Chao Xie <chao.xie@marvell.com>
>>>> ---
>>>>    drivers/usb/phy/Kconfig              |    7 +
>>>>    drivers/usb/phy/Makefile             |    1 +
>>>>    drivers/usb/phy/mv_usb2_phy.c        |  454
>>>> ++++++++++++++++++++++++++++++++++
>>>>    include/linux/platform_data/mv_usb.h |    9 +-
>>>>    include/linux/usb/mv_usb2.h          |   43 ++++
>>>>    5 files changed, 511 insertions(+), 3 deletions(-)
>>>>    create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>>>>    create mode 100644 include/linux/usb/mv_usb2.h
>>>>
>>>> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
>>>> index 65217a5..5479760 100644
>>>> --- a/drivers/usb/phy/Kconfig
>>>> +++ b/drivers/usb/phy/Kconfig
>>>> @@ -73,3 +73,10 @@ config SAMSUNG_USBPHY
>>>>          help
>>>>            Enable this to support Samsung USB phy controller for samsung
>>>>            SoCs.
>>>> +
>>>> +config MV_USB2_PHY
>>>> +       tristate "Marvell USB 2.0 PHY Driver"
>>>> +       depends on USB || USB_GADGET
>>>> +       help
>>>> +         Enable this to support Marvell USB 2.0 phy driver for Marvell
>>>> +         SoC.
>>>> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
>>>> index b13faa1..3835316 100644
>>>> --- a/drivers/usb/phy/Makefile
>>>> +++ b/drivers/usb/phy/Makefile
>>>> @@ -12,3 +12,4 @@ obj-$(CONFIG_MV_U3D_PHY)              += mv_u3d_phy.o
>>>>    obj-$(CONFIG_USB_EHCI_TEGRA)  += tegra_usb_phy.o
>>>>    obj-$(CONFIG_USB_RCAR_PHY)            += rcar-phy.o
>>>>    obj-$(CONFIG_SAMSUNG_USBPHY)          += samsung-usbphy.o
>>>> +obj-$(CONFIG_MV_USB2_PHY)              += mv_usb2_phy.o
>>>> diff --git a/drivers/usb/phy/mv_usb2_phy.c
>>>> b/drivers/usb/phy/mv_usb2_phy.c
>>>> new file mode 100644
>>>> index 0000000..c2bccae
>>>> --- /dev/null
>>>> +++ b/drivers/usb/phy/mv_usb2_phy.c
>>>> @@ -0,0 +1,454 @@
>>>> +/*
>>>> + * Copyright (C) 2010 Google, Inc.
>>>> + *
>>>> + * Author:
>>>> + *     Chao Xie <xiechao.mail@gmail.com>
>>>> + *
>>>> + * This software is licensed under the terms of the GNU General Public
>>>> + * License version 2, as published by the Free Software Foundation, and
>>>> + * may be copied, distributed, and modified under those terms.
>>>> + *
>>>> + * 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/resource.h>
>>>> +#include <linux/delay.h>
>>>> +#include <linux/slab.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_device.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/err.h>
>>>> +#include <linux/clk.h>
>>>> +#include <linux/export.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/platform_data/mv_usb.h>
>>>> +#include <linux/usb/mv_usb2.h>
>>>> +
>>>> +/* phy regs */
>>>> +#define UTMI_REVISION          0x0
>>>> +#define UTMI_CTRL              0x4
>>>> +#define UTMI_PLL               0x8
>>>> +#define UTMI_TX                        0xc
>>>> +#define UTMI_RX                        0x10
>>>> +#define UTMI_IVREF             0x14
>>>> +#define UTMI_T0                        0x18
>>>> +#define UTMI_T1                        0x1c
>>>> +#define UTMI_T2                        0x20
>>>> +#define UTMI_T3                        0x24
>>>> +#define UTMI_T4                        0x28
>>>> +#define UTMI_T5                        0x2c
>>>> +#define UTMI_RESERVE           0x30
>>>> +#define UTMI_USB_INT           0x34
>>>> +#define UTMI_DBG_CTL           0x38
>>>> +#define UTMI_OTG_ADDON         0x3c
>>>> +
>>>> +/* For UTMICTRL Register */
>>>> +#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
>>>> +/* pxa168 */
>>>> +#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
>>>> +#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
>>>> +#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
>>>> +#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
>>>> +
>>>> +#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
>>>> +#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT                28
>>>> +#define UTMI_CTRL_PU_REF_SHIFT                 20
>>>> +#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
>>>> +#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
>>>> +#define UTMI_CTRL_PWR_UP_SHIFT                  0
>>>> +
>>>> +/* For UTMI_PLL Register */
>>>> +#define UTMI_PLL_PLLCALI12_SHIFT               29
>>>> +#define UTMI_PLL_PLLCALI12_MASK                        (0x3 << 29)
>>>> +
>>>> +#define UTMI_PLL_PLLVDD18_SHIFT                        27
>>>> +#define UTMI_PLL_PLLVDD18_MASK                 (0x3 << 27)
>>>> +
>>>> +#define UTMI_PLL_PLLVDD12_SHIFT                        25
>>>> +#define UTMI_PLL_PLLVDD12_MASK                 (0x3 << 25)
>>>> +
>>>> +#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
>>>> +#define CLK_BLK_EN                              (0x1 << 24)
>>>> +#define PLL_READY                               (0x1 << 23)
>>>> +#define KVCO_EXT                                (0x1 << 22)
>>>> +#define VCOCAL_START                            (0x1 << 21)
>>>> +
>>>> +#define UTMI_PLL_KVCO_SHIFT                    15
>>>> +#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
>>>> +
>>>> +#define UTMI_PLL_ICP_SHIFT                     12
>>>> +#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
>>>> +
>>>> +#define UTMI_PLL_FBDIV_SHIFT                    4
>>>> +#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
>>>> +
>>>> +#define UTMI_PLL_REFDIV_SHIFT                   0
>>>> +#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
>>>> +
>>>> +/* For UTMI_TX Register */
>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT          27
>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_MASK           (0xf << 27)
>>>> +
>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT       26
>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK                (0x1 << 26)
>>>> +
>>>> +#define UTMI_TX_TXVDD12_SHIFT                   22
>>>> +#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
>>>> +
>>>> +#define UTMI_TX_CK60_PHSEL_SHIFT                17
>>>> +#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
>>>> +
>>>> +#define UTMI_TX_IMPCAL_VTH_SHIFT                14
>>>> +#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
>>>> +
>>>> +#define REG_RCAL_START                          (0x1 << 12)
>>>> +
>>>> +#define UTMI_TX_LOW_VDD_EN_SHIFT                11
>>>> +
>>>> +#define UTMI_TX_AMP_SHIFT                      0
>>>> +#define UTMI_TX_AMP_MASK                       (0x7 << 0)
>>>> +
>>>> +/* For UTMI_RX Register */
>>>> +#define UTMI_REG_SQ_LENGTH_SHIFT                15
>>>> +#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
>>>> +
>>>> +#define UTMI_RX_SQ_THRESH_SHIFT                 4
>>>> +#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
>>>> +
>>>> +#define UTMI_OTG_ADDON_OTG_ON                  (1 << 0)
>>>> +
>>>> +enum mv_usb2_phy_type {
>>>> +       PXA168_USB,
>>>> +       PXA910_USB,
>>>> +       MMP2_USB,
>>>> +};
>>>> +
>>>> +static struct mv_usb2_phy *the_phy;
>>>> +
>>>> +struct mv_usb2_phy *mv_usb2_get_phy(void)
>>>> +{
>>>> +       return the_phy;
>>>> +}
>>>> +EXPORT_SYMBOL(mv_usb2_get_phy);
>>>> +
>>>> +static unsigned int u2o_get(void __iomem *base, unsigned int offset)
>>>> +{
>>>> +       return readl(base + offset);
>>>> +}
>>>> +
>>>> +static void u2o_set(void __iomem *base, unsigned int offset,
>>>> +               unsigned int value)
>>>> +{
>>>> +       u32 reg;
>>>> +
>>>> +       reg = readl(base + offset);
>>>> +       reg |= value;
>>>> +       writel(reg, base + offset);
>>>> +       readl(base + offset);
>>>> +}
>>>> +
>>>> +static void u2o_clear(void __iomem *base, unsigned int offset,
>>>> +               unsigned int value)
>>>> +{
>>>> +       u32 reg;
>>>> +
>>>> +       reg = readl(base + offset);
>>>> +       reg &= ~value;
>>>> +       writel(reg, base + offset);
>>>> +       readl(base + offset);
>>>> +}
>>>> +
>>>> +static void u2o_write(void __iomem *base, unsigned int offset,
>>>> +               unsigned int value)
>>>> +{
>>>> +       writel(value, base + offset);
>>>> +       readl(base + offset);
>>>> +}
>>>> +
>>>> +static int _usb_phy_init(struct mv_usb2_phy *mv_phy)
>>>> +{
>>>> +       struct platform_device *pdev = mv_phy->pdev;
>>>> +       unsigned int loops = 0;
>>>> +       void __iomem *base = mv_phy->base;
>>>> +
>>>> +       dev_dbg(&pdev->dev, "phy init\n");
>>>> +
>>>> +       /* Initialize the USB PHY power */
>>>> +       if (mv_phy->type == PXA910_USB) {
>>>> +               u2o_set(base, UTMI_CTRL,
>>>> (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
>>>> +                       | (1<<UTMI_CTRL_PU_REF_SHIFT));
>>>> +       }
>>>> +
>>>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>>>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>>>> +
>>>> +       /* UTMI_PLL settings */
>>>> +       u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
>>>> +               | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
>>>> +               | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
>>>> +               | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
>>>> +
>>>> +       u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
>>>> +               | 0xb<<UTMI_PLL_REFDIV_SHIFT |
>>>> 3<<UTMI_PLL_PLLVDD18_SHIFT
>>>> +               | 3<<UTMI_PLL_PLLVDD12_SHIFT |
>>>> 3<<UTMI_PLL_PLLCALI12_SHIFT
>>>> +               | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
>>>> +
>>>> +       /* UTMI_TX */
>>>> +       u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
>>>> +               | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
>>>> +               | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
>>>> +               | UTMI_TX_AMP_MASK);
>>>> +       u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
>>>> +               | 4<<UTMI_TX_CK60_PHSEL_SHIFT |
>>>> 4<<UTMI_TX_IMPCAL_VTH_SHIFT
>>>> +               | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT |
>>>> 3<<UTMI_TX_AMP_SHIFT);
>>>> +
>>>> +       /* UTMI_RX */
>>>> +       u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
>>>> +               | UTMI_REG_SQ_LENGTH_MASK);
>>>> +       u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
>>>> +               | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
>>>> +
>>>> +       /* UTMI_IVREF */
>>>> +       if (mv_phy->type == PXA168_USB)
>>>> +               /* fixing Microsoft Altair board interface with NEC hub
>>>> issue -
>>>> +                * Set UTMI_IVREF from 0x4a3 to 0x4bf */
>>>> +               u2o_write(base, UTMI_IVREF, 0x4bf);
>>>> +
>>>> +       /* toggle VCOCAL_START bit of UTMI_PLL */
>>>> +       udelay(200);
>>>> +       u2o_set(base, UTMI_PLL, VCOCAL_START);
>>>> +       udelay(40);
>>>> +       u2o_clear(base, UTMI_PLL, VCOCAL_START);
>>>> +
>>>> +       /* toggle REG_RCAL_START bit of UTMI_TX */
>>>> +       udelay(400);
>>>> +       u2o_set(base, UTMI_TX, REG_RCAL_START);
>>>> +       udelay(40);
>>>> +       u2o_clear(base, UTMI_TX, REG_RCAL_START);
>>>> +       udelay(400);
>>>> +
>>>> +       /* Make sure PHY PLL is ready */
>>>> +       loops = 0;
>>>> +       while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
>>>> +               mdelay(1);
>>>> +               loops++;
>>>> +               if (loops > 100) {
>>>> +                       dev_warn(&pdev->dev, "calibrate timeout,
>>>> UTMI_PLL
>>>> %x\n",
>>>> +                               u2o_get(base, UTMI_PLL));
>>>> +                       break;
>>>> +               }
>>>> +       }
>>>> +
>>>> +       if (mv_phy->type == PXA168_USB) {
>>>> +               u2o_set(base, UTMI_RESERVE, 1 << 5);
>>>> +               /* Turn on UTMI PHY OTG extension */
>>>> +               u2o_write(base, UTMI_OTG_ADDON, 1);
>>>> +       }
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static int _usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>>>> +{
>>>> +       void __iomem *base = mv_phy->base;
>>>> +
>>>> +       if (mv_phy->type == PXA168_USB)
>>>> +               u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
>>>> +
>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
>>>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>>>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static int usb_phy_init(struct mv_usb2_phy *mv_phy)
>>>> +{
>>>> +       int i = 0;
>>>> +
>>>> +       mutex_lock(&mv_phy->phy_lock);
>>>> +       if (mv_phy->refcount++ == 0) {
>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>> +                       clk_prepare_enable(mv_phy->clks[i]);
>>>> +               _usb_phy_init(mv_phy);
>>>> +       }
>>>> +       mutex_unlock(&mv_phy->phy_lock);
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static void usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>>>> +{
>>>> +       int i = 0;
>>>> +
>>>> +       mutex_lock(&mv_phy->phy_lock);
>>>> +       if (mv_phy->refcount++ == 0) {
>>>> +               _usb_phy_shutdown(mv_phy);
>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>> +                       clk_disable_unprepare(mv_phy->clks[i]);
>>>> +       }
>>>> +       mutex_unlock(&mv_phy->phy_lock);
>>>> +}
>>>> +
>>>> +static struct of_device_id usb_phy_dt_ids[] = {
>>>> +       { .compatible = "mrvl,pxa168-usb-phy",  .data = (void
>>>> *)PXA168_USB},
>>>> +       { .compatible = "mrvl,pxa910-usb-phy",  .data = (void
>>>> *)PXA910_USB},
>>>> +       { .compatible = "mrvl,mmp2-usb-phy",    .data = (void
>>>> *)MMP2_USB},
>>>> +       {}
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);
>>>> +
>>>> +static int usb_phy_parse_dt(struct platform_device *pdev,
>>>> +                               struct mv_usb2_phy *mv_phy)
>>>> +{
>>>> +       struct device_node *np = pdev->dev.of_node;
>>>> +       const struct of_device_id *of_id =
>>>> +                       of_match_device(usb_phy_dt_ids, &pdev->dev);
>>>> +       unsigned int clks_num;
>>>> +       int i, ret;
>>>> +       const char *clk_name;
>>>> +
>>>> +       if (!np)
>>>> +               return 1;
>>>> +
>>>> +       clks_num = of_property_count_strings(np, "clocks");
>>>> +       if (clks_num < 0) {
>>>> +               dev_err(&pdev->dev, "failed to get clock number\n");
>>>> +               return clks_num;
>>>> +       }
>>>> +
>>>> +       mv_phy->clks = devm_kzalloc(&pdev->dev,
>>>> +               sizeof(struct clk *) * clks_num, GFP_KERNEL);
>>>> +       if (mv_phy->clks == NULL) {
>>>> +               dev_err(&pdev->dev,
>>>> +                       "failed to allocate mempory for clocks");
>>>> +               return -ENOMEM;
>>>> +       }
>>>> +
>>>> +       for (i = 0; i < clks_num; i++) {
>>>> +               ret = of_property_read_string_index(np, "clocks", i,
>>>> +                       &clk_name);
>>>> +               if (ret) {
>>>> +                       dev_err(&pdev->dev, "failed to read clocks\n");
>>>> +                       return ret;
>>>> +               }
>>>> +               mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
>>>> +               if (IS_ERR(mv_phy->clks[i])) {
>>>> +                       dev_err(&pdev->dev, "failed to get clock %s\n",
>>>> +                               clk_name);
>>>> +                       return PTR_ERR(mv_phy->clks[i]);
>>>> +               }
>>>> +       }
>>>> +
>>>> +       mv_phy->clks_num = clks_num;
>>>> +       mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static int usb_phy_probe(struct platform_device *pdev)
>>>> +{
>>>> +       struct mv_usb2_phy *mv_phy;
>>>> +       struct resource *r;
>>>> +       int ret, i;
>>>> +
>>>> +       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
>>>> +       if (mv_phy == NULL) {
>>>> +               dev_err(&pdev->dev, "failed to allocate memory\n");
>>>> +               return -ENOMEM;
>>>> +       }
>>>> +       mutex_init(&mv_phy->phy_lock);
>>>> +
>>>> +       ret = usb_phy_parse_dt(pdev, mv_phy);
>>>> +       /* no CONFIG_OF */
>>>> +       if (ret > 0) {
>>>> +               struct mv_usb_phy_platform_data *pdata
>>>> +                               = pdev->dev.platform_data;
>>>> +               const struct platform_device_id *id
>>>> +                               = platform_get_device_id(pdev);
>>>> +
>>>> +               if (pdata == NULL || id == NULL) {
>>>> +                       dev_err(&pdev->dev,
>>>> +                               "missing platform_data or id_entry\n");
>>>> +                       return -ENODEV;
>>>> +               }
>>>> +               mv_phy->type = (unsigned int)(id->driver_data);
>>>> +               mv_phy->clks_num = pdata->clknum;
>>>> +               mv_phy->clks = devm_kzalloc(&pdev->dev,
>>>> +                       sizeof(struct clk *) * mv_phy->clks_num,
>>>> GFP_KERNEL);
>>>> +               if (mv_phy->clks == NULL) {
>>>> +                       dev_err(&pdev->dev,
>>>> +                               "failed to allocate mempory for
>>>> clocks");
>>>> +                       return -ENOMEM;
>>>> +               }
>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>> +                       mv_phy->clks[i] = devm_clk_get(&pdev->dev,
>>>> +
>>>> pdata->clkname[i]);
>>>> +                       if (IS_ERR(mv_phy->clks[i])) {
>>>> +                               dev_err(&pdev->dev, "failed to get clock
>>>> %s\n",
>>>> +                                       pdata->clkname[i]);
>>>> +                               return PTR_ERR(mv_phy->clks[i]);
>>>> +                       }
>>>> +       } else if (ret < 0) {
>>>> +               dev_err(&pdev->dev, "error parse dt\n");
>>>> +               return ret;
>>>> +       }
>>>> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +       if (r == NULL) {
>>>> +               dev_err(&pdev->dev, "no phy I/O memory resource
>>>> defined\n");
>>>> +               return -ENODEV;
>>>> +       }
>>>> +       mv_phy->base = devm_ioremap(&pdev->dev, r->start,
>>>> resource_size(r));
>>>> +       if (mv_phy->base == NULL) {
>>>> +               dev_err(&pdev->dev, "error map register base\n");
>>>> +               return -EBUSY;
>>>> +       }
>>>> +       platform_set_drvdata(pdev, mv_phy);
>>>> +       mv_phy->pdev = pdev;
>>>> +       mv_phy->init = usb_phy_init;
>>>> +       mv_phy->shutdown = usb_phy_shutdown;
>>>> +
>>>> +       platform_set_drvdata(pdev, mv_phy);
>>>> +
>>>> +       the_phy = mv_phy;
>>>
>>>
>>>
>>> Is there any specific reason for not using the usb phy library?
>>> Please use the APIs provided in drivers/usb/otg/otg.c.
>>> These APIs will be moved to phy.c soon.
>>>
>>> Thanks
>>> Kishon
>>
>>
>> The phy in driver/usb/otg/otg.c is bound to OTG. The major target of
>> this APIs in OTG is help functions for OTG support.
>
>
> Not really. Much of what's in otg.c is related to PHY and we have an action
> item to rename otg.c to phy.c. Sascha hauer has already sent a patch for it.
>
>> I have used it and implemented it at mv_otg.c for OTG support. The
>> APIs only allow one phy driver register to it.
>
>
> PHY library has changed quite a bit since then. You might want to have a
> look at usb/otg/otg.c again in usb-next.
>
Thanks for your suggestion.

I have taken look at the otg.c again.
The problem is the phy list only allow a single phy driver for each type.
It defines only two valid types

        USB_PHY_TYPE_USB2,
        USB_PHY_TYPE_USB3,
when invoke usb_add_phy  to add a phy driver, if USB_PHY_TYPE_USB2 has
been added, it will return error
some piece of the code is listed below

list_for_each_entry(phy, &phy_list, head) {
                if (phy->type == type) {
                        ret = -EBUSY;
                        dev_err(x->dev, "transceiver type %s already exists\n",
                                                usb_phy_type_string(type));
                        goto out;
                }
        }

The USB IP we used includes EHCI and UDC controller together, and it
can support OTG functions.
When either mode(EHCI/UDC) is used, the PHY blocks should be enabled
because it controller to turn
the internal signals of USB IP block to the D+/D-/VBUS signals we see.
So if we register this phy to be type USB_PHY_TYPE_USB2, then how about OTG?
For OTG support we need register the PHY to complete the device->host
and host->device transaction, if we register it as
USB_PHY_TYPE_USB2, the registertation will fail.

So there will be three ways to do the job
way1:
1. invoke usb_add_phy in phy driver with type of USB_PHY_TYPE_USB2,
and initialize the callbacks
2. in usb otg driver, invoke usb_get_phy and initialize the otg part
way1 seems a little tricky because when the phy initialize is
seperated into two parts.

way2:
change the otg.c and make it can add mutiple phy for the type.
It takes time and will impact many drivers. I hope i can do it after i
have completed my patches.

way3:
It is what i have done in the patch series.


> Thanks
> Kishon

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-07  2:26         ` Chao Xie
@ 2013-02-07  5:57           ` kishon
  2013-02-18  2:53             ` Chao Xie
  0 siblings, 1 reply; 25+ messages in thread
From: kishon @ 2013-02-07  5:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Thursday 07 February 2013 07:56 AM, Chao Xie wrote:
> On Wed, Feb 6, 2013 at 6:35 PM, kishon <kishon@ti.com> wrote:
>> Hi,
>>
>>
>> On Wednesday 06 February 2013 01:48 PM, Chao Xie wrote:
>>>
>>> On Wed, Feb 6, 2013 at 4:10 PM, kishon <kishon@ti.com> wrote:
>>>>
>>>> Hi,
>>>>
>>>>
>>>> On Wednesday 06 February 2013 12:53 PM, Chao Xie wrote:
>>>>>
>>>>>
>>>>> The PHY is seperated from usb controller.
>>>>> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
>>>>> but PHY initialization may be different.
>>>>> the usb controller can support udc/otg/ehci, and for each of
>>>>> the mode, it need PHY to initialized before use the controller.
>>>>> Direclty writing the phy driver will make the usb controller
>>>>> driver to be simple and portable.
>>>>> The PHY driver will be used by marvell udc/otg/ehci.
>>>>>
>>>>> Signed-off-by: Chao Xie <chao.xie@marvell.com>
>>>>> ---
>>>>>     drivers/usb/phy/Kconfig              |    7 +
>>>>>     drivers/usb/phy/Makefile             |    1 +
>>>>>     drivers/usb/phy/mv_usb2_phy.c        |  454
>>>>> ++++++++++++++++++++++++++++++++++
>>>>>     include/linux/platform_data/mv_usb.h |    9 +-
>>>>>     include/linux/usb/mv_usb2.h          |   43 ++++
>>>>>     5 files changed, 511 insertions(+), 3 deletions(-)
>>>>>     create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>>>>>     create mode 100644 include/linux/usb/mv_usb2.h
>>>>>
>>>>> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
>>>>> index 65217a5..5479760 100644
>>>>> --- a/drivers/usb/phy/Kconfig
>>>>> +++ b/drivers/usb/phy/Kconfig
>>>>> @@ -73,3 +73,10 @@ config SAMSUNG_USBPHY
>>>>>           help
>>>>>             Enable this to support Samsung USB phy controller for samsung
>>>>>             SoCs.
>>>>> +
>>>>> +config MV_USB2_PHY
>>>>> +       tristate "Marvell USB 2.0 PHY Driver"
>>>>> +       depends on USB || USB_GADGET
>>>>> +       help
>>>>> +         Enable this to support Marvell USB 2.0 phy driver for Marvell
>>>>> +         SoC.
>>>>> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
>>>>> index b13faa1..3835316 100644
>>>>> --- a/drivers/usb/phy/Makefile
>>>>> +++ b/drivers/usb/phy/Makefile
>>>>> @@ -12,3 +12,4 @@ obj-$(CONFIG_MV_U3D_PHY)              += mv_u3d_phy.o
>>>>>     obj-$(CONFIG_USB_EHCI_TEGRA)  += tegra_usb_phy.o
>>>>>     obj-$(CONFIG_USB_RCAR_PHY)            += rcar-phy.o
>>>>>     obj-$(CONFIG_SAMSUNG_USBPHY)          += samsung-usbphy.o
>>>>> +obj-$(CONFIG_MV_USB2_PHY)              += mv_usb2_phy.o
>>>>> diff --git a/drivers/usb/phy/mv_usb2_phy.c
>>>>> b/drivers/usb/phy/mv_usb2_phy.c
>>>>> new file mode 100644
>>>>> index 0000000..c2bccae
>>>>> --- /dev/null
>>>>> +++ b/drivers/usb/phy/mv_usb2_phy.c
>>>>> @@ -0,0 +1,454 @@
>>>>> +/*
>>>>> + * Copyright (C) 2010 Google, Inc.
>>>>> + *
>>>>> + * Author:
>>>>> + *     Chao Xie <xiechao.mail@gmail.com>
>>>>> + *
>>>>> + * This software is licensed under the terms of the GNU General Public
>>>>> + * License version 2, as published by the Free Software Foundation, and
>>>>> + * may be copied, distributed, and modified under those terms.
>>>>> + *
>>>>> + * 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/resource.h>
>>>>> +#include <linux/delay.h>
>>>>> +#include <linux/slab.h>
>>>>> +#include <linux/of.h>
>>>>> +#include <linux/of_device.h>
>>>>> +#include <linux/io.h>
>>>>> +#include <linux/err.h>
>>>>> +#include <linux/clk.h>
>>>>> +#include <linux/export.h>
>>>>> +#include <linux/module.h>
>>>>> +#include <linux/platform_device.h>
>>>>> +#include <linux/platform_data/mv_usb.h>
>>>>> +#include <linux/usb/mv_usb2.h>
>>>>> +
>>>>> +/* phy regs */
>>>>> +#define UTMI_REVISION          0x0
>>>>> +#define UTMI_CTRL              0x4
>>>>> +#define UTMI_PLL               0x8
>>>>> +#define UTMI_TX                        0xc
>>>>> +#define UTMI_RX                        0x10
>>>>> +#define UTMI_IVREF             0x14
>>>>> +#define UTMI_T0                        0x18
>>>>> +#define UTMI_T1                        0x1c
>>>>> +#define UTMI_T2                        0x20
>>>>> +#define UTMI_T3                        0x24
>>>>> +#define UTMI_T4                        0x28
>>>>> +#define UTMI_T5                        0x2c
>>>>> +#define UTMI_RESERVE           0x30
>>>>> +#define UTMI_USB_INT           0x34
>>>>> +#define UTMI_DBG_CTL           0x38
>>>>> +#define UTMI_OTG_ADDON         0x3c
>>>>> +
>>>>> +/* For UTMICTRL Register */
>>>>> +#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
>>>>> +/* pxa168 */
>>>>> +#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
>>>>> +#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
>>>>> +#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
>>>>> +#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
>>>>> +
>>>>> +#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
>>>>> +#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT                28
>>>>> +#define UTMI_CTRL_PU_REF_SHIFT                 20
>>>>> +#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
>>>>> +#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
>>>>> +#define UTMI_CTRL_PWR_UP_SHIFT                  0
>>>>> +
>>>>> +/* For UTMI_PLL Register */
>>>>> +#define UTMI_PLL_PLLCALI12_SHIFT               29
>>>>> +#define UTMI_PLL_PLLCALI12_MASK                        (0x3 << 29)
>>>>> +
>>>>> +#define UTMI_PLL_PLLVDD18_SHIFT                        27
>>>>> +#define UTMI_PLL_PLLVDD18_MASK                 (0x3 << 27)
>>>>> +
>>>>> +#define UTMI_PLL_PLLVDD12_SHIFT                        25
>>>>> +#define UTMI_PLL_PLLVDD12_MASK                 (0x3 << 25)
>>>>> +
>>>>> +#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
>>>>> +#define CLK_BLK_EN                              (0x1 << 24)
>>>>> +#define PLL_READY                               (0x1 << 23)
>>>>> +#define KVCO_EXT                                (0x1 << 22)
>>>>> +#define VCOCAL_START                            (0x1 << 21)
>>>>> +
>>>>> +#define UTMI_PLL_KVCO_SHIFT                    15
>>>>> +#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
>>>>> +
>>>>> +#define UTMI_PLL_ICP_SHIFT                     12
>>>>> +#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
>>>>> +
>>>>> +#define UTMI_PLL_FBDIV_SHIFT                    4
>>>>> +#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
>>>>> +
>>>>> +#define UTMI_PLL_REFDIV_SHIFT                   0
>>>>> +#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
>>>>> +
>>>>> +/* For UTMI_TX Register */
>>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT          27
>>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_MASK           (0xf << 27)
>>>>> +
>>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT       26
>>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK                (0x1 << 26)
>>>>> +
>>>>> +#define UTMI_TX_TXVDD12_SHIFT                   22
>>>>> +#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
>>>>> +
>>>>> +#define UTMI_TX_CK60_PHSEL_SHIFT                17
>>>>> +#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
>>>>> +
>>>>> +#define UTMI_TX_IMPCAL_VTH_SHIFT                14
>>>>> +#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
>>>>> +
>>>>> +#define REG_RCAL_START                          (0x1 << 12)
>>>>> +
>>>>> +#define UTMI_TX_LOW_VDD_EN_SHIFT                11
>>>>> +
>>>>> +#define UTMI_TX_AMP_SHIFT                      0
>>>>> +#define UTMI_TX_AMP_MASK                       (0x7 << 0)
>>>>> +
>>>>> +/* For UTMI_RX Register */
>>>>> +#define UTMI_REG_SQ_LENGTH_SHIFT                15
>>>>> +#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
>>>>> +
>>>>> +#define UTMI_RX_SQ_THRESH_SHIFT                 4
>>>>> +#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
>>>>> +
>>>>> +#define UTMI_OTG_ADDON_OTG_ON                  (1 << 0)
>>>>> +
>>>>> +enum mv_usb2_phy_type {
>>>>> +       PXA168_USB,
>>>>> +       PXA910_USB,
>>>>> +       MMP2_USB,
>>>>> +};
>>>>> +
>>>>> +static struct mv_usb2_phy *the_phy;
>>>>> +
>>>>> +struct mv_usb2_phy *mv_usb2_get_phy(void)
>>>>> +{
>>>>> +       return the_phy;
>>>>> +}
>>>>> +EXPORT_SYMBOL(mv_usb2_get_phy);
>>>>> +
>>>>> +static unsigned int u2o_get(void __iomem *base, unsigned int offset)
>>>>> +{
>>>>> +       return readl(base + offset);
>>>>> +}
>>>>> +
>>>>> +static void u2o_set(void __iomem *base, unsigned int offset,
>>>>> +               unsigned int value)
>>>>> +{
>>>>> +       u32 reg;
>>>>> +
>>>>> +       reg = readl(base + offset);
>>>>> +       reg |= value;
>>>>> +       writel(reg, base + offset);
>>>>> +       readl(base + offset);
>>>>> +}
>>>>> +
>>>>> +static void u2o_clear(void __iomem *base, unsigned int offset,
>>>>> +               unsigned int value)
>>>>> +{
>>>>> +       u32 reg;
>>>>> +
>>>>> +       reg = readl(base + offset);
>>>>> +       reg &= ~value;
>>>>> +       writel(reg, base + offset);
>>>>> +       readl(base + offset);
>>>>> +}
>>>>> +
>>>>> +static void u2o_write(void __iomem *base, unsigned int offset,
>>>>> +               unsigned int value)
>>>>> +{
>>>>> +       writel(value, base + offset);
>>>>> +       readl(base + offset);
>>>>> +}
>>>>> +
>>>>> +static int _usb_phy_init(struct mv_usb2_phy *mv_phy)
>>>>> +{
>>>>> +       struct platform_device *pdev = mv_phy->pdev;
>>>>> +       unsigned int loops = 0;
>>>>> +       void __iomem *base = mv_phy->base;
>>>>> +
>>>>> +       dev_dbg(&pdev->dev, "phy init\n");
>>>>> +
>>>>> +       /* Initialize the USB PHY power */
>>>>> +       if (mv_phy->type == PXA910_USB) {
>>>>> +               u2o_set(base, UTMI_CTRL,
>>>>> (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
>>>>> +                       | (1<<UTMI_CTRL_PU_REF_SHIFT));
>>>>> +       }
>>>>> +
>>>>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>>>>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>>>>> +
>>>>> +       /* UTMI_PLL settings */
>>>>> +       u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
>>>>> +               | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
>>>>> +               | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
>>>>> +               | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
>>>>> +
>>>>> +       u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
>>>>> +               | 0xb<<UTMI_PLL_REFDIV_SHIFT |
>>>>> 3<<UTMI_PLL_PLLVDD18_SHIFT
>>>>> +               | 3<<UTMI_PLL_PLLVDD12_SHIFT |
>>>>> 3<<UTMI_PLL_PLLCALI12_SHIFT
>>>>> +               | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
>>>>> +
>>>>> +       /* UTMI_TX */
>>>>> +       u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
>>>>> +               | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
>>>>> +               | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
>>>>> +               | UTMI_TX_AMP_MASK);
>>>>> +       u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
>>>>> +               | 4<<UTMI_TX_CK60_PHSEL_SHIFT |
>>>>> 4<<UTMI_TX_IMPCAL_VTH_SHIFT
>>>>> +               | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT |
>>>>> 3<<UTMI_TX_AMP_SHIFT);
>>>>> +
>>>>> +       /* UTMI_RX */
>>>>> +       u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
>>>>> +               | UTMI_REG_SQ_LENGTH_MASK);
>>>>> +       u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
>>>>> +               | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
>>>>> +
>>>>> +       /* UTMI_IVREF */
>>>>> +       if (mv_phy->type == PXA168_USB)
>>>>> +               /* fixing Microsoft Altair board interface with NEC hub
>>>>> issue -
>>>>> +                * Set UTMI_IVREF from 0x4a3 to 0x4bf */
>>>>> +               u2o_write(base, UTMI_IVREF, 0x4bf);
>>>>> +
>>>>> +       /* toggle VCOCAL_START bit of UTMI_PLL */
>>>>> +       udelay(200);
>>>>> +       u2o_set(base, UTMI_PLL, VCOCAL_START);
>>>>> +       udelay(40);
>>>>> +       u2o_clear(base, UTMI_PLL, VCOCAL_START);
>>>>> +
>>>>> +       /* toggle REG_RCAL_START bit of UTMI_TX */
>>>>> +       udelay(400);
>>>>> +       u2o_set(base, UTMI_TX, REG_RCAL_START);
>>>>> +       udelay(40);
>>>>> +       u2o_clear(base, UTMI_TX, REG_RCAL_START);
>>>>> +       udelay(400);
>>>>> +
>>>>> +       /* Make sure PHY PLL is ready */
>>>>> +       loops = 0;
>>>>> +       while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
>>>>> +               mdelay(1);
>>>>> +               loops++;
>>>>> +               if (loops > 100) {
>>>>> +                       dev_warn(&pdev->dev, "calibrate timeout,
>>>>> UTMI_PLL
>>>>> %x\n",
>>>>> +                               u2o_get(base, UTMI_PLL));
>>>>> +                       break;
>>>>> +               }
>>>>> +       }
>>>>> +
>>>>> +       if (mv_phy->type == PXA168_USB) {
>>>>> +               u2o_set(base, UTMI_RESERVE, 1 << 5);
>>>>> +               /* Turn on UTMI PHY OTG extension */
>>>>> +               u2o_write(base, UTMI_OTG_ADDON, 1);
>>>>> +       }
>>>>> +
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +static int _usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>>>>> +{
>>>>> +       void __iomem *base = mv_phy->base;
>>>>> +
>>>>> +       if (mv_phy->type == PXA168_USB)
>>>>> +               u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
>>>>> +
>>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
>>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
>>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
>>>>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>>>>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>>>>> +
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +static int usb_phy_init(struct mv_usb2_phy *mv_phy)
>>>>> +{
>>>>> +       int i = 0;
>>>>> +
>>>>> +       mutex_lock(&mv_phy->phy_lock);
>>>>> +       if (mv_phy->refcount++ == 0) {
>>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>>> +                       clk_prepare_enable(mv_phy->clks[i]);
>>>>> +               _usb_phy_init(mv_phy);
>>>>> +       }
>>>>> +       mutex_unlock(&mv_phy->phy_lock);
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +static void usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>>>>> +{
>>>>> +       int i = 0;
>>>>> +
>>>>> +       mutex_lock(&mv_phy->phy_lock);
>>>>> +       if (mv_phy->refcount++ == 0) {
>>>>> +               _usb_phy_shutdown(mv_phy);
>>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>>> +                       clk_disable_unprepare(mv_phy->clks[i]);
>>>>> +       }
>>>>> +       mutex_unlock(&mv_phy->phy_lock);
>>>>> +}
>>>>> +
>>>>> +static struct of_device_id usb_phy_dt_ids[] = {
>>>>> +       { .compatible = "mrvl,pxa168-usb-phy",  .data = (void
>>>>> *)PXA168_USB},
>>>>> +       { .compatible = "mrvl,pxa910-usb-phy",  .data = (void
>>>>> *)PXA910_USB},
>>>>> +       { .compatible = "mrvl,mmp2-usb-phy",    .data = (void
>>>>> *)MMP2_USB},
>>>>> +       {}
>>>>> +};
>>>>> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);
>>>>> +
>>>>> +static int usb_phy_parse_dt(struct platform_device *pdev,
>>>>> +                               struct mv_usb2_phy *mv_phy)
>>>>> +{
>>>>> +       struct device_node *np = pdev->dev.of_node;
>>>>> +       const struct of_device_id *of_id =
>>>>> +                       of_match_device(usb_phy_dt_ids, &pdev->dev);
>>>>> +       unsigned int clks_num;
>>>>> +       int i, ret;
>>>>> +       const char *clk_name;
>>>>> +
>>>>> +       if (!np)
>>>>> +               return 1;
>>>>> +
>>>>> +       clks_num = of_property_count_strings(np, "clocks");
>>>>> +       if (clks_num < 0) {
>>>>> +               dev_err(&pdev->dev, "failed to get clock number\n");
>>>>> +               return clks_num;
>>>>> +       }
>>>>> +
>>>>> +       mv_phy->clks = devm_kzalloc(&pdev->dev,
>>>>> +               sizeof(struct clk *) * clks_num, GFP_KERNEL);
>>>>> +       if (mv_phy->clks == NULL) {
>>>>> +               dev_err(&pdev->dev,
>>>>> +                       "failed to allocate mempory for clocks");
>>>>> +               return -ENOMEM;
>>>>> +       }
>>>>> +
>>>>> +       for (i = 0; i < clks_num; i++) {
>>>>> +               ret = of_property_read_string_index(np, "clocks", i,
>>>>> +                       &clk_name);
>>>>> +               if (ret) {
>>>>> +                       dev_err(&pdev->dev, "failed to read clocks\n");
>>>>> +                       return ret;
>>>>> +               }
>>>>> +               mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
>>>>> +               if (IS_ERR(mv_phy->clks[i])) {
>>>>> +                       dev_err(&pdev->dev, "failed to get clock %s\n",
>>>>> +                               clk_name);
>>>>> +                       return PTR_ERR(mv_phy->clks[i]);
>>>>> +               }
>>>>> +       }
>>>>> +
>>>>> +       mv_phy->clks_num = clks_num;
>>>>> +       mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
>>>>> +
>>>>> +       return 0;
>>>>> +}
>>>>> +
>>>>> +static int usb_phy_probe(struct platform_device *pdev)
>>>>> +{
>>>>> +       struct mv_usb2_phy *mv_phy;
>>>>> +       struct resource *r;
>>>>> +       int ret, i;
>>>>> +
>>>>> +       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
>>>>> +       if (mv_phy == NULL) {
>>>>> +               dev_err(&pdev->dev, "failed to allocate memory\n");
>>>>> +               return -ENOMEM;
>>>>> +       }
>>>>> +       mutex_init(&mv_phy->phy_lock);
>>>>> +
>>>>> +       ret = usb_phy_parse_dt(pdev, mv_phy);
>>>>> +       /* no CONFIG_OF */
>>>>> +       if (ret > 0) {
>>>>> +               struct mv_usb_phy_platform_data *pdata
>>>>> +                               = pdev->dev.platform_data;
>>>>> +               const struct platform_device_id *id
>>>>> +                               = platform_get_device_id(pdev);
>>>>> +
>>>>> +               if (pdata == NULL || id == NULL) {
>>>>> +                       dev_err(&pdev->dev,
>>>>> +                               "missing platform_data or id_entry\n");
>>>>> +                       return -ENODEV;
>>>>> +               }
>>>>> +               mv_phy->type = (unsigned int)(id->driver_data);
>>>>> +               mv_phy->clks_num = pdata->clknum;
>>>>> +               mv_phy->clks = devm_kzalloc(&pdev->dev,
>>>>> +                       sizeof(struct clk *) * mv_phy->clks_num,
>>>>> GFP_KERNEL);
>>>>> +               if (mv_phy->clks == NULL) {
>>>>> +                       dev_err(&pdev->dev,
>>>>> +                               "failed to allocate mempory for
>>>>> clocks");
>>>>> +                       return -ENOMEM;
>>>>> +               }
>>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>>> +                       mv_phy->clks[i] = devm_clk_get(&pdev->dev,
>>>>> +
>>>>> pdata->clkname[i]);
>>>>> +                       if (IS_ERR(mv_phy->clks[i])) {
>>>>> +                               dev_err(&pdev->dev, "failed to get clock
>>>>> %s\n",
>>>>> +                                       pdata->clkname[i]);
>>>>> +                               return PTR_ERR(mv_phy->clks[i]);
>>>>> +                       }
>>>>> +       } else if (ret < 0) {
>>>>> +               dev_err(&pdev->dev, "error parse dt\n");
>>>>> +               return ret;
>>>>> +       }
>>>>> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>> +       if (r == NULL) {
>>>>> +               dev_err(&pdev->dev, "no phy I/O memory resource
>>>>> defined\n");
>>>>> +               return -ENODEV;
>>>>> +       }
>>>>> +       mv_phy->base = devm_ioremap(&pdev->dev, r->start,
>>>>> resource_size(r));
>>>>> +       if (mv_phy->base == NULL) {
>>>>> +               dev_err(&pdev->dev, "error map register base\n");
>>>>> +               return -EBUSY;
>>>>> +       }
>>>>> +       platform_set_drvdata(pdev, mv_phy);
>>>>> +       mv_phy->pdev = pdev;
>>>>> +       mv_phy->init = usb_phy_init;
>>>>> +       mv_phy->shutdown = usb_phy_shutdown;
>>>>> +
>>>>> +       platform_set_drvdata(pdev, mv_phy);
>>>>> +
>>>>> +       the_phy = mv_phy;
>>>>
>>>>
>>>>
>>>> Is there any specific reason for not using the usb phy library?
>>>> Please use the APIs provided in drivers/usb/otg/otg.c.
>>>> These APIs will be moved to phy.c soon.
>>>>
>>>> Thanks
>>>> Kishon
>>>
>>>
>>> The phy in driver/usb/otg/otg.c is bound to OTG. The major target of
>>> this APIs in OTG is help functions for OTG support.
>>
>>
>> Not really. Much of what's in otg.c is related to PHY and we have an action
>> item to rename otg.c to phy.c. Sascha hauer has already sent a patch for it.
>>
>>> I have used it and implemented it at mv_otg.c for OTG support. The
>>> APIs only allow one phy driver register to it.
>>
>>
>> PHY library has changed quite a bit since then. You might want to have a
>> look at usb/otg/otg.c again in usb-next.
>>
> Thanks for your suggestion.
>
> I have taken look at the otg.c again.
> The problem is the phy list only allow a single phy driver for each type.
> It defines only two valid types
>
>          USB_PHY_TYPE_USB2,
>          USB_PHY_TYPE_USB3,
> when invoke usb_add_phy  to add a phy driver, if USB_PHY_TYPE_USB2 has
> been added, it will return error
> some piece of the code is listed below
>
> list_for_each_entry(phy, &phy_list, head) {
>                  if (phy->type == type) {
>                          ret = -EBUSY;
>                          dev_err(x->dev, "transceiver type %s already exists\n",
>                                                  usb_phy_type_string(type));
>                          goto out;
>                  }
>          }
>
> The USB IP we used includes EHCI and UDC controller together, and it
> can support OTG functions.
> When either mode(EHCI/UDC) is used, the PHY blocks should be enabled
> because it controller to turn
> the internal signals of USB IP block to the D+/D-/VBUS signals we see.
> So if we register this phy to be type USB_PHY_TYPE_USB2, then how about OTG?
> For OTG support we need register the PHY to complete the device->host
> and host->device transaction, if we register it as
> USB_PHY_TYPE_USB2, the registertation will fail.
>
> So there will be three ways to do the job
> way1:
> 1. invoke usb_add_phy in phy driver with type of USB_PHY_TYPE_USB2,
> and initialize the callbacks
> 2. in usb otg driver, invoke usb_get_phy and initialize the otg part
> way1 seems a little tricky because when the phy initialize is
> seperated into two parts.
>
> way2:
> change the otg.c and make it can add mutiple phy for the type.
> It takes time and will impact many drivers. I hope i can do it after i
> have completed my patches.

This is already done. We have added API's like usb_add_phy_dev() for the 
same purpose. Now you can use usb_add_phy_dev() to add multiple PHYs (of 
same type or different) and then get the PHY using usb_get_phy_dev(). 
Note that you should use usb_bind_phy() in platform initialization file 
for binding the controller to the PHY.

These patches are merged in usb-next
http://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-next

Thanks
Kishon

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller
  2013-02-07  5:57           ` kishon
@ 2013-02-18  2:53             ` Chao Xie
  0 siblings, 0 replies; 25+ messages in thread
From: Chao Xie @ 2013-02-18  2:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 7, 2013 at 1:57 PM, kishon <kishon@ti.com> wrote:
> Hi,
>
>
> On Thursday 07 February 2013 07:56 AM, Chao Xie wrote:
>>
>> On Wed, Feb 6, 2013 at 6:35 PM, kishon <kishon@ti.com> wrote:
>>>
>>> Hi,
>>>
>>>
>>> On Wednesday 06 February 2013 01:48 PM, Chao Xie wrote:
>>>>
>>>>
>>>> On Wed, Feb 6, 2013 at 4:10 PM, kishon <kishon@ti.com> wrote:
>>>>>
>>>>>
>>>>> Hi,
>>>>>
>>>>>
>>>>> On Wednesday 06 February 2013 12:53 PM, Chao Xie wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> The PHY is seperated from usb controller.
>>>>>> The usb controller used in marvell pxa168/pxa910/mmp2 are same,
>>>>>> but PHY initialization may be different.
>>>>>> the usb controller can support udc/otg/ehci, and for each of
>>>>>> the mode, it need PHY to initialized before use the controller.
>>>>>> Direclty writing the phy driver will make the usb controller
>>>>>> driver to be simple and portable.
>>>>>> The PHY driver will be used by marvell udc/otg/ehci.
>>>>>>
>>>>>> Signed-off-by: Chao Xie <chao.xie@marvell.com>
>>>>>> ---
>>>>>>     drivers/usb/phy/Kconfig              |    7 +
>>>>>>     drivers/usb/phy/Makefile             |    1 +
>>>>>>     drivers/usb/phy/mv_usb2_phy.c        |  454
>>>>>> ++++++++++++++++++++++++++++++++++
>>>>>>     include/linux/platform_data/mv_usb.h |    9 +-
>>>>>>     include/linux/usb/mv_usb2.h          |   43 ++++
>>>>>>     5 files changed, 511 insertions(+), 3 deletions(-)
>>>>>>     create mode 100644 drivers/usb/phy/mv_usb2_phy.c
>>>>>>     create mode 100644 include/linux/usb/mv_usb2.h
>>>>>>
>>>>>> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
>>>>>> index 65217a5..5479760 100644
>>>>>> --- a/drivers/usb/phy/Kconfig
>>>>>> +++ b/drivers/usb/phy/Kconfig
>>>>>> @@ -73,3 +73,10 @@ config SAMSUNG_USBPHY
>>>>>>           help
>>>>>>             Enable this to support Samsung USB phy controller for
>>>>>> samsung
>>>>>>             SoCs.
>>>>>> +
>>>>>> +config MV_USB2_PHY
>>>>>> +       tristate "Marvell USB 2.0 PHY Driver"
>>>>>> +       depends on USB || USB_GADGET
>>>>>> +       help
>>>>>> +         Enable this to support Marvell USB 2.0 phy driver for
>>>>>> Marvell
>>>>>> +         SoC.
>>>>>> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
>>>>>> index b13faa1..3835316 100644
>>>>>> --- a/drivers/usb/phy/Makefile
>>>>>> +++ b/drivers/usb/phy/Makefile
>>>>>> @@ -12,3 +12,4 @@ obj-$(CONFIG_MV_U3D_PHY)              +=
>>>>>> mv_u3d_phy.o
>>>>>>     obj-$(CONFIG_USB_EHCI_TEGRA)  += tegra_usb_phy.o
>>>>>>     obj-$(CONFIG_USB_RCAR_PHY)            += rcar-phy.o
>>>>>>     obj-$(CONFIG_SAMSUNG_USBPHY)          += samsung-usbphy.o
>>>>>> +obj-$(CONFIG_MV_USB2_PHY)              += mv_usb2_phy.o
>>>>>> diff --git a/drivers/usb/phy/mv_usb2_phy.c
>>>>>> b/drivers/usb/phy/mv_usb2_phy.c
>>>>>> new file mode 100644
>>>>>> index 0000000..c2bccae
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/usb/phy/mv_usb2_phy.c
>>>>>> @@ -0,0 +1,454 @@
>>>>>> +/*
>>>>>> + * Copyright (C) 2010 Google, Inc.
>>>>>> + *
>>>>>> + * Author:
>>>>>> + *     Chao Xie <xiechao.mail@gmail.com>
>>>>>> + *
>>>>>> + * This software is licensed under the terms of the GNU General
>>>>>> Public
>>>>>> + * License version 2, as published by the Free Software Foundation,
>>>>>> and
>>>>>> + * may be copied, distributed, and modified under those terms.
>>>>>> + *
>>>>>> + * 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/resource.h>
>>>>>> +#include <linux/delay.h>
>>>>>> +#include <linux/slab.h>
>>>>>> +#include <linux/of.h>
>>>>>> +#include <linux/of_device.h>
>>>>>> +#include <linux/io.h>
>>>>>> +#include <linux/err.h>
>>>>>> +#include <linux/clk.h>
>>>>>> +#include <linux/export.h>
>>>>>> +#include <linux/module.h>
>>>>>> +#include <linux/platform_device.h>
>>>>>> +#include <linux/platform_data/mv_usb.h>
>>>>>> +#include <linux/usb/mv_usb2.h>
>>>>>> +
>>>>>> +/* phy regs */
>>>>>> +#define UTMI_REVISION          0x0
>>>>>> +#define UTMI_CTRL              0x4
>>>>>> +#define UTMI_PLL               0x8
>>>>>> +#define UTMI_TX                        0xc
>>>>>> +#define UTMI_RX                        0x10
>>>>>> +#define UTMI_IVREF             0x14
>>>>>> +#define UTMI_T0                        0x18
>>>>>> +#define UTMI_T1                        0x1c
>>>>>> +#define UTMI_T2                        0x20
>>>>>> +#define UTMI_T3                        0x24
>>>>>> +#define UTMI_T4                        0x28
>>>>>> +#define UTMI_T5                        0x2c
>>>>>> +#define UTMI_RESERVE           0x30
>>>>>> +#define UTMI_USB_INT           0x34
>>>>>> +#define UTMI_DBG_CTL           0x38
>>>>>> +#define UTMI_OTG_ADDON         0x3c
>>>>>> +
>>>>>> +/* For UTMICTRL Register */
>>>>>> +#define UTMI_CTRL_USB_CLK_EN                    (1 << 31)
>>>>>> +/* pxa168 */
>>>>>> +#define UTMI_CTRL_SUSPEND_SET1                  (1 << 30)
>>>>>> +#define UTMI_CTRL_SUSPEND_SET2                  (1 << 29)
>>>>>> +#define UTMI_CTRL_RXBUF_PDWN                    (1 << 24)
>>>>>> +#define UTMI_CTRL_TXBUF_PDWN                    (1 << 11)
>>>>>> +
>>>>>> +#define UTMI_CTRL_INPKT_DELAY_SHIFT             30
>>>>>> +#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT                28
>>>>>> +#define UTMI_CTRL_PU_REF_SHIFT                 20
>>>>>> +#define UTMI_CTRL_ARC_PULLDN_SHIFT              12
>>>>>> +#define UTMI_CTRL_PLL_PWR_UP_SHIFT              1
>>>>>> +#define UTMI_CTRL_PWR_UP_SHIFT                  0
>>>>>> +
>>>>>> +/* For UTMI_PLL Register */
>>>>>> +#define UTMI_PLL_PLLCALI12_SHIFT               29
>>>>>> +#define UTMI_PLL_PLLCALI12_MASK                        (0x3 << 29)
>>>>>> +
>>>>>> +#define UTMI_PLL_PLLVDD18_SHIFT                        27
>>>>>> +#define UTMI_PLL_PLLVDD18_MASK                 (0x3 << 27)
>>>>>> +
>>>>>> +#define UTMI_PLL_PLLVDD12_SHIFT                        25
>>>>>> +#define UTMI_PLL_PLLVDD12_MASK                 (0x3 << 25)
>>>>>> +
>>>>>> +#define UTMI_PLL_CLK_BLK_EN_SHIFT               24
>>>>>> +#define CLK_BLK_EN                              (0x1 << 24)
>>>>>> +#define PLL_READY                               (0x1 << 23)
>>>>>> +#define KVCO_EXT                                (0x1 << 22)
>>>>>> +#define VCOCAL_START                            (0x1 << 21)
>>>>>> +
>>>>>> +#define UTMI_PLL_KVCO_SHIFT                    15
>>>>>> +#define UTMI_PLL_KVCO_MASK                      (0x7 << 15)
>>>>>> +
>>>>>> +#define UTMI_PLL_ICP_SHIFT                     12
>>>>>> +#define UTMI_PLL_ICP_MASK                       (0x7 << 12)
>>>>>> +
>>>>>> +#define UTMI_PLL_FBDIV_SHIFT                    4
>>>>>> +#define UTMI_PLL_FBDIV_MASK                     (0xFF << 4)
>>>>>> +
>>>>>> +#define UTMI_PLL_REFDIV_SHIFT                   0
>>>>>> +#define UTMI_PLL_REFDIV_MASK                    (0xF << 0)
>>>>>> +
>>>>>> +/* For UTMI_TX Register */
>>>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT          27
>>>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_MASK           (0xf << 27)
>>>>>> +
>>>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT       26
>>>>>> +#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK                (0x1 << 26)
>>>>>> +
>>>>>> +#define UTMI_TX_TXVDD12_SHIFT                   22
>>>>>> +#define UTMI_TX_TXVDD12_MASK                    (0x3 << 22)
>>>>>> +
>>>>>> +#define UTMI_TX_CK60_PHSEL_SHIFT                17
>>>>>> +#define UTMI_TX_CK60_PHSEL_MASK                 (0xf << 17)
>>>>>> +
>>>>>> +#define UTMI_TX_IMPCAL_VTH_SHIFT                14
>>>>>> +#define UTMI_TX_IMPCAL_VTH_MASK                 (0x7 << 14)
>>>>>> +
>>>>>> +#define REG_RCAL_START                          (0x1 << 12)
>>>>>> +
>>>>>> +#define UTMI_TX_LOW_VDD_EN_SHIFT                11
>>>>>> +
>>>>>> +#define UTMI_TX_AMP_SHIFT                      0
>>>>>> +#define UTMI_TX_AMP_MASK                       (0x7 << 0)
>>>>>> +
>>>>>> +/* For UTMI_RX Register */
>>>>>> +#define UTMI_REG_SQ_LENGTH_SHIFT                15
>>>>>> +#define UTMI_REG_SQ_LENGTH_MASK                 (0x3 << 15)
>>>>>> +
>>>>>> +#define UTMI_RX_SQ_THRESH_SHIFT                 4
>>>>>> +#define UTMI_RX_SQ_THRESH_MASK                  (0xf << 4)
>>>>>> +
>>>>>> +#define UTMI_OTG_ADDON_OTG_ON                  (1 << 0)
>>>>>> +
>>>>>> +enum mv_usb2_phy_type {
>>>>>> +       PXA168_USB,
>>>>>> +       PXA910_USB,
>>>>>> +       MMP2_USB,
>>>>>> +};
>>>>>> +
>>>>>> +static struct mv_usb2_phy *the_phy;
>>>>>> +
>>>>>> +struct mv_usb2_phy *mv_usb2_get_phy(void)
>>>>>> +{
>>>>>> +       return the_phy;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(mv_usb2_get_phy);
>>>>>> +
>>>>>> +static unsigned int u2o_get(void __iomem *base, unsigned int offset)
>>>>>> +{
>>>>>> +       return readl(base + offset);
>>>>>> +}
>>>>>> +
>>>>>> +static void u2o_set(void __iomem *base, unsigned int offset,
>>>>>> +               unsigned int value)
>>>>>> +{
>>>>>> +       u32 reg;
>>>>>> +
>>>>>> +       reg = readl(base + offset);
>>>>>> +       reg |= value;
>>>>>> +       writel(reg, base + offset);
>>>>>> +       readl(base + offset);
>>>>>> +}
>>>>>> +
>>>>>> +static void u2o_clear(void __iomem *base, unsigned int offset,
>>>>>> +               unsigned int value)
>>>>>> +{
>>>>>> +       u32 reg;
>>>>>> +
>>>>>> +       reg = readl(base + offset);
>>>>>> +       reg &= ~value;
>>>>>> +       writel(reg, base + offset);
>>>>>> +       readl(base + offset);
>>>>>> +}
>>>>>> +
>>>>>> +static void u2o_write(void __iomem *base, unsigned int offset,
>>>>>> +               unsigned int value)
>>>>>> +{
>>>>>> +       writel(value, base + offset);
>>>>>> +       readl(base + offset);
>>>>>> +}
>>>>>> +
>>>>>> +static int _usb_phy_init(struct mv_usb2_phy *mv_phy)
>>>>>> +{
>>>>>> +       struct platform_device *pdev = mv_phy->pdev;
>>>>>> +       unsigned int loops = 0;
>>>>>> +       void __iomem *base = mv_phy->base;
>>>>>> +
>>>>>> +       dev_dbg(&pdev->dev, "phy init\n");
>>>>>> +
>>>>>> +       /* Initialize the USB PHY power */
>>>>>> +       if (mv_phy->type == PXA910_USB) {
>>>>>> +               u2o_set(base, UTMI_CTRL,
>>>>>> (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
>>>>>> +                       | (1<<UTMI_CTRL_PU_REF_SHIFT));
>>>>>> +       }
>>>>>> +
>>>>>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>>>>>> +       u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>>>>>> +
>>>>>> +       /* UTMI_PLL settings */
>>>>>> +       u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
>>>>>> +               | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
>>>>>> +               | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
>>>>>> +               | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
>>>>>> +
>>>>>> +       u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
>>>>>> +               | 0xb<<UTMI_PLL_REFDIV_SHIFT |
>>>>>> 3<<UTMI_PLL_PLLVDD18_SHIFT
>>>>>> +               | 3<<UTMI_PLL_PLLVDD12_SHIFT |
>>>>>> 3<<UTMI_PLL_PLLCALI12_SHIFT
>>>>>> +               | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
>>>>>> +
>>>>>> +       /* UTMI_TX */
>>>>>> +       u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
>>>>>> +               | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
>>>>>> +               | UTMI_TX_IMPCAL_VTH_MASK |
>>>>>> UTMI_TX_REG_EXT_FS_RCAL_MASK
>>>>>> +               | UTMI_TX_AMP_MASK);
>>>>>> +       u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
>>>>>> +               | 4<<UTMI_TX_CK60_PHSEL_SHIFT |
>>>>>> 4<<UTMI_TX_IMPCAL_VTH_SHIFT
>>>>>> +               | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT |
>>>>>> 3<<UTMI_TX_AMP_SHIFT);
>>>>>> +
>>>>>> +       /* UTMI_RX */
>>>>>> +       u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
>>>>>> +               | UTMI_REG_SQ_LENGTH_MASK);
>>>>>> +       u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
>>>>>> +               | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
>>>>>> +
>>>>>> +       /* UTMI_IVREF */
>>>>>> +       if (mv_phy->type == PXA168_USB)
>>>>>> +               /* fixing Microsoft Altair board interface with NEC
>>>>>> hub
>>>>>> issue -
>>>>>> +                * Set UTMI_IVREF from 0x4a3 to 0x4bf */
>>>>>> +               u2o_write(base, UTMI_IVREF, 0x4bf);
>>>>>> +
>>>>>> +       /* toggle VCOCAL_START bit of UTMI_PLL */
>>>>>> +       udelay(200);
>>>>>> +       u2o_set(base, UTMI_PLL, VCOCAL_START);
>>>>>> +       udelay(40);
>>>>>> +       u2o_clear(base, UTMI_PLL, VCOCAL_START);
>>>>>> +
>>>>>> +       /* toggle REG_RCAL_START bit of UTMI_TX */
>>>>>> +       udelay(400);
>>>>>> +       u2o_set(base, UTMI_TX, REG_RCAL_START);
>>>>>> +       udelay(40);
>>>>>> +       u2o_clear(base, UTMI_TX, REG_RCAL_START);
>>>>>> +       udelay(400);
>>>>>> +
>>>>>> +       /* Make sure PHY PLL is ready */
>>>>>> +       loops = 0;
>>>>>> +       while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
>>>>>> +               mdelay(1);
>>>>>> +               loops++;
>>>>>> +               if (loops > 100) {
>>>>>> +                       dev_warn(&pdev->dev, "calibrate timeout,
>>>>>> UTMI_PLL
>>>>>> %x\n",
>>>>>> +                               u2o_get(base, UTMI_PLL));
>>>>>> +                       break;
>>>>>> +               }
>>>>>> +       }
>>>>>> +
>>>>>> +       if (mv_phy->type == PXA168_USB) {
>>>>>> +               u2o_set(base, UTMI_RESERVE, 1 << 5);
>>>>>> +               /* Turn on UTMI PHY OTG extension */
>>>>>> +               u2o_write(base, UTMI_OTG_ADDON, 1);
>>>>>> +       }
>>>>>> +
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int _usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>>>>>> +{
>>>>>> +       void __iomem *base = mv_phy->base;
>>>>>> +
>>>>>> +       if (mv_phy->type == PXA168_USB)
>>>>>> +               u2o_clear(base, UTMI_OTG_ADDON,
>>>>>> UTMI_OTG_ADDON_OTG_ON);
>>>>>> +
>>>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
>>>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
>>>>>> +       u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
>>>>>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
>>>>>> +       u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
>>>>>> +
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int usb_phy_init(struct mv_usb2_phy *mv_phy)
>>>>>> +{
>>>>>> +       int i = 0;
>>>>>> +
>>>>>> +       mutex_lock(&mv_phy->phy_lock);
>>>>>> +       if (mv_phy->refcount++ == 0) {
>>>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>>>> +                       clk_prepare_enable(mv_phy->clks[i]);
>>>>>> +               _usb_phy_init(mv_phy);
>>>>>> +       }
>>>>>> +       mutex_unlock(&mv_phy->phy_lock);
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static void usb_phy_shutdown(struct mv_usb2_phy *mv_phy)
>>>>>> +{
>>>>>> +       int i = 0;
>>>>>> +
>>>>>> +       mutex_lock(&mv_phy->phy_lock);
>>>>>> +       if (mv_phy->refcount++ == 0) {
>>>>>> +               _usb_phy_shutdown(mv_phy);
>>>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>>>> +                       clk_disable_unprepare(mv_phy->clks[i]);
>>>>>> +       }
>>>>>> +       mutex_unlock(&mv_phy->phy_lock);
>>>>>> +}
>>>>>> +
>>>>>> +static struct of_device_id usb_phy_dt_ids[] = {
>>>>>> +       { .compatible = "mrvl,pxa168-usb-phy",  .data = (void
>>>>>> *)PXA168_USB},
>>>>>> +       { .compatible = "mrvl,pxa910-usb-phy",  .data = (void
>>>>>> *)PXA910_USB},
>>>>>> +       { .compatible = "mrvl,mmp2-usb-phy",    .data = (void
>>>>>> *)MMP2_USB},
>>>>>> +       {}
>>>>>> +};
>>>>>> +MODULE_DEVICE_TABLE(of, usb_phy_dt_ids);
>>>>>> +
>>>>>> +static int usb_phy_parse_dt(struct platform_device *pdev,
>>>>>> +                               struct mv_usb2_phy *mv_phy)
>>>>>> +{
>>>>>> +       struct device_node *np = pdev->dev.of_node;
>>>>>> +       const struct of_device_id *of_id =
>>>>>> +                       of_match_device(usb_phy_dt_ids, &pdev->dev);
>>>>>> +       unsigned int clks_num;
>>>>>> +       int i, ret;
>>>>>> +       const char *clk_name;
>>>>>> +
>>>>>> +       if (!np)
>>>>>> +               return 1;
>>>>>> +
>>>>>> +       clks_num = of_property_count_strings(np, "clocks");
>>>>>> +       if (clks_num < 0) {
>>>>>> +               dev_err(&pdev->dev, "failed to get clock number\n");
>>>>>> +               return clks_num;
>>>>>> +       }
>>>>>> +
>>>>>> +       mv_phy->clks = devm_kzalloc(&pdev->dev,
>>>>>> +               sizeof(struct clk *) * clks_num, GFP_KERNEL);
>>>>>> +       if (mv_phy->clks == NULL) {
>>>>>> +               dev_err(&pdev->dev,
>>>>>> +                       "failed to allocate mempory for clocks");
>>>>>> +               return -ENOMEM;
>>>>>> +       }
>>>>>> +
>>>>>> +       for (i = 0; i < clks_num; i++) {
>>>>>> +               ret = of_property_read_string_index(np, "clocks", i,
>>>>>> +                       &clk_name);
>>>>>> +               if (ret) {
>>>>>> +                       dev_err(&pdev->dev, "failed to read
>>>>>> clocks\n");
>>>>>> +                       return ret;
>>>>>> +               }
>>>>>> +               mv_phy->clks[i] = devm_clk_get(&pdev->dev, clk_name);
>>>>>> +               if (IS_ERR(mv_phy->clks[i])) {
>>>>>> +                       dev_err(&pdev->dev, "failed to get clock
>>>>>> %s\n",
>>>>>> +                               clk_name);
>>>>>> +                       return PTR_ERR(mv_phy->clks[i]);
>>>>>> +               }
>>>>>> +       }
>>>>>> +
>>>>>> +       mv_phy->clks_num = clks_num;
>>>>>> +       mv_phy->type = (enum mv_usb2_phy_type)(of_id->data);
>>>>>> +
>>>>>> +       return 0;
>>>>>> +}
>>>>>> +
>>>>>> +static int usb_phy_probe(struct platform_device *pdev)
>>>>>> +{
>>>>>> +       struct mv_usb2_phy *mv_phy;
>>>>>> +       struct resource *r;
>>>>>> +       int ret, i;
>>>>>> +
>>>>>> +       mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy),
>>>>>> GFP_KERNEL);
>>>>>> +       if (mv_phy == NULL) {
>>>>>> +               dev_err(&pdev->dev, "failed to allocate memory\n");
>>>>>> +               return -ENOMEM;
>>>>>> +       }
>>>>>> +       mutex_init(&mv_phy->phy_lock);
>>>>>> +
>>>>>> +       ret = usb_phy_parse_dt(pdev, mv_phy);
>>>>>> +       /* no CONFIG_OF */
>>>>>> +       if (ret > 0) {
>>>>>> +               struct mv_usb_phy_platform_data *pdata
>>>>>> +                               = pdev->dev.platform_data;
>>>>>> +               const struct platform_device_id *id
>>>>>> +                               = platform_get_device_id(pdev);
>>>>>> +
>>>>>> +               if (pdata == NULL || id == NULL) {
>>>>>> +                       dev_err(&pdev->dev,
>>>>>> +                               "missing platform_data or
>>>>>> id_entry\n");
>>>>>> +                       return -ENODEV;
>>>>>> +               }
>>>>>> +               mv_phy->type = (unsigned int)(id->driver_data);
>>>>>> +               mv_phy->clks_num = pdata->clknum;
>>>>>> +               mv_phy->clks = devm_kzalloc(&pdev->dev,
>>>>>> +                       sizeof(struct clk *) * mv_phy->clks_num,
>>>>>> GFP_KERNEL);
>>>>>> +               if (mv_phy->clks == NULL) {
>>>>>> +                       dev_err(&pdev->dev,
>>>>>> +                               "failed to allocate mempory for
>>>>>> clocks");
>>>>>> +                       return -ENOMEM;
>>>>>> +               }
>>>>>> +               for (i = 0; i < mv_phy->clks_num; i++)
>>>>>> +                       mv_phy->clks[i] = devm_clk_get(&pdev->dev,
>>>>>> +
>>>>>> pdata->clkname[i]);
>>>>>> +                       if (IS_ERR(mv_phy->clks[i])) {
>>>>>> +                               dev_err(&pdev->dev, "failed to get
>>>>>> clock
>>>>>> %s\n",
>>>>>> +                                       pdata->clkname[i]);
>>>>>> +                               return PTR_ERR(mv_phy->clks[i]);
>>>>>> +                       }
>>>>>> +       } else if (ret < 0) {
>>>>>> +               dev_err(&pdev->dev, "error parse dt\n");
>>>>>> +               return ret;
>>>>>> +       }
>>>>>> +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>> +       if (r == NULL) {
>>>>>> +               dev_err(&pdev->dev, "no phy I/O memory resource
>>>>>> defined\n");
>>>>>> +               return -ENODEV;
>>>>>> +       }
>>>>>> +       mv_phy->base = devm_ioremap(&pdev->dev, r->start,
>>>>>> resource_size(r));
>>>>>> +       if (mv_phy->base == NULL) {
>>>>>> +               dev_err(&pdev->dev, "error map register base\n");
>>>>>> +               return -EBUSY;
>>>>>> +       }
>>>>>> +       platform_set_drvdata(pdev, mv_phy);
>>>>>> +       mv_phy->pdev = pdev;
>>>>>> +       mv_phy->init = usb_phy_init;
>>>>>> +       mv_phy->shutdown = usb_phy_shutdown;
>>>>>> +
>>>>>> +       platform_set_drvdata(pdev, mv_phy);
>>>>>> +
>>>>>> +       the_phy = mv_phy;
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> Is there any specific reason for not using the usb phy library?
>>>>> Please use the APIs provided in drivers/usb/otg/otg.c.
>>>>> These APIs will be moved to phy.c soon.
>>>>>
>>>>> Thanks
>>>>> Kishon
>>>>
>>>>
>>>>
>>>> The phy in driver/usb/otg/otg.c is bound to OTG. The major target of
>>>> this APIs in OTG is help functions for OTG support.
>>>
>>>
>>>
>>> Not really. Much of what's in otg.c is related to PHY and we have an
>>> action
>>> item to rename otg.c to phy.c. Sascha hauer has already sent a patch for
>>> it.
>>>
>>>> I have used it and implemented it at mv_otg.c for OTG support. The
>>>> APIs only allow one phy driver register to it.
>>>
>>>
>>>
>>> PHY library has changed quite a bit since then. You might want to have a
>>> look at usb/otg/otg.c again in usb-next.
>>>
>> Thanks for your suggestion.
>>
>> I have taken look at the otg.c again.
>> The problem is the phy list only allow a single phy driver for each type.
>> It defines only two valid types
>>
>>          USB_PHY_TYPE_USB2,
>>          USB_PHY_TYPE_USB3,
>> when invoke usb_add_phy  to add a phy driver, if USB_PHY_TYPE_USB2 has
>> been added, it will return error
>> some piece of the code is listed below
>>
>> list_for_each_entry(phy, &phy_list, head) {
>>                  if (phy->type == type) {
>>                          ret = -EBUSY;
>>                          dev_err(x->dev, "transceiver type %s already
>> exists\n",
>>
>> usb_phy_type_string(type));
>>                          goto out;
>>                  }
>>          }
>>
>> The USB IP we used includes EHCI and UDC controller together, and it
>> can support OTG functions.
>> When either mode(EHCI/UDC) is used, the PHY blocks should be enabled
>> because it controller to turn
>> the internal signals of USB IP block to the D+/D-/VBUS signals we see.
>> So if we register this phy to be type USB_PHY_TYPE_USB2, then how about
>> OTG?
>> For OTG support we need register the PHY to complete the device->host
>> and host->device transaction, if we register it as
>> USB_PHY_TYPE_USB2, the registertation will fail.
>>
>> So there will be three ways to do the job
>> way1:
>> 1. invoke usb_add_phy in phy driver with type of USB_PHY_TYPE_USB2,
>> and initialize the callbacks
>> 2. in usb otg driver, invoke usb_get_phy and initialize the otg part
>> way1 seems a little tricky because when the phy initialize is
>> seperated into two parts.
>>
>> way2:
>> change the otg.c and make it can add mutiple phy for the type.
>> It takes time and will impact many drivers. I hope i can do it after i
>> have completed my patches.
>
>
> This is already done. We have added API's like usb_add_phy_dev() for the
> same purpose. Now you can use usb_add_phy_dev() to add multiple PHYs (of
> same type or different) and then get the PHY using usb_get_phy_dev(). Note
> that you should use usb_bind_phy() in platform initialization file for
> binding the controller to the PHY.
>
> These patches are merged in usb-next
> http://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-next
>
> Thanks
> Kishon

Thanks for your suggestion. I will take a look and redo the patches.

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2013-02-18  2:53 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-06  7:23 [V6 PATCH 00/16] mv-usb phy enhancement patches Chao Xie
2013-02-06  7:23 ` [V6 PATCH 01/16] usb: phy: mv_usb2: add PHY driver for marvell usb2 controller Chao Xie
2013-02-06  8:10   ` kishon
2013-02-06  8:18     ` Chao Xie
2013-02-06 10:35       ` kishon
2013-02-07  2:26         ` Chao Xie
2013-02-07  5:57           ` kishon
2013-02-18  2:53             ` Chao Xie
2013-02-06 14:42   ` Mark Rutland
2013-02-07  2:00     ` Chao Xie
2013-02-06  7:23 ` [V6 PATCH 02/16] usb: gadget: mv_udc: use PHY driver for udc Chao Xie
2013-02-06  7:23 ` [V6 PATCH 03/16] usb: ehci: ehci-mv: use PHY driver for ehci Chao Xie
2013-02-06  7:23 ` [V6 PATCH 04/16] usb: otg: mv_otg: use PHY driver for otg Chao Xie
2013-02-06  7:23 ` [V6 PATCH 05/16] arm: mmp2: change the defintion of usb devices Chao Xie
2013-02-06  7:23 ` [V6 PATCH 06/16] arm: pxa910: " Chao Xie
2013-02-06  7:23 ` [V6 PATCH 07/16] arm: brownstone: add usb support for the board Chao Xie
2013-02-06  7:23 ` [V6 PATCH 08/16] arm: ttc_dkb: add usb support Chao Xie
2013-02-06  7:23 ` [V6 PATCH 09/16] arm: mmp: remove the usb phy setting Chao Xie
2013-02-06  7:23 ` [V6 PATCH 10/16] arm: mmp: remove usb devices from pxa168 Chao Xie
2013-02-06  7:23 ` [V6 PATCH 11/16] usb: phy: mv_usb2_phy: add externel chip support Chao Xie
2013-02-06  7:23 ` [V6 PATCH 12/16] usb: gadget: mv_udc: add extern " Chao Xie
2013-02-06  7:23 ` [V6 PATCH 13/16] usb: ehci: ehci-mv: " Chao Xie
2013-02-06  7:23 ` [V6 PATCH 14/16] usb: otg: mv_otg: " Chao Xie
2013-02-06  7:23 ` [V6 PATCH 15/16] arm: mmp: add extern chip support for brownstone Chao Xie
2013-02-06  7:23 ` [V6 PATCH 16/16] arm: mmp: add extern chip support for ttc_dkb Chao Xie

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.