From patchwork Sun Sep 4 21:31:49 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Blumenstingl X-Patchwork-Id: 9312865 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 42BB9600CA for ; Sun, 4 Sep 2016 21:36:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3717728753 for ; Sun, 4 Sep 2016 21:36:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2B2BA28756; Sun, 4 Sep 2016 21:36:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4E97828753 for ; Sun, 4 Sep 2016 21:36:02 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bgf3b-0002YI-Dv; Sun, 04 Sep 2016 21:34:27 +0000 Received: from mail-wm0-x243.google.com ([2a00:1450:400c:c09::243]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bgf1w-0001h8-2Y; Sun, 04 Sep 2016 21:32:47 +0000 Received: by mail-wm0-x243.google.com with SMTP id c133so10634438wmd.2; Sun, 04 Sep 2016 14:32:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ZtumySGYlJseVpAu1N4UEFvqs+LS/C2TEplTyZJ28lQ=; b=KO+wzfv9o1jJzRF5CZ4NQvDsB0gLVOZkIfRcJ/o8rIwyuzCu0ciodPSnRyLYYk8p0V 2I7Djf6/ztsTLU5m2/yEix6Pwt/r8jt05xHBjbLQk6KcpsX/aaHXTxpuayRL08+ropK3 sROcVUknLg5yWxSxYsStYVbsp1DMyvrHCdaJykQecICs3+mwux9x32LySgmJrCvVJSFd Z7jbY8+RdHpUrVgV5uYif106rwZNHsG2FkdidN4Nw2cptOhKFuPEIm0F3+BBoHK/WjJF sfcFkTMkWXhPqV0rOB9GYBf7WcrnHr2caVY4IA20o5HFGCky+QMhTepB5tRcJDv4c92r JzJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ZtumySGYlJseVpAu1N4UEFvqs+LS/C2TEplTyZJ28lQ=; b=iB2TSz0xauOHNNiQkCnOMHV71ee5LZxVRpViVK81Xj0wfBV8JBVcHWqGHJ1/63dWQ/ cAX/tAiqEWaFDQrCk+2ae0tb0yZPmT6TPx489M4sbnmMbfuL1M5VmaborCAglY6FjY7b rb4BAAYz6MWiVfv9DUg4dovBLK57hZedy5BTug9vh0yD2/1hN3XU+A9uMQEv2BK5fL2m aCgzassp9P2wka8j88saGzqzztD1SUONDWMhJ6FMCNCESbInWjIpbAdqI449LD2IHE1F eqzpWCngktWNJvIBROX8hJecIdQ6Bx+1BJl6HCF2SSm/cLUErCQreihjK0otUPNq+dXn 1o8Q== X-Gm-Message-State: AE9vXwOITI7vEtbHJdAC3DahPC0iPPTgjg3NpobGiYoVf4581yREw6+Ct6dwdF4IRZ0KQg== X-Received: by 10.28.26.200 with SMTP id a191mr12029743wma.27.1473024746256; Sun, 04 Sep 2016 14:32:26 -0700 (PDT) Received: from blackbox.darklights.net (p200300DCD3CA8104A82AA8E503619161.dip0.t-ipconnect.de. [2003:dc:d3ca:8104:a82a:a8e5:361:9161]) by smtp.googlemail.com with ESMTPSA id e12sm16576059wmg.17.2016.09.04.14.32.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 04 Sep 2016 14:32:25 -0700 (PDT) From: Martin Blumenstingl To: linux-clk@vger.kernel.org, linux-usb@vger.kernel.org, linux-amlogic@lists.infradead.org, jbrunet@baylibre.com, johnyoun@synopsys.com, kishon@ti.com, khilman@baylibre.com, carlo@caione.org Subject: [PATCH 4/7] phy: meson: add USB2 PHY support for Meson8b and GXBB Date: Sun, 4 Sep 2016 23:31:49 +0200 Message-Id: <20160904213152.25837-5-martin.blumenstingl@googlemail.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20160904213152.25837-1-martin.blumenstingl@googlemail.com> References: <20160904213152.25837-1-martin.blumenstingl@googlemail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160904_143244_542332_E919E397 X-CRM114-Status: GOOD ( 21.52 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, Martin Blumenstingl , sboyd@codeaurora.org, mturquette@baylibre.com, will.deacon@arm.com, robh+dt@kernel.org, catalin.marinas@arm.com, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This is a new driver for the USB PHY found in Meson8b and GXBB SoCs. Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Tested-by: Kevin Hilman --- drivers/phy/Kconfig | 11 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-meson-usb2.c | 299 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 drivers/phy/phy-meson-usb2.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 19bff3a..6ad87ec 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -453,4 +453,15 @@ config PHY_NS2_PCIE help Enable this to support the Broadcom Northstar2 PCIe PHY. If unsure, say N. + +config PHY_MESON_USB2 + tristate "Meson USB2 PHY driver" + default ARCH_MESON + depends on OF && (ARCH_MESON || COMPILE_TEST) + select GENERIC_PHY + help + Enable this to support the Meson USB2 PHYs found in Meson8b + and GXBB SoCs. + If unsure, say N. + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 90ae198..dd507ac 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -56,3 +56,4 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o +obj-$(CONFIG_PHY_MESON_USB2) += phy-meson-usb2.o diff --git a/drivers/phy/phy-meson-usb2.c b/drivers/phy/phy-meson-usb2.c new file mode 100644 index 0000000..8cda138 --- /dev/null +++ b/drivers/phy/phy-meson-usb2.c @@ -0,0 +1,299 @@ +/* + * Meson USB2 PHY driver + * + * Copyright (C) 2016 Martin Blumenstingl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_CONFIG 0x00 + #define REG_CONFIG_CLK_EN BIT(0) + #define REG_CONFIG_CLK_SEL_MASK GENMASK(3, 1) + #define REG_CONFIG_CLK_DIV_MASK GENMASK(10, 4) + #define REG_CONFIG_CLK_32k_ALTSEL BIT(15) + #define REG_CONFIG_TEST_TRIG BIT(31) + +#define REG_CTRL 0x04 + #define REG_CTRL_SOFT_PRST BIT(0) + #define REG_CTRL_SOFT_HRESET BIT(1) + #define REG_CTRL_SS_SCALEDOWN_MODE_MASK GENMASK(3, 2) + #define REG_CTRL_CLK_DET_RST BIT(4) + #define REG_CTRL_INTR_SEL BIT(5) + #define REG_CTRL_CLK_DETECTED BIT(8) + #define REG_CTRL_SOF_SENT_RCVD_TGL BIT(9) + #define REG_CTRL_SOF_TOGGLE_OUT BIT(10) + #define REG_CTRL_POWER_ON_RESET BIT(15) + #define REG_CTRL_SLEEPM BIT(16) + #define REG_CTRL_TX_BITSTUFF_ENN_H BIT(17) + #define REG_CTRL_TX_BITSTUFF_ENN BIT(18) + #define REG_CTRL_COMMON_ON BIT(19) + #define REG_CTRL_REF_CLK_SEL_MASK GENMASK(21, 20) + #define REG_CTRL_REF_CLK_SEL_SHIFT 20 + #define REG_CTRL_FSEL_MASK GENMASK(24, 22) + #define REG_CTRL_FSEL_SHIFT 22 + #define REG_CTRL_PORT_RESET BIT(25) + #define REG_CTRL_THREAD_ID_MASK GENMASK(31, 26) + +#define REG_ENDP_INTR 0x08 + +/* bits [31:26], [24:21] and [15:3] seem to be read-only */ +#define REG_ADP_BC 0x0c + #define REG_ADP_BC_VBUS_VLD_EXT_SEL BIT(0) + #define REG_ADP_BC_VBUS_VLD_EXT BIT(1) + #define REG_ADP_BC_OTG_DISABLE BIT(2) + #define REG_ADP_BC_ID_PULLUP BIT(3) + #define REG_ADP_BC_DRV_VBUS BIT(4) + #define REG_ADP_BC_ADP_PRB_EN BIT(5) + #define REG_ADP_BC_ADP_DISCHARGE BIT(6) + #define REG_ADP_BC_ADP_CHARGE BIT(7) + #define REG_ADP_BC_SESS_END BIT(8) + #define REG_ADP_BC_DEVICE_SESS_VLD BIT(9) + #define REG_ADP_BC_B_VALID BIT(10) + #define REG_ADP_BC_A_VALID BIT(11) + #define REG_ADP_BC_ID_DIG BIT(12) + #define REG_ADP_BC_VBUS_VALID BIT(13) + #define REG_ADP_BC_ADP_PROBE BIT(14) + #define REG_ADP_BC_ADP_SENSE BIT(15) + #define REG_ADP_BC_ACA_ENABLE BIT(16) + #define REG_ADP_BC_DCD_ENABLE BIT(17) + #define REG_ADP_BC_VDAT_DET_EN_B BIT(18) + #define REG_ADP_BC_VDAT_SRC_EN_B BIT(19) + #define REG_ADP_BC_CHARGE_SEL BIT(20) + #define REG_ADP_BC_CHARGE_DETECT BIT(21) + #define REG_ADP_BC_ACA_PIN_RANGE_C BIT(22) + #define REG_ADP_BC_ACA_PIN_RANGE_B BIT(23) + #define REG_ADP_BC_ACA_PIN_RANGE_A BIT(24) + #define REG_ADP_BC_ACA_PIN_GND BIT(25) + #define REG_ADP_BC_ACA_PIN_FLOAT BIT(26) + +#define REG_DBG_UART 0x14 + +#define REG_TEST 0x18 + #define REG_TEST_DATA_IN_MASK GENMASK(3, 0) + #define REG_TEST_EN_MASK GENMASK(7, 4) + #define REG_TEST_ADDR_MASK GENMASK(11, 8) + #define REG_TEST_DATA_OUT_SEL BIT(12) + #define REG_TEST_CLK BIT(13) + #define REG_TEST_VA_TEST_EN_B_MASK GENMASK(15, 14) + #define REG_TEST_DATA_OUT_MASK GENMASK(19, 16) + #define REG_TEST_DISABLE_ID_PULLUP BIT(20) + +#define REG_TUNE 0x1c + #define REG_TUNE_TX_RES_TUNE_MASK GENMASK(1, 0) + #define REG_TUNE_TX_HSXV_TUNE_MASK GENMASK(3, 2) + #define REG_TUNE_TX_VREF_TUNE_MASK GENMASK(7, 4) + #define REG_TUNE_TX_RISE_TUNE_MASK GENMASK(9, 8) + #define REG_TUNE_TX_PREEMP_PULSE_TUNE BIT(10) + #define REG_TUNE_TX_PREEMP_AMP_TUNE_MASK GENMASK(12, 11) + #define REG_TUNE_TX_FSLS_TUNE_MASK GENMASK(16, 13) + #define REG_TUNE_SQRX_TUNE_MASK GENMASK(19, 17) + #define REG_TUNE_OTG_TUNE GENMASK(22, 20) + #define REG_TUNE_COMP_DIS_TUNE GENMASK(25, 23) + #define REG_TUNE_HOST_DM_PULLDOWN BIT(26) + #define REG_TUNE_HOST_DP_PULLDOWN BIT(27) + +#define RESET_COMPLETE_TIME 500 +#define ACA_ENABLE_COMPLETE_TIME 50 + +/* + * The PHYs are sharing a common reset line -> we are only allowed to reset + * once for all PHYs. + */ +static int usb_reset_refcnt; + +struct phy_meson_usb2_priv { + void __iomem *regs; + enum usb_dr_mode dr_mode; + struct reset_control *reset_usb_otg; + struct clk *clk_usb_general; + struct clk *clk_usb; +}; + +static u32 phy_meson_usb2_read(struct phy_meson_usb2_priv *phy_priv, u32 reg) +{ + return readl(phy_priv->regs + reg); +} + +static void phy_meson_usb2_mask_bits(struct phy_meson_usb2_priv *phy_priv, + u32 reg, u32 mask, u32 value) +{ + u32 data; + + data = phy_meson_usb2_read(phy_priv, reg); + data &= ~mask; + data |= (value & mask); + + writel(data, phy_priv->regs + reg); +} + +static int phy_meson_usb2_power_on(struct phy *phy) +{ + struct phy_meson_usb2_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(priv->clk_usb_general); + if (ret) { + dev_err(&phy->dev, "Failed to enable USB general clock\n"); + return ret; + } + + ret = clk_prepare_enable(priv->clk_usb); + if (ret) { + dev_err(&phy->dev, "Failed to enable USB DDR clock\n"); + return ret; + } + + phy_meson_usb2_mask_bits(priv, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL, + REG_CONFIG_CLK_32k_ALTSEL); + + phy_meson_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK, + 0x2 << REG_CTRL_REF_CLK_SEL_SHIFT); + + phy_meson_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_FSEL_MASK, + 0x5 << REG_CTRL_FSEL_SHIFT); + + /* reset the PHY */ + phy_meson_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_POWER_ON_RESET, + REG_CTRL_POWER_ON_RESET); + udelay(RESET_COMPLETE_TIME); + phy_meson_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_POWER_ON_RESET, 0); + udelay(RESET_COMPLETE_TIME); + + phy_meson_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT, + REG_CTRL_SOF_TOGGLE_OUT); + + if (priv->dr_mode == USB_DR_MODE_HOST) { + phy_meson_usb2_mask_bits(priv, REG_ADP_BC, + REG_ADP_BC_ACA_ENABLE, + REG_ADP_BC_ACA_ENABLE); + + udelay(ACA_ENABLE_COMPLETE_TIME); + + if (phy_meson_usb2_read(priv, REG_ADP_BC) & + REG_ADP_BC_ACA_PIN_FLOAT) { + dev_warn(&phy->dev, "USB ID detect failed!\n"); + return -EINVAL; + } + } + + return 0; +} + +static int phy_meson_usb2_power_off(struct phy *phy) +{ + struct phy_meson_usb2_priv *priv = phy_get_drvdata(phy); + + clk_disable_unprepare(priv->clk_usb); + clk_disable_unprepare(priv->clk_usb_general); + + return 0; +} + +static const struct phy_ops phy_meson_usb2_ops = { + .power_on = phy_meson_usb2_power_on, + .power_off = phy_meson_usb2_power_off, + .owner = THIS_MODULE, +}; + +static int phy_meson_usb2_probe(struct platform_device *pdev) +{ + struct phy_meson_usb2_priv *priv; + struct resource *res; + struct phy *phy; + struct phy_provider *phy_provider; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + priv->clk_usb_general = devm_clk_get(&pdev->dev, "usb_general"); + if (IS_ERR(priv->clk_usb_general)) + return PTR_ERR(priv->clk_usb_general); + + priv->clk_usb = devm_clk_get(&pdev->dev, "usb"); + if (IS_ERR(priv->clk_usb)) + return PTR_ERR(priv->clk_usb); + + priv->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1); + if (priv->dr_mode == USB_DR_MODE_UNKNOWN) { + dev_err(&pdev->dev, + "missing dual role configuration of the controller\n"); + return -EINVAL; + } + + phy = devm_phy_create(&pdev->dev, NULL, &phy_meson_usb2_ops); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); + return PTR_ERR(phy); + } + + if (usb_reset_refcnt++ == 0) { + ret = device_reset(&pdev->dev); + if (ret) { + dev_err(&phy->dev, "Failed to reset USB PHY\n"); + return ret; + } + } + + phy_set_drvdata(phy, priv); + + phy_provider = + devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); + + if (IS_ERR(phy_provider)) { + usb_reset_refcnt--; + + return PTR_ERR(phy_provider); + } + + return 0; +} + +static int phy_meson_usb2_remove(struct platform_device *pdev) +{ + usb_reset_refcnt--; + + return 0; +} + +static const struct of_device_id phy_meson_usb2_of_match[] = { + { .compatible = "amlogic,meson8b-usb2-phy", }, + { .compatible = "amlogic,meson-gxbb-usb2-phy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, phy_meson_usb2_of_match); + +static struct platform_driver phy_meson_usb2_driver = { + .probe = phy_meson_usb2_probe, + .remove = phy_meson_usb2_remove, + .driver = { + .name = "phy-meson-usb2", + .of_match_table = phy_meson_usb2_of_match, + }, +}; +module_platform_driver(phy_meson_usb2_driver); + +MODULE_AUTHOR("Martin Blumenstingl "); +MODULE_DESCRIPTION("Meson USB2 PHY driver"); +MODULE_LICENSE("GPL");