root/drivers/net/phy/mdio-aspeed.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. aspeed_mdio_read
  2. aspeed_mdio_write
  3. aspeed_mdio_probe
  4. aspeed_mdio_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* Copyright (C) 2019 IBM Corp. */
   3 
   4 #include <linux/bitfield.h>
   5 #include <linux/delay.h>
   6 #include <linux/iopoll.h>
   7 #include <linux/mdio.h>
   8 #include <linux/module.h>
   9 #include <linux/of.h>
  10 #include <linux/of_mdio.h>
  11 #include <linux/phy.h>
  12 #include <linux/platform_device.h>
  13 
  14 #define DRV_NAME "mdio-aspeed"
  15 
  16 #define ASPEED_MDIO_CTRL                0x0
  17 #define   ASPEED_MDIO_CTRL_FIRE         BIT(31)
  18 #define   ASPEED_MDIO_CTRL_ST           BIT(28)
  19 #define     ASPEED_MDIO_CTRL_ST_C45     0
  20 #define     ASPEED_MDIO_CTRL_ST_C22     1
  21 #define   ASPEED_MDIO_CTRL_OP           GENMASK(27, 26)
  22 #define     MDIO_C22_OP_WRITE           0b01
  23 #define     MDIO_C22_OP_READ            0b10
  24 #define   ASPEED_MDIO_CTRL_PHYAD        GENMASK(25, 21)
  25 #define   ASPEED_MDIO_CTRL_REGAD        GENMASK(20, 16)
  26 #define   ASPEED_MDIO_CTRL_MIIWDATA     GENMASK(15, 0)
  27 
  28 #define ASPEED_MDIO_DATA                0x4
  29 #define   ASPEED_MDIO_DATA_MDC_THRES    GENMASK(31, 24)
  30 #define   ASPEED_MDIO_DATA_MDIO_EDGE    BIT(23)
  31 #define   ASPEED_MDIO_DATA_MDIO_LATCH   GENMASK(22, 20)
  32 #define   ASPEED_MDIO_DATA_IDLE         BIT(16)
  33 #define   ASPEED_MDIO_DATA_MIIRDATA     GENMASK(15, 0)
  34 
  35 #define ASPEED_MDIO_INTERVAL_US         100
  36 #define ASPEED_MDIO_TIMEOUT_US          (ASPEED_MDIO_INTERVAL_US * 10)
  37 
  38 struct aspeed_mdio {
  39         void __iomem *base;
  40 };
  41 
  42 static int aspeed_mdio_read(struct mii_bus *bus, int addr, int regnum)
  43 {
  44         struct aspeed_mdio *ctx = bus->priv;
  45         u32 ctrl;
  46         u32 data;
  47         int rc;
  48 
  49         dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d\n", __func__, addr,
  50                 regnum);
  51 
  52         /* Just clause 22 for the moment */
  53         if (regnum & MII_ADDR_C45)
  54                 return -EOPNOTSUPP;
  55 
  56         ctrl = ASPEED_MDIO_CTRL_FIRE
  57                 | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
  58                 | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_READ)
  59                 | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
  60                 | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regnum);
  61 
  62         iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
  63 
  64         rc = readl_poll_timeout(ctx->base + ASPEED_MDIO_DATA, data,
  65                                 data & ASPEED_MDIO_DATA_IDLE,
  66                                 ASPEED_MDIO_INTERVAL_US,
  67                                 ASPEED_MDIO_TIMEOUT_US);
  68         if (rc < 0)
  69                 return rc;
  70 
  71         return FIELD_GET(ASPEED_MDIO_DATA_MIIRDATA, data);
  72 }
  73 
  74 static int aspeed_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
  75 {
  76         struct aspeed_mdio *ctx = bus->priv;
  77         u32 ctrl;
  78 
  79         dev_dbg(&bus->dev, "%s: addr: %d, regnum: %d, val: 0x%x\n",
  80                 __func__, addr, regnum, val);
  81 
  82         /* Just clause 22 for the moment */
  83         if (regnum & MII_ADDR_C45)
  84                 return -EOPNOTSUPP;
  85 
  86         ctrl = ASPEED_MDIO_CTRL_FIRE
  87                 | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
  88                 | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_WRITE)
  89                 | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
  90                 | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, regnum)
  91                 | FIELD_PREP(ASPEED_MDIO_CTRL_MIIWDATA, val);
  92 
  93         iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL);
  94 
  95         return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl,
  96                                   !(ctrl & ASPEED_MDIO_CTRL_FIRE),
  97                                   ASPEED_MDIO_INTERVAL_US,
  98                                   ASPEED_MDIO_TIMEOUT_US);
  99 }
 100 
 101 static int aspeed_mdio_probe(struct platform_device *pdev)
 102 {
 103         struct aspeed_mdio *ctx;
 104         struct mii_bus *bus;
 105         int rc;
 106 
 107         bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*ctx));
 108         if (!bus)
 109                 return -ENOMEM;
 110 
 111         ctx = bus->priv;
 112         ctx->base = devm_platform_ioremap_resource(pdev, 0);
 113         if (IS_ERR(ctx->base))
 114                 return PTR_ERR(ctx->base);
 115 
 116         bus->name = DRV_NAME;
 117         snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
 118         bus->parent = &pdev->dev;
 119         bus->read = aspeed_mdio_read;
 120         bus->write = aspeed_mdio_write;
 121 
 122         rc = of_mdiobus_register(bus, pdev->dev.of_node);
 123         if (rc) {
 124                 dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
 125                 return rc;
 126         }
 127 
 128         platform_set_drvdata(pdev, bus);
 129 
 130         return 0;
 131 }
 132 
 133 static int aspeed_mdio_remove(struct platform_device *pdev)
 134 {
 135         mdiobus_unregister(platform_get_drvdata(pdev));
 136 
 137         return 0;
 138 }
 139 
 140 static const struct of_device_id aspeed_mdio_of_match[] = {
 141         { .compatible = "aspeed,ast2600-mdio", },
 142         { },
 143 };
 144 
 145 static struct platform_driver aspeed_mdio_driver = {
 146         .driver = {
 147                 .name = DRV_NAME,
 148                 .of_match_table = aspeed_mdio_of_match,
 149         },
 150         .probe = aspeed_mdio_probe,
 151         .remove = aspeed_mdio_remove,
 152 };
 153 
 154 module_platform_driver(aspeed_mdio_driver);
 155 
 156 MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
 157 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */