Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.17-rc2 163 lines 4.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2022 Baylibre, SAS. 3 * Author: Jerome Brunet <jbrunet@baylibre.com> 4 */ 5 6#include <linux/bitfield.h> 7#include <linux/delay.h> 8#include <linux/clk.h> 9#include <linux/io.h> 10#include <linux/mdio-mux.h> 11#include <linux/module.h> 12#include <linux/platform_device.h> 13 14#define ETH_REG2 0x0 15#define REG2_PHYID GENMASK(21, 0) 16#define EPHY_GXL_ID 0x110181 17#define REG2_LEDACT GENMASK(23, 22) 18#define REG2_LEDLINK GENMASK(25, 24) 19#define REG2_DIV4SEL BIT(27) 20#define REG2_REVERSED BIT(28) 21#define REG2_ADCBYPASS BIT(30) 22#define REG2_CLKINSEL BIT(31) 23#define ETH_REG3 0x4 24#define REG3_ENH BIT(3) 25#define REG3_CFGMODE GENMASK(6, 4) 26#define REG3_AUTOMDIX BIT(7) 27#define REG3_PHYADDR GENMASK(12, 8) 28#define REG3_PWRUPRST BIT(21) 29#define REG3_PWRDOWN BIT(22) 30#define REG3_LEDPOL BIT(23) 31#define REG3_PHYMDI BIT(26) 32#define REG3_CLKINEN BIT(29) 33#define REG3_PHYIP BIT(30) 34#define REG3_PHYEN BIT(31) 35#define ETH_REG4 0x8 36#define REG4_PWRUPRSTSIG BIT(0) 37 38#define MESON_GXL_MDIO_EXTERNAL_ID 0 39#define MESON_GXL_MDIO_INTERNAL_ID 1 40 41struct gxl_mdio_mux { 42 void __iomem *regs; 43 void *mux_handle; 44}; 45 46static void gxl_enable_internal_mdio(struct gxl_mdio_mux *priv) 47{ 48 u32 val; 49 50 /* Setup the internal phy */ 51 val = (REG3_ENH | 52 FIELD_PREP(REG3_CFGMODE, 0x7) | 53 REG3_AUTOMDIX | 54 FIELD_PREP(REG3_PHYADDR, 8) | 55 REG3_LEDPOL | 56 REG3_PHYMDI | 57 REG3_CLKINEN | 58 REG3_PHYIP); 59 60 writel(REG4_PWRUPRSTSIG, priv->regs + ETH_REG4); 61 writel(val, priv->regs + ETH_REG3); 62 mdelay(10); 63 64 /* NOTE: The HW kept the phy id configurable at runtime. 65 * The id below is arbitrary. It is the one used in the vendor code. 66 * The only constraint is that it must match the one in 67 * drivers/net/phy/meson-gxl.c to properly match the PHY. 68 */ 69 writel(REG2_REVERSED | FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), 70 priv->regs + ETH_REG2); 71 72 /* Enable the internal phy */ 73 val |= REG3_PHYEN; 74 writel(val, priv->regs + ETH_REG3); 75 writel(0, priv->regs + ETH_REG4); 76 77 /* The phy needs a bit of time to power up */ 78 mdelay(10); 79} 80 81static void gxl_enable_external_mdio(struct gxl_mdio_mux *priv) 82{ 83 /* Reset the mdio bus mux to the external phy */ 84 writel(0, priv->regs + ETH_REG3); 85} 86 87static int gxl_mdio_switch_fn(int current_child, int desired_child, 88 void *data) 89{ 90 struct gxl_mdio_mux *priv = dev_get_drvdata(data); 91 92 if (current_child == desired_child) 93 return 0; 94 95 switch (desired_child) { 96 case MESON_GXL_MDIO_EXTERNAL_ID: 97 gxl_enable_external_mdio(priv); 98 break; 99 case MESON_GXL_MDIO_INTERNAL_ID: 100 gxl_enable_internal_mdio(priv); 101 break; 102 default: 103 return -EINVAL; 104 } 105 106 return 0; 107} 108 109static const struct of_device_id gxl_mdio_mux_match[] = { 110 { .compatible = "amlogic,gxl-mdio-mux", }, 111 {}, 112}; 113MODULE_DEVICE_TABLE(of, gxl_mdio_mux_match); 114 115static int gxl_mdio_mux_probe(struct platform_device *pdev) 116{ 117 struct device *dev = &pdev->dev; 118 struct gxl_mdio_mux *priv; 119 struct clk *rclk; 120 int ret; 121 122 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 123 if (!priv) 124 return -ENOMEM; 125 platform_set_drvdata(pdev, priv); 126 127 priv->regs = devm_platform_ioremap_resource(pdev, 0); 128 if (IS_ERR(priv->regs)) 129 return PTR_ERR(priv->regs); 130 131 rclk = devm_clk_get_enabled(dev, "ref"); 132 if (IS_ERR(rclk)) 133 return dev_err_probe(dev, PTR_ERR(rclk), 134 "failed to get reference clock\n"); 135 136 ret = mdio_mux_init(dev, dev->of_node, gxl_mdio_switch_fn, 137 &priv->mux_handle, dev, NULL); 138 if (ret) 139 dev_err_probe(dev, ret, "mdio multiplexer init failed\n"); 140 141 return ret; 142} 143 144static void gxl_mdio_mux_remove(struct platform_device *pdev) 145{ 146 struct gxl_mdio_mux *priv = platform_get_drvdata(pdev); 147 148 mdio_mux_uninit(priv->mux_handle); 149} 150 151static struct platform_driver gxl_mdio_mux_driver = { 152 .probe = gxl_mdio_mux_probe, 153 .remove = gxl_mdio_mux_remove, 154 .driver = { 155 .name = "gxl-mdio-mux", 156 .of_match_table = gxl_mdio_mux_match, 157 }, 158}; 159module_platform_driver(gxl_mdio_mux_driver); 160 161MODULE_DESCRIPTION("Amlogic GXL MDIO multiplexer driver"); 162MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 163MODULE_LICENSE("GPL");