Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp2072040pxb; Sat, 21 Nov 2020 07:54:42 -0800 (PST) X-Google-Smtp-Source: ABdhPJywbmkbpFu5Zl1M3tBb5t2/+TVHvwVMrMWR8FRlXgveFdKhOZSfg6OZun0OLNUjxcKTpgED X-Received: by 2002:aa7:c44d:: with SMTP id n13mr41194921edr.138.1605974082552; Sat, 21 Nov 2020 07:54:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605974082; cv=none; d=google.com; s=arc-20160816; b=HvhZ7ZCW9OA38WkrBdsf52Hr3fdiknmNIkASZ54/i9o52EAkHy1EDNHZJOD4dg2g02 3gqgRgaFmqXvpoN2iUr/38G2f0SNErChsJ/TlhkLqhN8001ZyjFX4hWMuQx2wW/KJeR9 7vtsOmh8eV7dasLzeU/Tw42nWsDu5Rk75FcsZOiUs8XynY5Ru8nGLdT2eQMxLTOUB7Yv elDEe/QXXSOt3Enhn0Fjii8JpWleNKEy6eVVxtS8xvDoIRXg6S5YIDHhow8v3MQ8JA9O J1jipgCXTZ06dHouG86pNfgQMpFc5BYyR4C4+w+m/d3X4aIsucr93l4vzgeITSkZnGRV 7tYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=6PkM+WWapRNdDfn6qtgva5KZPO7D28g+mKdaOZGBNaQ=; b=IFbsNlCJuCraWTZpL+LI4MvyUSZNygqo6q8kaM8gYaYabsNZMJXHskBsQ5RynkUUXm 5fQ90Q18PuvMl6VJPN9SxxQF4mpJt5oEwb1jlLEVlJR8LRWJrKZU0EzIrp2NJK9GDT6U NylFs2ksIckAHFgWtfGSxqnQ1TVFA0VlzzA7unxsesHvdh92SnzKoU7eNYJObfjrLRXi fRvap/yxsGRfq4pXcxA2ULkk2b/IS+/mlQkMMhQ3Z371XyEr5MZEiE8w/Ts9c+QsBvWy E592SQcmBe6nTDQFQWltSzOTb2iEMz9M/jpPy4SFTP0YD5sU4CX8lc9sQvTPjFz4RlsQ zY9w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=IlEUgmVd; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id e4si3713005edr.585.2020.11.21.07.54.18; Sat, 21 Nov 2020 07:54:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=IlEUgmVd; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728044AbgKUPup (ORCPT + 99 others); Sat, 21 Nov 2020 10:50:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40666 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727882AbgKUPuo (ORCPT ); Sat, 21 Nov 2020 10:50:44 -0500 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C68BEC061A4A; Sat, 21 Nov 2020 07:50:43 -0800 (PST) Received: by mail-wr1-x444.google.com with SMTP id t4so1046130wrr.12; Sat, 21 Nov 2020 07:50:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6PkM+WWapRNdDfn6qtgva5KZPO7D28g+mKdaOZGBNaQ=; b=IlEUgmVdF5tb2HQuTKVNiZ73NFpp7Q5+rVQmzEWejWRhHfoP2wZy8tN9ZlAka3z28+ 4aXiFjsCplvCq+G7/a6J7LzwmWIwXNrguSODYDnvA6oAnbDBQp8+ccq/5UqaMVv/+P35 pejYUWBSRs4RL0XFA4OJGPYEuI6OetmMmF9UDThIZVnSHT+Fc6T150sPoS6Hve0UegtV CkNzkOARGHmhqkbwRWXjP3f4ZLqjtde+Jo2MDSOx8VaMN3JZfTueNr9/o3vDuetvnpFG 0ejST8XbeZld48S8+Ld0kJHMc1V+V6//R1WMyO5vDo6cf871aa+vvw2rd8fe5gcND126 A9dg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6PkM+WWapRNdDfn6qtgva5KZPO7D28g+mKdaOZGBNaQ=; b=HSYjLKtTquUlm9FT1RzmaT4FEEXwFqTy5TyTyecFUEJAZCXxoDOQ7gUJxPdCFsht+L YO5KfVAXe4h4iXNyqLhPQVCqx0VUuz8wRVrrMe0mI8rnfeq7A8BrEt9Vf7oNDMrLgLXy TR2hV2tAfDvGGVsuL0poz/PUannJ3csylzmriLbsUvC845+WfWcrsDfiZcefot6KdiU2 C0f6/5nZjZPvRD7vv348BqIIHNUWEe/5PFcwjg87ikQnBLYRZPh6E/ta1MYThmNfb1GE yQxNJ/lphnDw7Mn53MKbhCvGZqfPZiMHGF5lAnANb3Nd33if2AZV/RGAa8oxVFpwyRw9 H1Eg== X-Gm-Message-State: AOAM530/m7F+Fo+3MnEyHFj8gwzbB0vgPV8jPmlQT0o1th5prwJxvtGb JBE3Bn63ubZhpfn/Hfe+VGE= X-Received: by 2002:adf:e5cb:: with SMTP id a11mr21761758wrn.15.1605973842504; Sat, 21 Nov 2020 07:50:42 -0800 (PST) Received: from localhost.localdomain (161.red-83-46-194.dynamicip.rima-tde.net. [83.46.194.161]) by smtp.gmail.com with ESMTPSA id n128sm7959598wmb.46.2020.11.21.07.50.41 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 21 Nov 2020 07:50:42 -0800 (PST) From: Sergio Paracuellos To: vkoul@kernel.org Cc: robh+dt@kernel.org, kishon@ti.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, devel@driverdev.osuosl.org, neil@brown.name Subject: [PATCH v6 2/4] phy: ralink: Add PHY driver for MT7621 PCIe PHY Date: Sat, 21 Nov 2020 16:50:35 +0100 Message-Id: <20201121155037.21354-3-sergio.paracuellos@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201121155037.21354-1-sergio.paracuellos@gmail.com> References: <20201121155037.21354-1-sergio.paracuellos@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds a driver for the PCIe PHY of MT7621 SoC. Signed-off-by: Sergio Paracuellos --- drivers/phy/ralink/Kconfig | 8 + drivers/phy/ralink/Makefile | 1 + drivers/phy/ralink/phy-mt7621-pci.c | 352 ++++++++++++++++++++++++++++ 3 files changed, 361 insertions(+) create mode 100644 drivers/phy/ralink/phy-mt7621-pci.c diff --git a/drivers/phy/ralink/Kconfig b/drivers/phy/ralink/Kconfig index da982c9cffb3..2fabb14d2998 100644 --- a/drivers/phy/ralink/Kconfig +++ b/drivers/phy/ralink/Kconfig @@ -2,6 +2,14 @@ # # PHY drivers for Ralink platforms. # +config PHY_MT7621_PCI + tristate "MediaTek MT7621 PCI PHY Driver" + depends on (RALINK || COMPILE_TEST) && OF + select GENERIC_PHY + select REGMAP_MMIO + help + Say 'Y' here to add support for MediaTek MT7621 PCI PHY driver, + config PHY_RALINK_USB tristate "Ralink USB PHY driver" depends on RALINK || COMPILE_TEST diff --git a/drivers/phy/ralink/Makefile b/drivers/phy/ralink/Makefile index d8d3ffcf0a15..cda2a4a7ca5e 100644 --- a/drivers/phy/ralink/Makefile +++ b/drivers/phy/ralink/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_PHY_MT7621_PCI) += phy-mt7621-pci.o obj-$(CONFIG_PHY_RALINK_USB) += phy-ralink-usb.o diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c new file mode 100644 index 000000000000..db79088d5362 --- /dev/null +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mediatek MT7621 PCI PHY Driver + * Author: Sergio Paracuellos + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RG_PE1_PIPE_REG 0x02c +#define RG_PE1_PIPE_RST BIT(12) +#define RG_PE1_PIPE_CMD_FRC BIT(4) + +#define RG_P0_TO_P1_WIDTH 0x100 +#define RG_PE1_H_LCDDS_REG 0x49c +#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) + +#define RG_PE1_FRC_H_XTAL_REG 0x400 +#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) +#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) + +#define RG_PE1_FRC_PHY_REG 0x000 +#define RG_PE1_FRC_PHY_EN BIT(4) +#define RG_PE1_PHY_EN BIT(5) + +#define RG_PE1_H_PLL_REG 0x490 +#define RG_PE1_H_PLL_BC GENMASK(23, 22) +#define RG_PE1_H_PLL_BP GENMASK(21, 18) +#define RG_PE1_H_PLL_IR GENMASK(15, 12) +#define RG_PE1_H_PLL_IC GENMASK(11, 8) +#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) +#define RG_PE1_PLL_DIVEN GENMASK(3, 1) + +#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc +#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) + +#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 +#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) + +#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 +#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) +#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) + +#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 +#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) + +#define RG_PE1_H_PLL_BR_REG 0x4ac +#define RG_PE1_H_PLL_BR GENMASK(18, 16) + +#define RG_PE1_MSTCKDIV_REG 0x414 +#define RG_PE1_MSTCKDIV GENMASK(7, 6) + +#define RG_PE1_FRC_MSTCKDIV BIT(5) + +#define XTAL_MASK GENMASK(7, 6) + +#define MAX_PHYS 2 + +/** + * struct mt7621_pci_phy - Mt7621 Pcie PHY core + * @dev: pointer to device + * @regmap: kernel regmap pointer + * @phy: pointer to the kernel PHY device + * @port_base: base register + * @has_dual_port: if the phy has dual ports. + * @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst' + * needs to be executed. Depends on chip revision. + */ +struct mt7621_pci_phy { + struct device *dev; + struct regmap *regmap; + struct phy *phy; + void __iomem *port_base; + bool has_dual_port; + bool bypass_pipe_rst; +}; + +static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy, + u32 reg, u32 clr, u32 set) +{ + u32 val; + + /* + * We cannot use 'regmap_write_bits' here because internally + * 'set' is masked before is set to the value that will be + * written to the register. That way results in no reliable + * pci setup. Avoid to mask 'set' before set value to 'val' + * completely avoid the problem. + */ + regmap_read(phy->regmap, reg, &val); + val &= ~clr; + val |= set; + regmap_write(phy->regmap, reg, val); +} + +static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy) +{ + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_RST); + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_CMD_FRC); + + if (phy->has_dual_port) { + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, + 0, RG_PE1_PIPE_RST); + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, + 0, RG_PE1_PIPE_CMD_FRC); + } +} + +static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy) +{ + struct device *dev = phy->dev; + u32 xtal_mode; + + xtal_mode = FIELD_GET(XTAL_MASK, rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0)); + + /* Set PCIe Port PHY to disable SSC */ + /* Debug Xtal Type */ + mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG, + RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE, + RG_PE1_FRC_H_XTAL_TYPE | + FIELD_PREP(RG_PE1_H_XTAL_TYPE, 0x00)); + + /* disable port */ + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG, RG_PE1_PHY_EN, + RG_PE1_FRC_PHY_EN); + + if (phy->has_dual_port) { + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + } + + if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ + /* Set Pre-divider ratio (for host mode) */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x01)); + + dev_dbg(dev, "Xtal is 40MHz\n"); + } else if (xtal_mode >= 6) { /* 25MHz Xal */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00)); + + /* Select feedback clock */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG, + RG_PE1_H_PLL_FBKSEL, + FIELD_PREP(RG_PE1_H_PLL_FBKSEL, 0x01)); + + /* DDS NCPO PCW (for host mode) */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, + RG_PE1_H_LCDDS_SSC_PRD, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_PRD, 0x00)); + + /* DDS SSC dither period control */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, + RG_PE1_H_LCDDS_SSC_PRD, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_PRD, 0x18d)); + + /* DDS SSC dither amplitude control */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG, + RG_PE1_H_LCDDS_SSC_DELTA | + RG_PE1_H_LCDDS_SSC_DELTA1, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_DELTA, 0x4a) | + FIELD_PREP(RG_PE1_H_LCDDS_SSC_DELTA1, 0x4a)); + + dev_dbg(dev, "Xtal is 25MHz\n"); + } else { /* 20MHz Xtal */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00)); + + dev_dbg(dev, "Xtal is 20MHz\n"); + } + + /* DDS clock inversion */ + mt7621_phy_rmw(phy, RG_PE1_LCDDS_CLK_PH_INV_REG, + RG_PE1_LCDDS_CLK_PH_INV, RG_PE1_LCDDS_CLK_PH_INV); + + /* Set PLL bits */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, + RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR | + RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN, + FIELD_PREP(RG_PE1_H_PLL_BC, 0x02) | + FIELD_PREP(RG_PE1_H_PLL_BP, 0x06) | + FIELD_PREP(RG_PE1_H_PLL_IR, 0x02) | + FIELD_PREP(RG_PE1_H_PLL_IC, 0x01) | + FIELD_PREP(RG_PE1_PLL_DIVEN, 0x02)); + + mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG, RG_PE1_H_PLL_BR, + FIELD_PREP(RG_PE1_H_PLL_BR, 0x00)); + + if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ + /* set force mode enable of da_pe1_mstckdiv */ + mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG, + RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV, + FIELD_PREP(RG_PE1_MSTCKDIV, 0x01) | + RG_PE1_FRC_MSTCKDIV); + } +} + +static int mt7621_pci_phy_init(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + if (mphy->bypass_pipe_rst) + mt7621_bypass_pipe_rst(mphy); + + mt7621_set_phy_for_ssc(mphy); + + return 0; +} + +static int mt7621_pci_phy_power_on(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + /* Enable PHY and disable force mode */ + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, + RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); + + if (mphy->has_dual_port) { + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); + } + + return 0; +} + +static int mt7621_pci_phy_power_off(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + /* Disable PHY */ + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + + if (mphy->has_dual_port) { + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + } + + return 0; +} + +static int mt7621_pci_phy_exit(struct phy *phy) +{ + return 0; +} + +static const struct phy_ops mt7621_pci_phy_ops = { + .init = mt7621_pci_phy_init, + .exit = mt7621_pci_phy_exit, + .power_on = mt7621_pci_phy_power_on, + .power_off = mt7621_pci_phy_power_off, + .owner = THIS_MODULE, +}; + +static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev); + + if (WARN_ON(args->args[0] >= MAX_PHYS)) + return ERR_PTR(-ENODEV); + + mt7621_phy->has_dual_port = args->args[0]; + + dev_info(dev, "PHY for 0x%08x (dual port = %d)\n", + (unsigned int)mt7621_phy->port_base, mt7621_phy->has_dual_port); + + return mt7621_phy->phy; +} + +static const struct soc_device_attribute mt7621_pci_quirks_match[] = { + { .soc_id = "mt7621", .revision = "E2" } +}; + +static const struct regmap_config mt7621_pci_phy_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x700, +}; + +static int mt7621_pci_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct soc_device_attribute *attr; + struct phy_provider *provider; + struct mt7621_pci_phy *phy; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + attr = soc_device_match(mt7621_pci_quirks_match); + if (attr) + phy->bypass_pipe_rst = true; + + phy->dev = dev; + platform_set_drvdata(pdev, phy); + + phy->port_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->port_base)) { + dev_err(dev, "failed to remap phy regs\n"); + return PTR_ERR(phy->port_base); + } + + phy->regmap = devm_regmap_init_mmio(phy->dev, phy->port_base, + &mt7621_pci_phy_regmap_config); + if (IS_ERR(phy->regmap)) + return PTR_ERR(phy->regmap); + + phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy->phy, phy); + + provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id mt7621_pci_phy_ids[] = { + { .compatible = "mediatek,mt7621-pci-phy" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt7621_pci_ids); + +static struct platform_driver mt7621_pci_phy_driver = { + .probe = mt7621_pci_phy_probe, + .driver = { + .name = "mt7621-pci-phy", + .of_match_table = of_match_ptr(mt7621_pci_phy_ids), + }, +}; + +builtin_platform_driver(mt7621_pci_phy_driver); + +MODULE_AUTHOR("Sergio Paracuellos "); +MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver"); +MODULE_LICENSE("GPL v2"); -- 2.25.1