18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Broadcom UniMAC MDIO bus controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014-2017 Broadcom 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/of_mdio.h> 158c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 168c2ecf20Sopenharmony_ci#include <linux/phy.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_data/mdio-bcm-unimac.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/sched.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define MDIO_CMD 0x00 228c2ecf20Sopenharmony_ci#define MDIO_START_BUSY (1 << 29) 238c2ecf20Sopenharmony_ci#define MDIO_READ_FAIL (1 << 28) 248c2ecf20Sopenharmony_ci#define MDIO_RD (2 << 26) 258c2ecf20Sopenharmony_ci#define MDIO_WR (1 << 26) 268c2ecf20Sopenharmony_ci#define MDIO_PMD_SHIFT 21 278c2ecf20Sopenharmony_ci#define MDIO_PMD_MASK 0x1F 288c2ecf20Sopenharmony_ci#define MDIO_REG_SHIFT 16 298c2ecf20Sopenharmony_ci#define MDIO_REG_MASK 0x1F 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define MDIO_CFG 0x04 328c2ecf20Sopenharmony_ci#define MDIO_C22 (1 << 0) 338c2ecf20Sopenharmony_ci#define MDIO_C45 0 348c2ecf20Sopenharmony_ci#define MDIO_CLK_DIV_SHIFT 4 358c2ecf20Sopenharmony_ci#define MDIO_CLK_DIV_MASK 0x3F 368c2ecf20Sopenharmony_ci#define MDIO_SUPP_PREAMBLE (1 << 12) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct unimac_mdio_priv { 398c2ecf20Sopenharmony_ci struct mii_bus *mii_bus; 408c2ecf20Sopenharmony_ci void __iomem *base; 418c2ecf20Sopenharmony_ci int (*wait_func) (void *wait_func_data); 428c2ecf20Sopenharmony_ci void *wait_func_data; 438c2ecf20Sopenharmony_ci struct clk *clk; 448c2ecf20Sopenharmony_ci u32 clk_freq; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline u32 unimac_mdio_readl(struct unimac_mdio_priv *priv, u32 offset) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci /* MIPS chips strapped for BE will automagically configure the 508c2ecf20Sopenharmony_ci * peripheral registers for CPU-native byte order. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 538c2ecf20Sopenharmony_ci return __raw_readl(priv->base + offset); 548c2ecf20Sopenharmony_ci else 558c2ecf20Sopenharmony_ci return readl_relaxed(priv->base + offset); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic inline void unimac_mdio_writel(struct unimac_mdio_priv *priv, u32 val, 598c2ecf20Sopenharmony_ci u32 offset) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 628c2ecf20Sopenharmony_ci __raw_writel(val, priv->base + offset); 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci writel_relaxed(val, priv->base + offset); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic inline void unimac_mdio_start(struct unimac_mdio_priv *priv) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci u32 reg; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci reg = unimac_mdio_readl(priv, MDIO_CMD); 728c2ecf20Sopenharmony_ci reg |= MDIO_START_BUSY; 738c2ecf20Sopenharmony_ci unimac_mdio_writel(priv, reg, MDIO_CMD); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci return unimac_mdio_readl(priv, MDIO_CMD) & MDIO_START_BUSY; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int unimac_mdio_poll(void *wait_func_data) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct unimac_mdio_priv *priv = wait_func_data; 848c2ecf20Sopenharmony_ci unsigned int timeout = 1000; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci do { 878c2ecf20Sopenharmony_ci if (!unimac_mdio_busy(priv)) 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 918c2ecf20Sopenharmony_ci } while (--timeout); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return -ETIMEDOUT; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct unimac_mdio_priv *priv = bus->priv; 998c2ecf20Sopenharmony_ci int ret; 1008c2ecf20Sopenharmony_ci u32 cmd; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Prepare the read operation */ 1038c2ecf20Sopenharmony_ci cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT); 1048c2ecf20Sopenharmony_ci unimac_mdio_writel(priv, cmd, MDIO_CMD); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* Start MDIO transaction */ 1078c2ecf20Sopenharmony_ci unimac_mdio_start(priv); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci ret = priv->wait_func(priv->wait_func_data); 1108c2ecf20Sopenharmony_ci if (ret) 1118c2ecf20Sopenharmony_ci return ret; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci cmd = unimac_mdio_readl(priv, MDIO_CMD); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Some broken devices are known not to release the line during 1168c2ecf20Sopenharmony_ci * turn-around, e.g: Broadcom BCM53125 external switches, so check for 1178c2ecf20Sopenharmony_ci * that condition here and ignore the MDIO controller read failure 1188c2ecf20Sopenharmony_ci * indication. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (cmd & MDIO_READ_FAIL)) 1218c2ecf20Sopenharmony_ci return -EIO; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return cmd & 0xffff; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int unimac_mdio_write(struct mii_bus *bus, int phy_id, 1278c2ecf20Sopenharmony_ci int reg, u16 val) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct unimac_mdio_priv *priv = bus->priv; 1308c2ecf20Sopenharmony_ci u32 cmd; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Prepare the write operation */ 1338c2ecf20Sopenharmony_ci cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) | 1348c2ecf20Sopenharmony_ci (reg << MDIO_REG_SHIFT) | (0xffff & val); 1358c2ecf20Sopenharmony_ci unimac_mdio_writel(priv, cmd, MDIO_CMD); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci unimac_mdio_start(priv); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return priv->wait_func(priv->wait_func_data); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with 1438c2ecf20Sopenharmony_ci * their internal MDIO management controller making them fail to successfully 1448c2ecf20Sopenharmony_ci * be read from or written to for the first transaction. We insert a dummy 1458c2ecf20Sopenharmony_ci * BMSR read here to make sure that phy_get_device() and get_phy_id() can 1468c2ecf20Sopenharmony_ci * correctly read the PHY MII_PHYSID1/2 registers and successfully register a 1478c2ecf20Sopenharmony_ci * PHY device for this peripheral. 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * Once the PHY driver is registered, we can workaround subsequent reads from 1508c2ecf20Sopenharmony_ci * there (e.g: during system-wide power management). 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * bus->reset is invoked before mdiobus_scan during mdiobus_register and is 1538c2ecf20Sopenharmony_ci * therefore the right location to stick that workaround. Since we do not want 1548c2ecf20Sopenharmony_ci * to read from non-existing PHYs, we either use bus->phy_mask or do a manual 1558c2ecf20Sopenharmony_ci * Device Tree scan to limit the search area. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistatic int unimac_mdio_reset(struct mii_bus *bus) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct device_node *np = bus->dev.of_node; 1608c2ecf20Sopenharmony_ci struct device_node *child; 1618c2ecf20Sopenharmony_ci u32 read_mask = 0; 1628c2ecf20Sopenharmony_ci int addr; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (!np) { 1658c2ecf20Sopenharmony_ci read_mask = ~bus->phy_mask; 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci for_each_available_child_of_node(np, child) { 1688c2ecf20Sopenharmony_ci addr = of_mdio_parse_addr(&bus->dev, child); 1698c2ecf20Sopenharmony_ci if (addr < 0) 1708c2ecf20Sopenharmony_ci continue; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci read_mask |= 1 << addr; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci for (addr = 0; addr < PHY_MAX_ADDR; addr++) { 1778c2ecf20Sopenharmony_ci if (read_mask & 1 << addr) { 1788c2ecf20Sopenharmony_ci dev_dbg(&bus->dev, "Workaround for PHY @ %d\n", addr); 1798c2ecf20Sopenharmony_ci mdiobus_read(bus, addr, MII_BMSR); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void unimac_mdio_clk_set(struct unimac_mdio_priv *priv) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci unsigned long rate; 1898c2ecf20Sopenharmony_ci u32 reg, div; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* Keep the hardware default values */ 1928c2ecf20Sopenharmony_ci if (!priv->clk_freq) 1938c2ecf20Sopenharmony_ci return; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (!priv->clk) 1968c2ecf20Sopenharmony_ci rate = 250000000; 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci rate = clk_get_rate(priv->clk); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci div = (rate / (2 * priv->clk_freq)) - 1; 2018c2ecf20Sopenharmony_ci if (div & ~MDIO_CLK_DIV_MASK) { 2028c2ecf20Sopenharmony_ci pr_warn("Incorrect MDIO clock frequency, ignoring\n"); 2038c2ecf20Sopenharmony_ci return; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* The MDIO clock is the reference clock (typicaly 250Mhz) divided by 2078c2ecf20Sopenharmony_ci * 2 x (MDIO_CLK_DIV + 1) 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci reg = unimac_mdio_readl(priv, MDIO_CFG); 2108c2ecf20Sopenharmony_ci reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT); 2118c2ecf20Sopenharmony_ci reg |= div << MDIO_CLK_DIV_SHIFT; 2128c2ecf20Sopenharmony_ci unimac_mdio_writel(priv, reg, MDIO_CFG); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int unimac_mdio_probe(struct platform_device *pdev) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct unimac_mdio_pdata *pdata = pdev->dev.platform_data; 2188c2ecf20Sopenharmony_ci struct unimac_mdio_priv *priv; 2198c2ecf20Sopenharmony_ci struct device_node *np; 2208c2ecf20Sopenharmony_ci struct mii_bus *bus; 2218c2ecf20Sopenharmony_ci struct resource *r; 2228c2ecf20Sopenharmony_ci int ret; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci np = pdev->dev.of_node; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 2278c2ecf20Sopenharmony_ci if (!priv) 2288c2ecf20Sopenharmony_ci return -ENOMEM; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2318c2ecf20Sopenharmony_ci if (!r) 2328c2ecf20Sopenharmony_ci return -EINVAL; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* Just ioremap, as this MDIO block is usually integrated into an 2358c2ecf20Sopenharmony_ci * Ethernet MAC controller register range 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); 2388c2ecf20Sopenharmony_ci if (!priv->base) { 2398c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to remap register\n"); 2408c2ecf20Sopenharmony_ci return -ENOMEM; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci priv->clk = devm_clk_get_optional(&pdev->dev, NULL); 2448c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk)) 2458c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 2488c2ecf20Sopenharmony_ci if (ret) 2498c2ecf20Sopenharmony_ci return ret; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq)) 2528c2ecf20Sopenharmony_ci priv->clk_freq = 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci unimac_mdio_clk_set(priv); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci priv->mii_bus = mdiobus_alloc(); 2578c2ecf20Sopenharmony_ci if (!priv->mii_bus) { 2588c2ecf20Sopenharmony_ci ret = -ENOMEM; 2598c2ecf20Sopenharmony_ci goto out_clk_disable; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci bus = priv->mii_bus; 2638c2ecf20Sopenharmony_ci bus->priv = priv; 2648c2ecf20Sopenharmony_ci if (pdata) { 2658c2ecf20Sopenharmony_ci bus->name = pdata->bus_name; 2668c2ecf20Sopenharmony_ci priv->wait_func = pdata->wait_func; 2678c2ecf20Sopenharmony_ci priv->wait_func_data = pdata->wait_func_data; 2688c2ecf20Sopenharmony_ci bus->phy_mask = ~pdata->phy_mask; 2698c2ecf20Sopenharmony_ci } else { 2708c2ecf20Sopenharmony_ci bus->name = "unimac MII bus"; 2718c2ecf20Sopenharmony_ci priv->wait_func_data = priv; 2728c2ecf20Sopenharmony_ci priv->wait_func = unimac_mdio_poll; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci bus->parent = &pdev->dev; 2758c2ecf20Sopenharmony_ci bus->read = unimac_mdio_read; 2768c2ecf20Sopenharmony_ci bus->write = unimac_mdio_write; 2778c2ecf20Sopenharmony_ci bus->reset = unimac_mdio_reset; 2788c2ecf20Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = of_mdiobus_register(bus, np); 2818c2ecf20Sopenharmony_ci if (ret) { 2828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "MDIO bus registration failed\n"); 2838c2ecf20Sopenharmony_ci goto out_mdio_free; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Broadcom UniMAC MDIO bus\n"); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ciout_mdio_free: 2938c2ecf20Sopenharmony_ci mdiobus_free(bus); 2948c2ecf20Sopenharmony_ciout_clk_disable: 2958c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 2968c2ecf20Sopenharmony_ci return ret; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int unimac_mdio_remove(struct platform_device *pdev) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct unimac_mdio_priv *priv = platform_get_drvdata(pdev); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci mdiobus_unregister(priv->mii_bus); 3048c2ecf20Sopenharmony_ci mdiobus_free(priv->mii_bus); 3058c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int __maybe_unused unimac_mdio_suspend(struct device *d) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct unimac_mdio_priv *priv = dev_get_drvdata(d); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int __maybe_unused unimac_mdio_resume(struct device *d) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct unimac_mdio_priv *priv = dev_get_drvdata(d); 3228c2ecf20Sopenharmony_ci int ret; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 3258c2ecf20Sopenharmony_ci if (ret) 3268c2ecf20Sopenharmony_ci return ret; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci unimac_mdio_clk_set(priv); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return 0; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops, 3348c2ecf20Sopenharmony_ci unimac_mdio_suspend, unimac_mdio_resume); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic const struct of_device_id unimac_mdio_ids[] = { 3378c2ecf20Sopenharmony_ci { .compatible = "brcm,genet-mdio-v5", }, 3388c2ecf20Sopenharmony_ci { .compatible = "brcm,genet-mdio-v4", }, 3398c2ecf20Sopenharmony_ci { .compatible = "brcm,genet-mdio-v3", }, 3408c2ecf20Sopenharmony_ci { .compatible = "brcm,genet-mdio-v2", }, 3418c2ecf20Sopenharmony_ci { .compatible = "brcm,genet-mdio-v1", }, 3428c2ecf20Sopenharmony_ci { .compatible = "brcm,unimac-mdio", }, 3438c2ecf20Sopenharmony_ci { /* sentinel */ }, 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, unimac_mdio_ids); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic struct platform_driver unimac_mdio_driver = { 3488c2ecf20Sopenharmony_ci .driver = { 3498c2ecf20Sopenharmony_ci .name = UNIMAC_MDIO_DRV_NAME, 3508c2ecf20Sopenharmony_ci .of_match_table = unimac_mdio_ids, 3518c2ecf20Sopenharmony_ci .pm = &unimac_mdio_pm_ops, 3528c2ecf20Sopenharmony_ci }, 3538c2ecf20Sopenharmony_ci .probe = unimac_mdio_probe, 3548c2ecf20Sopenharmony_ci .remove = unimac_mdio_remove, 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_cimodule_platform_driver(unimac_mdio_driver); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Broadcom Corporation"); 3598c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller"); 3608c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3618c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" UNIMAC_MDIO_DRV_NAME); 362