From patchwork Tue Feb 5 00:37:12 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dongjin Kim X-Patchwork-Id: 2095721 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id B79EB3FD56 for ; Tue, 5 Feb 2013 00:39:50 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1U2WXh-0007P6-SQ; Tue, 05 Feb 2013 00:37:45 +0000 Received: from mail-pa0-f42.google.com ([209.85.220.42]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1U2WXe-0007OD-4P for linux-arm-kernel@lists.infradead.org; Tue, 05 Feb 2013 00:37:43 +0000 Received: by mail-pa0-f42.google.com with SMTP id kq12so858168pab.15 for ; Mon, 04 Feb 2013 16:37:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer; bh=tB4k25QV0m93DuQEyVx+zfwtknFlnkVD8hfspea7pUQ=; b=kyNLW76CGgT8jut1TjT8fXxruEhnLTbR0Zqt6B9v/ti9rCvm5bRpYi3jhUwPnDxhre MBBM78xMjG1KNFnRJYgC+O+JwqTtBogSk1sLhMS0xKhtVslOH4zyzcHj+8vtmEe/VQRR DE6s8musfi50uofbfmTxt4giZlTEyGCRcA7UJWECWI6TmzHLWnos3Jlg9tAbpWJ03Yla fRr8vyaP49ZPvVsK+TUyt+DDg26WE3ZBdpYpSutuC3YD0yz2ta7Im395CFPTI2jpBF60 xIX0lkCC0Zc/nezmOPN1DBDsAMp3/dJB+btuEgSOMMu60qFzYRHbS0hmA4pFsxJMbtpS m+zg== X-Received: by 10.66.52.116 with SMTP id s20mr9714706pao.70.1360024659348; Mon, 04 Feb 2013 16:37:39 -0800 (PST) Received: from localhost.localdomain ([222.120.78.75]) by mx.google.com with ESMTPS id l5sm24861951pax.10.2013.02.04.16.37.35 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 04 Feb 2013 16:37:38 -0800 (PST) From: Dongjin Kim To: Subject: [PATCH] usb: phy: Add USB host phy support on Exyno4412 Date: Tue, 5 Feb 2013 09:37:12 +0900 Message-Id: <1360024635-15181-1-git-send-email-tobetter@gmail.com> X-Mailer: git-send-email 1.7.10.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130204_193742_348493_89EE6F1B X-CRM114-Status: GOOD ( 20.33 ) X-Spam-Score: 0.3 (/) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (0.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- 3.0 KHOP_BIG_TO_CC Sent to 10+ recipients instaed of Bcc or a list 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (tobetter[at]gmail.com) -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.220.42 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Kukjin Kim , Russell King , Praveen Paneri , Greg Kroah-Hartman , Tomasz Figa , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Felipe Balbi , Kyungmin Park , Thomas Abraham , Dongjin Kim , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This patch adds host phy support for Samsung's Exynos4412 SoC to samsung-usbphy driver and its device node. Cc: Praveen Paneri Signed-off-by: Dongjin Kim --- arch/arm/boot/dts/exynos4412.dtsi | 13 ++++ drivers/usb/phy/samsung-usbphy.c | 156 ++++++++++++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index 387aa27..c01d841 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi @@ -33,4 +33,17 @@ #address-cells = <1>; #size-cells = <0>; }; + + usbphy@125B0000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "samsung,exynos4412-usbphy"; + reg = <0x125B0000 0x100>; + status = "disabled"; + ranges; + + usbphy-sys { + reg = <0x10020704 0xc>; + }; + }; }; diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c index 6ea5537..c800fa4 100644 --- a/drivers/usb/phy/samsung-usbphy.c +++ b/drivers/usb/phy/samsung-usbphy.c @@ -47,7 +47,7 @@ #define PHYCLK_MODE_USB11 (0x1 << 6) #define PHYCLK_EXT_OSC (0x1 << 5) -#define PHYCLK_COMMON_ON_N (0x1 << 4) +#define PHYCLK_COMMON_ON_N_PHY0 (0x1 << 4) #define PHYCLK_ID_PULL (0x1 << 2) #define PHYCLK_CLKSEL_MASK (0x3 << 0) #define PHYCLK_CLKSEL_48M (0x0 << 0) @@ -60,6 +60,22 @@ #define RSTCON_HLINK_SWRST (0x1 << 1) #define RSTCON_SWRST (0x1 << 0) +/* For Exynos4412 */ +#define PHYCLK_COMMON_ON_N_PHY1 (0x1 << 7) + +#define PHYPWR_NORMAL_MASK_HSIC1 (0x7 << 12) +#define PHYPWR_NORMAL_MASK_HSIC0 (0x7 << 9) +#define PHYPWR_NORMAL_MASK_PHY1 (0x7 << 6) + +#define PHYPWR_ANALOG_POWERDOWN_PHY1 (0x1 << 7) + +#define RSTCON_HLINK_SWRST_MASK (0xf << 7) +#define RSTCON_PHY1_SWRST_MASK (0xf << 3) +#define RSTCON_PHY0_SWRST_MASK (0x7 << 0) + +#define EXYNOS4_PHY_HSIC_CTRL0 (0x04) +#define EXYNOS4_PHY_HSIC_CTRL1 (0x08) + /* EXYNOS5 */ #define EXYNOS5_PHY_HOST_CTRL0 (0x00) @@ -174,6 +190,7 @@ enum samsung_cpu_type { TYPE_S3C64XX, TYPE_EXYNOS4210, + TYPE_EXYNOS4412, TYPE_EXYNOS5250, }; @@ -322,6 +339,17 @@ static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on) en_mask = sphy->drv_data->hostphy_en_mask; } break; + case TYPE_EXYNOS4412: + if (sphy->phy_type == USB_PHY_TYPE_DEVICE) { + reg = sphy->pmuregs + + sphy->drv_data->devphy_reg_offset; + en_mask = sphy->drv_data->devphy_en_mask; + } else if (sphy->phy_type == USB_PHY_TYPE_HOST) { + reg = sphy->pmuregs + + sphy->drv_data->hostphy_reg_offset; + en_mask = sphy->drv_data->hostphy_en_mask; + } + break; default: dev_err(sphy->dev, "Invalid SoC type\n"); return; @@ -422,6 +450,29 @@ static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy) refclk_freq = FSEL_CLKSEL_24M; break; } + } else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412) { + switch (clk_get_rate(ref_clk)) { + case 9600 * KHZ: + refclk_freq = FSEL_CLKSEL_9600K; + break; + case 10 * MHZ: + refclk_freq = FSEL_CLKSEL_10M; + break; + case 12 * MHZ: + refclk_freq = FSEL_CLKSEL_12M; + break; + case 19200 * KHZ: + refclk_freq = FSEL_CLKSEL_19200K; + break; + case 20 * MHZ: + refclk_freq = FSEL_CLKSEL_20M; + break; + case 24 * MHZ: + default: + /* default reference clock */ + refclk_freq = FSEL_CLKSEL_24M; + break; + } } else { switch (clk_get_rate(ref_clk)) { case 12 * MHZ: @@ -561,6 +612,69 @@ static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy) writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL); } +static bool exynos4_phyhost_is_on(void *regs) +{ + u32 reg; + + reg = readl(regs + SAMSUNG_PHYPWR); + + return !(reg & PHYPWR_ANALOG_POWERDOWN_PHY1); +} + +static void samsung_exynos4412_usbphy_enable(struct samsung_usbphy *sphy) +{ + void __iomem *regs = sphy->regs; + u32 phypwr; + u32 phyclk; + u32 rstcon; + + /* + * phy_usage helps in keeping usage count for phy + * so that the first consumer enabling the phy is also + * the last consumer to disable it. + */ + + atomic_inc(&sphy->phy_usage); + + if (exynos4_phyhost_is_on(regs)) { + dev_info(sphy->dev, "Already power on PHY\n"); + return; + } + + writel(EXYNOS_USBPHY_ENABLE, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL0); + writel(EXYNOS_USBPHY_ENABLE, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL1); + + /* Common block configuration during suspend */ + phyclk = sphy->ref_clk_freq + & ~(PHYCLK_COMMON_ON_N_PHY0 | PHYCLK_COMMON_ON_N_PHY1); + writel(phyclk, regs + SAMSUNG_PHYCLK); + + /* set to normal of Device */ + phypwr = readl(regs + SAMSUNG_PHYPWR) & ~PHYPWR_NORMAL_MASK_PHY0; + writel(phypwr, regs + SAMSUNG_PHYPWR); + + /* set to normal of Host */ + phypwr &= ~(PHYPWR_NORMAL_MASK_HSIC0 | PHYPWR_NORMAL_MASK_HSIC1 + | PHYPWR_NORMAL_MASK_PHY1); + writel(phypwr, regs + SAMSUNG_PHYPWR); + + /* reset both PHY and Link of Device */ + rstcon = readl(regs + SAMSUNG_RSTCON) | RSTCON_PHY0_SWRST_MASK; + writel(rstcon, regs + SAMSUNG_RSTCON); + udelay(10); + rstcon &= ~RSTCON_PHY0_SWRST_MASK; + writel(rstcon, regs + SAMSUNG_RSTCON); + + /* reset both PHY and Link of Host */ + rstcon = readl(regs + SAMSUNG_RSTCON) + | (RSTCON_HLINK_SWRST_MASK | RSTCON_PHY1_SWRST_MASK); + writel(rstcon, regs + SAMSUNG_RSTCON); + udelay(10); + rstcon &= ~(RSTCON_HLINK_SWRST_MASK | RSTCON_PHY1_SWRST_MASK); + writel(rstcon, regs + SAMSUNG_RSTCON); + udelay(80); +} + static void samsung_usbphy_enable(struct samsung_usbphy *sphy) { void __iomem *regs = sphy->regs; @@ -575,7 +689,7 @@ static void samsung_usbphy_enable(struct samsung_usbphy *sphy) switch (sphy->drv_data->cpu_type) { case TYPE_S3C64XX: - phyclk &= ~PHYCLK_COMMON_ON_N; + phyclk &= ~PHYCLK_COMMON_ON_N_PHY0; phypwr &= ~PHYPWR_NORMAL_MASK; rstcon |= RSTCON_SWRST; break; @@ -631,6 +745,28 @@ static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy) writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); } +static void samsung_exynos4412_usbphy_disable(struct samsung_usbphy *sphy) +{ + void __iomem *regs = sphy->regs; + u32 phypwr; + + if (atomic_dec_return(&sphy->phy_usage) > 0) { + dev_info(sphy->dev, "still being used\n"); + return; + } + + /* unset to normal of Host and Device */ + phypwr = readl(regs + SAMSUNG_PHYPWR); + phypwr |= (PHYPWR_NORMAL_MASK_HSIC0 + | PHYPWR_NORMAL_MASK_HSIC1 + | PHYPWR_NORMAL_MASK_PHY1 + | PHYPWR_NORMAL_MASK_PHY0); + writel(phypwr, regs + SAMSUNG_PHYPWR); + + writel(0, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL0); + writel(0, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL1); +} + static void samsung_usbphy_disable(struct samsung_usbphy *sphy) { void __iomem *regs = sphy->regs; @@ -696,6 +832,8 @@ static int samsung_usbphy_init(struct usb_phy *phy) /* Initialize usb phy registers */ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) samsung_exynos5_usbphy_enable(sphy); + else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412) + samsung_exynos4412_usbphy_enable(sphy); else samsung_usbphy_enable(sphy); @@ -739,6 +877,8 @@ static void samsung_usbphy_shutdown(struct usb_phy *phy) /* De-initialize usb phy registers */ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) samsung_exynos5_usbphy_disable(sphy); + else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412) + samsung_exynos4412_usbphy_disable(sphy); else samsung_usbphy_disable(sphy); @@ -872,6 +1012,12 @@ static const struct samsung_usbphy_drvdata usbphy_exynos4 = { .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, }; +static const struct samsung_usbphy_drvdata usbphy_exynos4412 = { + .cpu_type = TYPE_EXYNOS4412, + .devphy_en_mask = EXYNOS_USBPHY_ENABLE, + .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, +}; + static struct samsung_usbphy_drvdata usbphy_exynos5 = { .cpu_type = TYPE_EXYNOS5250, .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, @@ -887,6 +1033,9 @@ static const struct of_device_id samsung_usbphy_dt_match[] = { .compatible = "samsung,exynos4210-usbphy", .data = &usbphy_exynos4, }, { + .compatible = "samsung,exynos4412-usbphy", + .data = &usbphy_exynos4412, + }, { .compatible = "samsung,exynos5250-usbphy", .data = &usbphy_exynos5 }, @@ -903,6 +1052,9 @@ static struct platform_device_id samsung_usbphy_driver_ids[] = { .name = "exynos4210-usbphy", .driver_data = (unsigned long)&usbphy_exynos4, }, { + .name = "exynos4412-usbphy", + .driver_data = (unsigned long)&usbphy_exynos4412, + }, { .name = "exynos5250-usbphy", .driver_data = (unsigned long)&usbphy_exynos5, },