123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- From dde0e95fff92e9f5009f3bea75278e0e34a48822 Mon Sep 17 00:00:00 2001
- From: Daniel Golle <[email protected]>
- Date: Tue, 12 Dec 2023 03:47:47 +0000
- Subject: [PATCH 5/5] net: pcs: add driver for MediaTek USXGMII PCS
- Add driver for USXGMII PCS found in the MediaTek MT7988 SoC and supporting
- USXGMII, 10GBase-R and 5GBase-R interface modes.
- Signed-off-by: Daniel Golle <[email protected]>
- ---
- MAINTAINERS | 2 +
- drivers/net/pcs/Kconfig | 11 +
- drivers/net/pcs/Makefile | 1 +
- drivers/net/pcs/pcs-mtk-usxgmii.c | 456 ++++++++++++++++++++++++++++
- include/linux/pcs/pcs-mtk-usxgmii.h | 27 ++
- 5 files changed, 497 insertions(+)
- create mode 100644 drivers/net/pcs/pcs-mtk-usxgmii.c
- create mode 100644 include/linux/pcs/pcs-mtk-usxgmii.h
- --- a/MAINTAINERS
- +++ b/MAINTAINERS
- @@ -12941,7 +12941,9 @@ M: Daniel Golle <[email protected]>
- L: [email protected]
- S: Maintained
- F: drivers/net/pcs/pcs-mtk-lynxi.c
- +F: drivers/net/pcs/pcs-mtk-usxgmii.c
- F: include/linux/pcs/pcs-mtk-lynxi.h
- +F: include/linux/pcs/pcs-mtk-usxgmii.h
-
- MEDIATEK I2C CONTROLLER DRIVER
- M: Qii Wang <[email protected]>
- --- a/drivers/net/pcs/Kconfig
- +++ b/drivers/net/pcs/Kconfig
- @@ -18,6 +18,17 @@ config PCS_LYNX
- This module provides helpers to phylink for managing the Lynx PCS
- which is part of the Layerscape and QorIQ Ethernet SERDES.
-
- +config PCS_MTK_USXGMII
- + tristate "MediaTek USXGMII PCS"
- + select PCS_MTK_LYNXI
- + select PHY_MTK_PEXTP
- + select PHYLINK
- + help
- + This module provides a driver for MediaTek's USXGMII PCS supporting
- + 10GBase-R, 5GBase-R and USXGMII interface modes.
- + 1000Base-X, 2500Base-X and Cisco SGMII are supported on the same
- + differential pairs via an embedded LynxI PHY.
- +
- config PCS_RZN1_MIIC
- tristate "Renesas RZ/N1 MII converter"
- depends on OF && (ARCH_RZN1 || COMPILE_TEST)
- --- a/drivers/net/pcs/Makefile
- +++ b/drivers/net/pcs/Makefile
- @@ -8,3 +8,4 @@ obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
- obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o
- obj-$(CONFIG_PCS_ALTERA_TSE) += pcs-altera-tse.o
- obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o
- +obj-$(CONFIG_PCS_MTK_USXGMII) += pcs-mtk-usxgmii.o
- --- /dev/null
- +++ b/drivers/net/pcs/pcs-mtk-usxgmii.c
- @@ -0,0 +1,456 @@
- +// SPDX-License-Identifier: GPL-2.0
- +/*
- + * Copyright (c) 2023 MediaTek Inc.
- + * Author: Henry Yen <[email protected]>
- + * Daniel Golle <[email protected]>
- + */
- +
- +#include <linux/clk.h>
- +#include <linux/io.h>
- +#include <linux/mfd/syscon.h>
- +#include <linux/mdio.h>
- +#include <linux/mutex.h>
- +#include <linux/of.h>
- +#include <linux/of_platform.h>
- +#include <linux/reset.h>
- +#include <linux/pcs/pcs-mtk-usxgmii.h>
- +#include <linux/platform_device.h>
- +
- +/* USXGMII subsystem config registers */
- +/* Register to control speed */
- +#define RG_PHY_TOP_SPEED_CTRL1 0x80c
- +#define USXGMII_RATE_UPDATE_MODE BIT(31)
- +#define USXGMII_MAC_CK_GATED BIT(29)
- +#define USXGMII_IF_FORCE_EN BIT(28)
- +#define USXGMII_RATE_ADAPT_MODE GENMASK(10, 8)
- +#define USXGMII_RATE_ADAPT_MODE_X1 0
- +#define USXGMII_RATE_ADAPT_MODE_X2 1
- +#define USXGMII_RATE_ADAPT_MODE_X4 2
- +#define USXGMII_RATE_ADAPT_MODE_X10 3
- +#define USXGMII_RATE_ADAPT_MODE_X100 4
- +#define USXGMII_RATE_ADAPT_MODE_X5 5
- +#define USXGMII_RATE_ADAPT_MODE_X50 6
- +#define USXGMII_XFI_RX_MODE GENMASK(6, 4)
- +#define USXGMII_XFI_TX_MODE GENMASK(2, 0)
- +#define USXGMII_XFI_MODE_10G 0
- +#define USXGMII_XFI_MODE_5G 1
- +#define USXGMII_XFI_MODE_2P5G 3
- +
- +/* Register to control PCS AN */
- +#define RG_PCS_AN_CTRL0 0x810
- +#define USXGMII_AN_RESTART BIT(31)
- +#define USXGMII_AN_SYNC_CNT GENMASK(30, 11)
- +#define USXGMII_AN_ENABLE BIT(0)
- +
- +#define RG_PCS_AN_CTRL2 0x818
- +#define USXGMII_LINK_TIMER_IDLE_DETECT GENMASK(29, 20)
- +#define USXGMII_LINK_TIMER_COMP_ACK_DETECT GENMASK(19, 10)
- +#define USXGMII_LINK_TIMER_AN_RESTART GENMASK(9, 0)
- +
- +/* Register to read PCS AN status */
- +#define RG_PCS_AN_STS0 0x81c
- +#define USXGMII_LPA GENMASK(15, 0)
- +#define USXGMII_LPA_LATCH BIT(31)
- +
- +/* Register to read PCS link status */
- +#define RG_PCS_RX_STATUS0 0x904
- +#define RG_PCS_RX_STATUS_UPDATE BIT(16)
- +#define RG_PCS_RX_LINK_STATUS BIT(2)
- +
- +/* struct mtk_usxgmii_pcs - This structure holds each usxgmii PCS
- + * @pcs: Phylink PCS structure
- + * @dev: Pointer to device structure
- + * @base: IO memory to access PCS hardware
- + * @clk: Pointer to USXGMII clk
- + * @reset: Pointer to USXGMII reset control
- + * @interface: Currently selected interface mode
- + * @neg_mode: Currently used phylink neg_mode
- + * @node: List node
- + */
- +struct mtk_usxgmii_pcs {
- + struct phylink_pcs pcs;
- + struct device *dev;
- + void __iomem *base;
- + struct clk *clk;
- + struct reset_control *reset;
- + phy_interface_t interface;
- + unsigned int neg_mode;
- + struct list_head node;
- +};
- +
- +static LIST_HEAD(mtk_usxgmii_pcs_instances);
- +static DEFINE_MUTEX(instance_mutex);
- +
- +static u32 mtk_r32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg)
- +{
- + return ioread32(mpcs->base + reg);
- +}
- +
- +static void mtk_m32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg, u32 mask, u32 set)
- +{
- + u32 val;
- +
- + val = ioread32(mpcs->base + reg);
- + val &= ~mask;
- + val |= set;
- + iowrite32(val, mpcs->base + reg);
- +}
- +
- +static struct mtk_usxgmii_pcs *pcs_to_mtk_usxgmii_pcs(struct phylink_pcs *pcs)
- +{
- + return container_of(pcs, struct mtk_usxgmii_pcs, pcs);
- +}
- +
- +static void mtk_usxgmii_reset(struct mtk_usxgmii_pcs *mpcs)
- +{
- + reset_control_assert(mpcs->reset);
- + udelay(100);
- + reset_control_deassert(mpcs->reset);
- +
- + mdelay(10);
- +}
- +
- +static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
- + phy_interface_t interface,
- + const unsigned long *advertising,
- + bool permit_pause_to_mac)
- +{
- + struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
- + unsigned int an_ctrl = 0, link_timer = 0, xfi_mode = 0, adapt_mode = 0;
- + bool mode_changed = false;
- +
- + if (interface == PHY_INTERFACE_MODE_USXGMII) {
- + an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF) | USXGMII_AN_ENABLE;
- + link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) |
- + FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) |
- + FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B);
- + xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) |
- + FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G);
- + } else if (interface == PHY_INTERFACE_MODE_10GBASER) {
- + an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF);
- + link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) |
- + FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) |
- + FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B);
- + xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) |
- + FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G);
- + adapt_mode = USXGMII_RATE_UPDATE_MODE;
- + } else if (interface == PHY_INTERFACE_MODE_5GBASER) {
- + an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0xFF);
- + link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x3D) |
- + FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x3D) |
- + FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x3D);
- + xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_5G) |
- + FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_5G);
- + adapt_mode = USXGMII_RATE_UPDATE_MODE;
- + } else {
- + return -EINVAL;
- + }
- +
- + adapt_mode |= FIELD_PREP(USXGMII_RATE_ADAPT_MODE, USXGMII_RATE_ADAPT_MODE_X1);
- +
- + if (mpcs->interface != interface) {
- + mpcs->interface = interface;
- + mode_changed = true;
- + }
- +
- + mtk_usxgmii_reset(mpcs);
- +
- + /* Setup USXGMII AN ctrl */
- + mtk_m32(mpcs, RG_PCS_AN_CTRL0,
- + USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE,
- + an_ctrl);
- +
- + mtk_m32(mpcs, RG_PCS_AN_CTRL2,
- + USXGMII_LINK_TIMER_IDLE_DETECT |
- + USXGMII_LINK_TIMER_COMP_ACK_DETECT |
- + USXGMII_LINK_TIMER_AN_RESTART,
- + link_timer);
- +
- + mpcs->neg_mode = neg_mode;
- +
- + /* Gated MAC CK */
- + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1,
- + USXGMII_MAC_CK_GATED, USXGMII_MAC_CK_GATED);
- +
- + /* Enable interface force mode */
- + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1,
- + USXGMII_IF_FORCE_EN, USXGMII_IF_FORCE_EN);
- +
- + /* Setup USXGMII adapt mode */
- + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1,
- + USXGMII_RATE_UPDATE_MODE | USXGMII_RATE_ADAPT_MODE,
- + adapt_mode);
- +
- + /* Setup USXGMII speed */
- + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1,
- + USXGMII_XFI_RX_MODE | USXGMII_XFI_TX_MODE,
- + xfi_mode);
- +
- + usleep_range(1, 10);
- +
- + /* Un-gated MAC CK */
- + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_MAC_CK_GATED, 0);
- +
- + usleep_range(1, 10);
- +
- + /* Disable interface force mode for the AN mode */
- + if (an_ctrl & USXGMII_AN_ENABLE)
- + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_IF_FORCE_EN, 0);
- +
- + return mode_changed;
- +}
- +
- +static void mtk_usxgmii_pcs_get_fixed_speed(struct mtk_usxgmii_pcs *mpcs,
- + struct phylink_link_state *state)
- +{
- + u32 val = mtk_r32(mpcs, RG_PHY_TOP_SPEED_CTRL1);
- + int speed;
- +
- + /* Calculate speed from interface speed and rate adapt mode */
- + switch (FIELD_GET(USXGMII_XFI_RX_MODE, val)) {
- + case USXGMII_XFI_MODE_10G:
- + speed = 10000;
- + break;
- + case USXGMII_XFI_MODE_5G:
- + speed = 5000;
- + break;
- + case USXGMII_XFI_MODE_2P5G:
- + speed = 2500;
- + break;
- + default:
- + state->speed = SPEED_UNKNOWN;
- + return;
- + }
- +
- + switch (FIELD_GET(USXGMII_RATE_ADAPT_MODE, val)) {
- + case USXGMII_RATE_ADAPT_MODE_X100:
- + speed /= 100;
- + break;
- + case USXGMII_RATE_ADAPT_MODE_X50:
- + speed /= 50;
- + break;
- + case USXGMII_RATE_ADAPT_MODE_X10:
- + speed /= 10;
- + break;
- + case USXGMII_RATE_ADAPT_MODE_X5:
- + speed /= 5;
- + break;
- + case USXGMII_RATE_ADAPT_MODE_X4:
- + speed /= 4;
- + break;
- + case USXGMII_RATE_ADAPT_MODE_X2:
- + speed /= 2;
- + break;
- + case USXGMII_RATE_ADAPT_MODE_X1:
- + break;
- + default:
- + state->speed = SPEED_UNKNOWN;
- + return;
- + }
- +
- + state->speed = speed;
- + state->duplex = DUPLEX_FULL;
- +}
- +
- +static void mtk_usxgmii_pcs_get_an_state(struct mtk_usxgmii_pcs *mpcs,
- + struct phylink_link_state *state)
- +{
- + u16 lpa;
- +
- + /* Refresh LPA by toggling LPA_LATCH */
- + mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, USXGMII_LPA_LATCH);
- + ndelay(1020);
- + mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, 0);
- + ndelay(1020);
- + lpa = FIELD_GET(USXGMII_LPA, mtk_r32(mpcs, RG_PCS_AN_STS0));
- +
- + phylink_decode_usxgmii_word(state, lpa);
- +}
- +
- +static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs,
- + struct phylink_link_state *state)
- +{
- + struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
- +
- + /* Refresh USXGMII link status by toggling RG_PCS_AN_STATUS_UPDATE */
- + mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE,
- + RG_PCS_RX_STATUS_UPDATE);
- + ndelay(1020);
- + mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE, 0);
- + ndelay(1020);
- +
- + /* Read USXGMII link status */
- + state->link = FIELD_GET(RG_PCS_RX_LINK_STATUS,
- + mtk_r32(mpcs, RG_PCS_RX_STATUS0));
- +
- + /* Continuously repeat re-configuration sequence until link comes up */
- + if (!state->link) {
- + mtk_usxgmii_pcs_config(pcs, mpcs->neg_mode,
- + state->interface, NULL, false);
- + return;
- + }
- +
- + if (FIELD_GET(USXGMII_AN_ENABLE, mtk_r32(mpcs, RG_PCS_AN_CTRL0)))
- + mtk_usxgmii_pcs_get_an_state(mpcs, state);
- + else
- + mtk_usxgmii_pcs_get_fixed_speed(mpcs, state);
- +}
- +
- +static void mtk_usxgmii_pcs_restart_an(struct phylink_pcs *pcs)
- +{
- + struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
- +
- + mtk_m32(mpcs, RG_PCS_AN_CTRL0, USXGMII_AN_RESTART, USXGMII_AN_RESTART);
- +}
- +
- +static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
- + phy_interface_t interface,
- + int speed, int duplex)
- +{
- + /* Reconfiguring USXGMII to ensure the quality of the RX signal
- + * after the line side link up.
- + */
- + mtk_usxgmii_pcs_config(pcs, neg_mode, interface, NULL, false);
- +}
- +
- +static void mtk_usxgmii_pcs_disable(struct phylink_pcs *pcs)
- +{
- + struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
- +
- + mpcs->interface = PHY_INTERFACE_MODE_NA;
- + mpcs->neg_mode = -1;
- +}
- +
- +static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = {
- + .pcs_config = mtk_usxgmii_pcs_config,
- + .pcs_get_state = mtk_usxgmii_pcs_get_state,
- + .pcs_an_restart = mtk_usxgmii_pcs_restart_an,
- + .pcs_link_up = mtk_usxgmii_pcs_link_up,
- + .pcs_disable = mtk_usxgmii_pcs_disable,
- +};
- +
- +static int mtk_usxgmii_probe(struct platform_device *pdev)
- +{
- + struct device *dev = &pdev->dev;
- + struct mtk_usxgmii_pcs *mpcs;
- +
- + mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL);
- + if (!mpcs)
- + return -ENOMEM;
- +
- + mpcs->base = devm_platform_ioremap_resource(pdev, 0);
- + if (IS_ERR(mpcs->base))
- + return PTR_ERR(mpcs->base);
- +
- + mpcs->dev = dev;
- + mpcs->pcs.ops = &mtk_usxgmii_pcs_ops;
- + mpcs->pcs.poll = true;
- + mpcs->pcs.neg_mode = true;
- + mpcs->interface = PHY_INTERFACE_MODE_NA;
- + mpcs->neg_mode = -1;
- +
- + mpcs->clk = devm_clk_get_enabled(mpcs->dev, NULL);
- + if (IS_ERR(mpcs->clk))
- + return PTR_ERR(mpcs->clk);
- +
- + mpcs->reset = devm_reset_control_get_shared(dev, NULL);
- + if (IS_ERR(mpcs->reset))
- + return PTR_ERR(mpcs->reset);
- +
- + reset_control_deassert(mpcs->reset);
- +
- + platform_set_drvdata(pdev, mpcs);
- +
- + mutex_lock(&instance_mutex);
- + list_add_tail(&mpcs->node, &mtk_usxgmii_pcs_instances);
- + mutex_unlock(&instance_mutex);
- +
- + return 0;
- +}
- +
- +static int mtk_usxgmii_remove(struct platform_device *pdev)
- +{
- + struct device *dev = &pdev->dev;
- + struct mtk_usxgmii_pcs *cur, *tmp;
- +
- + mutex_lock(&instance_mutex);
- + list_for_each_entry_safe(cur, tmp, &mtk_usxgmii_pcs_instances, node)
- + if (cur->dev == dev) {
- + list_del(&cur->node);
- + break;
- + }
- + mutex_unlock(&instance_mutex);
- +
- + return 0;
- +}
- +
- +static const struct of_device_id mtk_usxgmii_of_mtable[] = {
- + { .compatible = "mediatek,mt7988-usxgmiisys" },
- + { /* sentinel */ },
- +};
- +MODULE_DEVICE_TABLE(of, mtk_usxgmii_of_mtable);
- +
- +struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np)
- +{
- + struct platform_device *pdev;
- + struct mtk_usxgmii_pcs *mpcs;
- +
- + if (!np)
- + return NULL;
- +
- + if (!of_device_is_available(np))
- + return ERR_PTR(-ENODEV);
- +
- + if (!of_match_node(mtk_usxgmii_of_mtable, np))
- + return ERR_PTR(-EINVAL);
- +
- + pdev = of_find_device_by_node(np);
- + if (!pdev || !platform_get_drvdata(pdev)) {
- + if (pdev)
- + put_device(&pdev->dev);
- + return ERR_PTR(-EPROBE_DEFER);
- + }
- +
- + mpcs = platform_get_drvdata(pdev);
- + device_link_add(dev, mpcs->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
- +
- + return &mpcs->pcs;
- +}
- +EXPORT_SYMBOL(mtk_usxgmii_pcs_get);
- +
- +void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs)
- +{
- + struct mtk_usxgmii_pcs *cur, *mpcs = NULL;
- +
- + if (!pcs)
- + return;
- +
- + mutex_lock(&instance_mutex);
- + list_for_each_entry(cur, &mtk_usxgmii_pcs_instances, node)
- + if (pcs == &cur->pcs) {
- + mpcs = cur;
- + break;
- + }
- + mutex_unlock(&instance_mutex);
- +
- + if (WARN_ON(!mpcs))
- + return;
- +
- + put_device(mpcs->dev);
- +}
- +EXPORT_SYMBOL(mtk_usxgmii_pcs_put);
- +
- +static struct platform_driver mtk_usxgmii_driver = {
- + .driver = {
- + .name = "mtk_usxgmii",
- + .suppress_bind_attrs = true,
- + .of_match_table = mtk_usxgmii_of_mtable,
- + },
- + .probe = mtk_usxgmii_probe,
- + .remove = mtk_usxgmii_remove,
- +};
- +module_platform_driver(mtk_usxgmii_driver);
- +
- +MODULE_LICENSE("GPL");
- +MODULE_DESCRIPTION("MediaTek USXGMII PCS driver");
- +MODULE_AUTHOR("Daniel Golle <[email protected]>");
- --- /dev/null
- +++ b/include/linux/pcs/pcs-mtk-usxgmii.h
- @@ -0,0 +1,27 @@
- +/* SPDX-License-Identifier: GPL-2.0 */
- +#ifndef __LINUX_PCS_MTK_USXGMII_H
- +#define __LINUX_PCS_MTK_USXGMII_H
- +
- +#include <linux/phylink.h>
- +
- +/**
- + * mtk_usxgmii_select_pcs() - Get MediaTek PCS instance
- + * @np: Pointer to device node indentifying a MediaTek USXGMII PCS
- + * @mode: Ethernet PHY interface mode
- + *
- + * Return PCS identified by a device node and the PHY interface mode in use
- + *
- + * Return: Pointer to phylink PCS instance of NULL
- + */
- +#if IS_ENABLED(CONFIG_PCS_MTK_USXGMII)
- +struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np);
- +void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs);
- +#else
- +static inline struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np)
- +{
- + return NULL;
- +}
- +static inline void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs) { }
- +#endif /* IS_ENABLED(CONFIG_PCS_MTK_USXGMII) */
- +
- +#endif /* __LINUX_PCS_MTK_USXGMII_H */
|