From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 151DECDB47C for ; Thu, 25 Jun 2026 02:40:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=IJeplgejA1hUTBaBt/PvggL/lR9v1jlIlJGEA1zzuC0=; b=4gwNT1n/CWrvwo 8FuwK6KK7hZnDnZnfvR90w4xIhX1I+t3adORdwzdbmGtMV6IhRT5hRtov2N+KmsU2AgCaURZtZDWb 0OcSADzS8VRLs5xe3OUPI9FZhy078oe2E+5wnRg3RnkM62eK0BgVLvybq4DAGeHavqYskf7OIsUbM 7zeV3eSDh820l12kFBCq79vwOBjzVgl6kVwOdNEk4QigRpPCuF9e/YQClyd0zeSKq9Zxw28uNH0Sk /gRMD2S0UKfvCsVGZu0qaWrkkTyuClNzEYHzt5F0RGHfxFvUufMhGbrw24+Q12mzHjKdLGYy0eMPj tIThmHsgc8ci8IP7BYfA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1wca0v-00000008Zu7-3IMf; Thu, 25 Jun 2026 02:40:25 +0000 Received: from mail-pl1-x631.google.com ([2607:f8b0:4864:20::631]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1wca0q-00000008Zq1-0el8 for linux-phy@lists.infradead.org; Thu, 25 Jun 2026 02:40:21 +0000 Received: by mail-pl1-x631.google.com with SMTP id d9443c01a7336-2c6bdb8a8bdso9212645ad.1 for ; Wed, 24 Jun 2026 19:40:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1782355219; x=1782960019; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=gZF9/d8gcaFhPvH5Xrt9e1pEQ7MzJhwRlysg1r+yUBQ=; b=aDezQ+PWPMhJjalZXd3C6ttYv66h32xPnnnsWccOdU03TQIubEZqQ9WHEhoiQcPR2s vB6Un+Bd4GyGEYN3EtbKO56o/pXaBdCjVaZ4PQPyj9A1Qh0GY0qBHImjokdtIQCWMqgD e2UJcL2fNUfZL614mACm4nrYfUr2DaNEPTpa7u6cfexyUeSld3MWVGzLcaVTv2lgB1Th 8p2isIyC6CFYNQsq+L6ajrECBx9ylT3QIX4TL6ljmeBPGFl5JxJkspglke4S1wTmOLBI w3f0oMxkbwTRL3KcIEczMcqJJjlxdP8AjulwNVloyEI6Hpfhvy86vE11PxO2Ur0t+6hu 0nwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782355219; x=1782960019; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=gZF9/d8gcaFhPvH5Xrt9e1pEQ7MzJhwRlysg1r+yUBQ=; b=oXj1cZ9uagIVg0w3VBEWXEYaT0l9OmvEI51l0IdyIP5pmKifHAgAOlVQtuEwdfspqI g3/sNLX9U/RAcQLpD0A86A8vVXzA/0KsR0mKzkuBS2EtMYRWmbI1Oy/ZfQvL9urnPQ7X 3Saatd4atMakijLpTeVUwct+qlRQUPGwsjn+pjmuVBlKtusoSM7PaKw9baJqbf3MyquV izddGY4PIgMxHW9ZvTUEac6zY/z3yUxjmLtWCjPO0yv+c+xIVAzDhza9qpe4WCPXbUko UcaVlVdS275nfcPxbM2H6MlthL34KoVF2pP/R7b7dT5u+UvM8wSfWEJORCcxYMUGi7NA 2+yg== X-Forwarded-Encrypted: i=1; AHgh+RqfwjJk6Yf4vfYIIA7r37UZDhO+pyPzCfLBA427SiBCN1QEDML8bKoFL1hbG3TF5hb4LvETLVYvURc=@lists.infradead.org X-Gm-Message-State: AOJu0YynuqDTzEmkjcW+qZ3xM+pVRSYdMVzBLOTC+boMplVbY8nPRUNE P+pGhbfCUHA9PB1a50TCNNql6N68VgIWMDTc9a0Hga4tddscSn6JgSiZ X-Gm-Gg: AfdE7cnzJKlJqR0E7Nvf5BQLug2UFhXwmuhfMrmRiMwiO3TdAZ3CaNwM1pQkQCuiA9n OaSLuP9l/4T4Aoqx6Xi7V9u7pwuZr4NCwSbjjdwFcCRUAEKcpQyHx+YYgIAMGE769GCgmBIo8NY 3gf27nj/SSRD10NInZRlzRd9vCyLQkxaOt4kZ2gmjfL9l/1bATaKaGTQ/BB+UD6heDUhnlvpsP7 ws2SgqoeeAkRWUR0XzKpggoDNUv8c4My9vckoo16EtfvJ5hX4Edf089yE15QEPTX5I+9H7letgl 0JlEVA9Lee3/fzq4niln0uAqioaDQJWoT4+aOIrhwDbIYFaDHtRJol6yEfXA/FZowLGKx7nNn15 Fn0EScJAunBnEYAcHuI3fexjqyXjo6kwZP5ouEM7lUAL2RZ2sj9xwt5yLQXX89Nx8kOAZzJ5EyN 4HIK2FprDdO40jj6sP1yaHViInXeR6zkYncIbTwfdl/B5ZvqCf1I2fInBiK09aiEnVq5sghT1yV g== X-Received: by 2002:a17:903:2281:b0:2c7:ef3c:c672 with SMTP id d9443c01a7336-2c7fc696b4dmr7325035ad.11.1782355219053; Wed, 24 Jun 2026 19:40:19 -0700 (PDT) Received: from localhost.localdomain (60-250-196-139.hinet-ip.hinet.net. [60.250.196.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2c7f64dc839sm8538545ad.68.2026.06.24.19.40.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Jun 2026 19:40:18 -0700 (PDT) From: Joey Lu To: Vinod Koul , Neil Armstrong Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Arnd Bergmann , Catalin Marinas , Jacky Huang , Shan-Chun Hung , Hui-Ping Chen , Joey Lu , linux-phy@lists.infradead.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Lu Subject: [PATCH v2 4/4] phy: nuvoton: phy-ma35d1-usb2: extend to dual-port with OTG support Date: Thu, 25 Jun 2026 10:39:58 +0800 Message-ID: <20260625023958.569299-5-a0987203069@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260625023958.569299-1-a0987203069@gmail.com> References: <20260625023958.569299-1-a0987203069@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260624_194020_362854_AF0DB6D9 X-CRM114-Status: GOOD ( 25.94 ) X-BeenThere: linux-phy@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux Phy Mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-phy" Errors-To: linux-phy-bounces+linux-phy=archiver.kernel.org@lists.infradead.org The existing driver handled only PHY0 in device mode (DWC2 gadget). Extend it to manage both PHY ports and integrate OTG support, per reviewer suggestion to reuse the existing driver rather than add a separate one. The MA35D1 SoC has two USB PHY ports: - PHY0 (USB0): OTG port shared between the DWC2 gadget controller and EHCI0/OHCI0 host controllers. A hardware mux in the SoC automatically routes the USB0 signals to the appropriate controller based on the USB ID pin state. - PHY1 (USB1): dedicated host-only port for EHCI1/OHCI1. Key changes: Dual-port support A loop in probe() creates two struct phy objects, one per port, each with its own phy_set_drvdata() context. A custom xlate function selects the correct phy by the single #phy-cells argument. Unified .init callback A single ma35_usb_phy_init() handles both ports using parametric register macros (USBPMISCR_PHY_*(n)). If the SUSPEND bit is already set the init is skipped entirely, preventing the shared PHY0 from being reset while a live link is active. On cold boot, PHY0 polls for either host-mode clocks (HSTCKSTB + CK12MSTB) or device-mode clock (DEVCKSTB) since the hardware selects the role automatically; PHY1 polls for host-mode clocks only. Clock management removed .power_on/.power_off and all struct clk handling are removed. Each USB controller (DWC2, EHCI, OHCI) already gates its own clock directly through its DTS clocks binding. Having the PHY driver redundantly enable the same gates added unnecessary coupling without benefit. OTG role switch for PHY0 A read-only USB role switch is registered, reporting the current OTG role by reading the USB ID pin state from PWRONOTP[16]. .set returns -EOPNOTSUPP since the hardware mux is fully automatic. allow_userspace_control is kept true to preserve the sysfs attribute for observation; writes are rejected by .set. syscon regmap via parent The driver obtains the regmap by calling syscon_node_to_regmap(pdev->dev.parent->of_node), removing the need for the nuvoton,sys phandle. Signed-off-by: Joey Lu --- drivers/phy/nuvoton/phy-ma35d1-usb2.c | 267 ++++++++++++++++++-------- 1 file changed, 192 insertions(+), 75 deletions(-) diff --git a/drivers/phy/nuvoton/phy-ma35d1-usb2.c b/drivers/phy/nuvoton/phy-ma35d1-usb2.c index 9a459b700ed4..19242b10cee3 100644 --- a/drivers/phy/nuvoton/phy-ma35d1-usb2.c +++ b/drivers/phy/nuvoton/phy-ma35d1-usb2.c @@ -1,11 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2024 Nuvoton Technology Corp. + * Nuvoton MA35D1 USB 2.0 PHY driver + * + * Supports PHY0 (USB0 OTG port, shared between DWC2 gadget and EHCI0/OHCI0) + * and PHY1 (USB1 host-only port, used by EHCI1/OHCI1). The hardware mux on + * PHY0 switches automatically via the USB ID pin. + * + * Copyright (C) 2026 Nuvoton Technology Corp. */ #include -#include #include -#include #include #include #include @@ -13,131 +17,244 @@ #include #include #include +#include -/* USB PHY Miscellaneous Control Register */ -#define MA35_SYS_REG_USBPMISCR 0x60 -#define PHY0POR BIT(0) /* PHY Power-On Reset Control Bit */ -#define PHY0SUSPEND BIT(1) /* PHY Suspend; 0: suspend, 1: operaion */ -#define PHY0COMN BIT(2) /* PHY Common Block Power-Down Control */ -#define PHY0DEVCKSTB BIT(10) /* PHY 60 MHz UTMI clock stable bit */ +#define MA35_SYS_PWRONOTP 0x04 +#define PWRONOTP_USBP0ID BIT(16) /* USB0 ID pin state */ + +#define MA35_SYS_USBPMISCR 0x60 +#define USBPMISCR_PHY_POR(n) BIT(0 + (n) * 16) +#define USBPMISCR_PHY_SUSPEND(n) BIT(1 + (n) * 16) +#define USBPMISCR_PHY_COMN(n) BIT(2 + (n) * 16) +#define USBPMISCR_PHY_HSTCKSTB(n) BIT(8 + (n) * 16) +#define USBPMISCR_PHY_CK12MSTB(n) BIT(9 + (n) * 16) +#define USBPMISCR_PHY_DEVCKSTB(n) BIT(10 + (n) * 16) +/* Mask for control bits (POR, SUSPEND, COMN) of one PHY */ +#define USBPMISCR_PHY_CTL_MASK(n) (0x7u << ((n) * 16)) +/* Host-mode ready: SUSPEND set */ +#define USBPMISCR_PHY_HOST_READY(n) (USBPMISCR_PHY_SUSPEND(n) | \ + USBPMISCR_PHY_HSTCKSTB(n) | \ + USBPMISCR_PHY_CK12MSTB(n)) +/* Device-mode ready: SUSPEND set */ +#define USBPMISCR_PHY_DEV_READY(n) (USBPMISCR_PHY_SUSPEND(n) | \ + USBPMISCR_PHY_DEVCKSTB(n)) +/* RCALCODE: 4-bit resistor trim at bits [15:12] (PHY0) or [31:28] (PHY1) */ +#define USBPMISCR_RCAL_SHIFT(n) (12 + (n) * 16) +#define USBPMISCR_RCAL_MASK(n) GENMASK(USBPMISCR_RCAL_SHIFT(n) + 3, \ + USBPMISCR_RCAL_SHIFT(n)) + +#define MA35_SYS_MISCFCR0 0x70 +/* Bit 12: USB host over-current detect polarity (shared, both ports) */ +#define MISCFCR0_UHOVRCURH BIT(12) + +#define MA35_PHY_NUM 2 + +struct ma35_phy_port { + struct phy *phy; + unsigned int idx; +}; struct ma35_usb_phy { - struct clk *clk; struct device *dev; struct regmap *sysreg; + struct ma35_phy_port port[MA35_PHY_NUM]; + struct usb_role_switch *role_sw; }; -static int ma35_usb_phy_power_on(struct phy *phy) +static int ma35_usb_phy_init(struct phy *phy) { - struct ma35_usb_phy *p_phy = phy_get_drvdata(phy); + struct ma35_phy_port *port = phy_get_drvdata(phy); + struct ma35_usb_phy *p = container_of(port - port->idx, + struct ma35_usb_phy, port[0]); + unsigned int n = port->idx; unsigned int val; int ret; - ret = clk_prepare_enable(p_phy->clk); - if (ret < 0) { - dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret); - return ret; - } + regmap_read(p->sysreg, MA35_SYS_USBPMISCR, &val); - regmap_read(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, &val); - if (val & PHY0SUSPEND) { - /* - * USB PHY0 is in operation mode already - * make sure USB PHY 60 MHz UTMI Interface Clock ready - */ - ret = regmap_read_poll_timeout(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, val, - val & PHY0DEVCKSTB, 10, 1000); - if (ret == 0) - return 0; - } + if (val & USBPMISCR_PHY_SUSPEND(n)) + return 0; - /* - * reset USB PHY0. - * wait until USB PHY0 60 MHz UTMI Interface Clock ready - */ - regmap_update_bits(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, 0x7, (PHY0POR | PHY0SUSPEND)); + regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR, + USBPMISCR_PHY_CTL_MASK(n), + USBPMISCR_PHY_POR(n) | USBPMISCR_PHY_SUSPEND(n)); udelay(20); - /* make USB PHY0 enter operation mode */ - regmap_update_bits(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, 0x7, PHY0SUSPEND); + regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR, + USBPMISCR_PHY_CTL_MASK(n), + USBPMISCR_PHY_SUSPEND(n)); + + if (n == 0) { + ret = regmap_read_poll_timeout(p->sysreg, MA35_SYS_USBPMISCR, + val, + ((val & USBPMISCR_PHY_HOST_READY(0)) == + USBPMISCR_PHY_HOST_READY(0)) || + ((val & USBPMISCR_PHY_DEV_READY(0)) == + USBPMISCR_PHY_DEV_READY(0)), + 10, 1000); + } else { + ret = regmap_read_poll_timeout(p->sysreg, MA35_SYS_USBPMISCR, + val, + (val & USBPMISCR_PHY_HOST_READY(n)) == + USBPMISCR_PHY_HOST_READY(n), + 10, 1000); + } - /* make sure USB PHY 60 MHz UTMI Interface Clock ready */ - ret = regmap_read_poll_timeout(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, val, - val & PHY0DEVCKSTB, 10, 1000); - if (ret == -ETIMEDOUT) { - dev_err(p_phy->dev, "Check PHY clock, Timeout: %d\n", ret); - clk_disable_unprepare(p_phy->clk); + if (ret) { + dev_err(p->dev, "USB PHY%u clock not stable (USBPMISCR=0x%08x)\n", + n, val); return ret; } return 0; } -static int ma35_usb_phy_power_off(struct phy *phy) +static const struct phy_ops ma35_usb_phy_ops = { + .init = ma35_usb_phy_init, + .owner = THIS_MODULE, +}; + +static int ma35_role_sw_set(struct usb_role_switch *sw, enum usb_role role) +{ + return -EOPNOTSUPP; +} + +static enum usb_role ma35_role_sw_get(struct usb_role_switch *sw) +{ + struct ma35_usb_phy *p = usb_role_switch_get_drvdata(sw); + u32 val; + + regmap_read(p->sysreg, MA35_SYS_PWRONOTP, &val); + + return (val & PWRONOTP_USBP0ID) ? USB_ROLE_HOST : USB_ROLE_DEVICE; +} + +static int ma35_role_switch_init(struct platform_device *pdev, + struct ma35_usb_phy *p) { - struct ma35_usb_phy *p_phy = phy_get_drvdata(phy); + struct usb_role_switch_desc sw_desc = {0}; + + sw_desc.set = ma35_role_sw_set; + sw_desc.get = ma35_role_sw_get; + sw_desc.allow_userspace_control = true; + sw_desc.driver_data = p; + sw_desc.fwnode = dev_fwnode(&pdev->dev); + + p->role_sw = usb_role_switch_register(&pdev->dev, &sw_desc); + if (IS_ERR(p->role_sw)) + return dev_err_probe(&pdev->dev, PTR_ERR(p->role_sw), + "failed to register role switch\n"); - clk_disable_unprepare(p_phy->clk); return 0; } -static const struct phy_ops ma35_usb_phy_ops = { - .power_on = ma35_usb_phy_power_on, - .power_off = ma35_usb_phy_power_off, - .owner = THIS_MODULE, -}; +static void ma35_role_switch_exit(struct ma35_usb_phy *p) +{ + if (p->role_sw) { + usb_role_switch_unregister(p->role_sw); + p->role_sw = NULL; + } +} + +static struct phy *ma35_usb_phy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct ma35_usb_phy *p = dev_get_drvdata(dev); + + if (args->args[0] >= MA35_PHY_NUM) + return ERR_PTR(-EINVAL); + + return p->port[args->args[0]].phy; +} static int ma35_usb_phy_probe(struct platform_device *pdev) { struct phy_provider *provider; - struct ma35_usb_phy *p_phy; - struct phy *phy; + struct ma35_usb_phy *p; + int n, ret; + u32 code; - p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL); - if (!p_phy) + p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + if (!p) return -ENOMEM; - p_phy->dev = &pdev->dev; - platform_set_drvdata(pdev, p_phy); + p->dev = &pdev->dev; + platform_set_drvdata(pdev, p); + + p->sysreg = syscon_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(p->sysreg)) + return dev_err_probe(&pdev->dev, PTR_ERR(p->sysreg), + "failed to get parent SYS regmap\n"); + + for (n = 0; n < MA35_PHY_NUM; n++) { + if (of_property_read_u32_index(pdev->dev.of_node, + "nuvoton,rcalcode", n, &code)) + continue; - p_phy->sysreg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "nuvoton,sys"); - if (IS_ERR(p_phy->sysreg)) - return dev_err_probe(&pdev->dev, PTR_ERR(p_phy->sysreg), - "Failed to get SYS registers\n"); + if (code > 15) + return dev_err_probe(&pdev->dev, -EINVAL, + "rcalcode[%d] %u out of range (0-15)\n", + n, code); - p_phy->clk = of_clk_get(pdev->dev.of_node, 0); - if (IS_ERR(p_phy->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(p_phy->clk), - "failed to find usb_phy clock\n"); + regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR, + USBPMISCR_RCAL_MASK(n), + code << USBPMISCR_RCAL_SHIFT(n)); + } + + if (of_property_read_bool(pdev->dev.of_node, "nuvoton,oc-active-high")) + regmap_update_bits(p->sysreg, MA35_SYS_MISCFCR0, + MISCFCR0_UHOVRCURH, MISCFCR0_UHOVRCURH); + + for (n = 0; n < MA35_PHY_NUM; n++) { + p->port[n].idx = n; - phy = devm_phy_create(&pdev->dev, NULL, &ma35_usb_phy_ops); - if (IS_ERR(phy)) - return dev_err_probe(&pdev->dev, PTR_ERR(phy), "Failed to create PHY\n"); + p->port[n].phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, + &ma35_usb_phy_ops); + if (IS_ERR(p->port[n].phy)) + return dev_err_probe(&pdev->dev, PTR_ERR(p->port[n].phy), + "failed to create PHY%d\n", n); - phy_set_drvdata(phy, p_phy); + phy_set_drvdata(p->port[n].phy, &p->port[n]); + } + + ret = ma35_role_switch_init(pdev, p); + if (ret) + return ret; - provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); - if (IS_ERR(provider)) + provider = devm_of_phy_provider_register(&pdev->dev, ma35_usb_phy_xlate); + if (IS_ERR(provider)) { + ma35_role_switch_exit(p); return dev_err_probe(&pdev->dev, PTR_ERR(provider), - "Failed to register PHY provider\n"); + "failed to register PHY provider\n"); + } + return 0; } +static void ma35_usb_phy_remove(struct platform_device *pdev) +{ + struct ma35_usb_phy *p = platform_get_drvdata(pdev); + + ma35_role_switch_exit(p); +} + static const struct of_device_id ma35_usb_phy_of_match[] = { - { .compatible = "nuvoton,ma35d1-usb2-phy", }, - { }, + { .compatible = "nuvoton,ma35d1-usb2-phy" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ma35_usb_phy_of_match); static struct platform_driver ma35_usb_phy_driver = { .probe = ma35_usb_phy_probe, - .driver = { - .name = "ma35d1-usb2-phy", - .of_match_table = ma35_usb_phy_of_match, + .remove = ma35_usb_phy_remove, + .driver = { + .name = "ma35d1-usb2-phy", + .of_match_table = ma35_usb_phy_of_match, }, }; module_platform_driver(ma35_usb_phy_driver); MODULE_DESCRIPTION("Nuvoton ma35d1 USB2.0 PHY driver"); MODULE_AUTHOR("Hui-Ping Chen "); +MODULE_AUTHOR("Joey Lu "); MODULE_LICENSE("GPL"); -- 2.43.0 -- linux-phy mailing list linux-phy@lists.infradead.org https://lists.infradead.org/mailman/listinfo/linux-phy