root/drivers/net/phy/mdio-hisi-femac.c

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

DEFINITIONS

This source file includes following definitions.
  1. hisi_femac_mdio_wait_ready
  2. hisi_femac_mdio_read
  3. hisi_femac_mdio_write
  4. hisi_femac_mdio_probe
  5. hisi_femac_mdio_remove

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Hisilicon Fast Ethernet MDIO Bus Driver
   4  *
   5  * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/iopoll.h>
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/of_address.h>
  13 #include <linux/of_mdio.h>
  14 #include <linux/platform_device.h>
  15 
  16 #define MDIO_RWCTRL             0x00
  17 #define MDIO_RO_DATA            0x04
  18 #define MDIO_WRITE              BIT(13)
  19 #define MDIO_RW_FINISH          BIT(15)
  20 #define BIT_PHY_ADDR_OFFSET     8
  21 #define BIT_WR_DATA_OFFSET      16
  22 
  23 struct hisi_femac_mdio_data {
  24         struct clk *clk;
  25         void __iomem *membase;
  26 };
  27 
  28 static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data)
  29 {
  30         u32 val;
  31 
  32         return readl_poll_timeout(data->membase + MDIO_RWCTRL,
  33                                   val, val & MDIO_RW_FINISH, 20, 10000);
  34 }
  35 
  36 static int hisi_femac_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
  37 {
  38         struct hisi_femac_mdio_data *data = bus->priv;
  39         int ret;
  40 
  41         ret = hisi_femac_mdio_wait_ready(data);
  42         if (ret)
  43                 return ret;
  44 
  45         writel((mii_id << BIT_PHY_ADDR_OFFSET) | regnum,
  46                data->membase + MDIO_RWCTRL);
  47 
  48         ret = hisi_femac_mdio_wait_ready(data);
  49         if (ret)
  50                 return ret;
  51 
  52         return readl(data->membase + MDIO_RO_DATA) & 0xFFFF;
  53 }
  54 
  55 static int hisi_femac_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
  56                                  u16 value)
  57 {
  58         struct hisi_femac_mdio_data *data = bus->priv;
  59         int ret;
  60 
  61         ret = hisi_femac_mdio_wait_ready(data);
  62         if (ret)
  63                 return ret;
  64 
  65         writel(MDIO_WRITE | (value << BIT_WR_DATA_OFFSET) |
  66                (mii_id << BIT_PHY_ADDR_OFFSET) | regnum,
  67                data->membase + MDIO_RWCTRL);
  68 
  69         return hisi_femac_mdio_wait_ready(data);
  70 }
  71 
  72 static int hisi_femac_mdio_probe(struct platform_device *pdev)
  73 {
  74         struct device_node *np = pdev->dev.of_node;
  75         struct mii_bus *bus;
  76         struct hisi_femac_mdio_data *data;
  77         int ret;
  78 
  79         bus = mdiobus_alloc_size(sizeof(*data));
  80         if (!bus)
  81                 return -ENOMEM;
  82 
  83         bus->name = "hisi_femac_mii_bus";
  84         bus->read = &hisi_femac_mdio_read;
  85         bus->write = &hisi_femac_mdio_write;
  86         snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
  87         bus->parent = &pdev->dev;
  88 
  89         data = bus->priv;
  90         data->membase = devm_platform_ioremap_resource(pdev, 0);
  91         if (IS_ERR(data->membase)) {
  92                 ret = PTR_ERR(data->membase);
  93                 goto err_out_free_mdiobus;
  94         }
  95 
  96         data->clk = devm_clk_get(&pdev->dev, NULL);
  97         if (IS_ERR(data->clk)) {
  98                 ret = PTR_ERR(data->clk);
  99                 goto err_out_free_mdiobus;
 100         }
 101 
 102         ret = clk_prepare_enable(data->clk);
 103         if (ret)
 104                 goto err_out_free_mdiobus;
 105 
 106         ret = of_mdiobus_register(bus, np);
 107         if (ret)
 108                 goto err_out_disable_clk;
 109 
 110         platform_set_drvdata(pdev, bus);
 111 
 112         return 0;
 113 
 114 err_out_disable_clk:
 115         clk_disable_unprepare(data->clk);
 116 err_out_free_mdiobus:
 117         mdiobus_free(bus);
 118         return ret;
 119 }
 120 
 121 static int hisi_femac_mdio_remove(struct platform_device *pdev)
 122 {
 123         struct mii_bus *bus = platform_get_drvdata(pdev);
 124         struct hisi_femac_mdio_data *data = bus->priv;
 125 
 126         mdiobus_unregister(bus);
 127         clk_disable_unprepare(data->clk);
 128         mdiobus_free(bus);
 129 
 130         return 0;
 131 }
 132 
 133 static const struct of_device_id hisi_femac_mdio_dt_ids[] = {
 134         { .compatible = "hisilicon,hisi-femac-mdio" },
 135         { }
 136 };
 137 MODULE_DEVICE_TABLE(of, hisi_femac_mdio_dt_ids);
 138 
 139 static struct platform_driver hisi_femac_mdio_driver = {
 140         .probe = hisi_femac_mdio_probe,
 141         .remove = hisi_femac_mdio_remove,
 142         .driver = {
 143                 .name = "hisi-femac-mdio",
 144                 .of_match_table = hisi_femac_mdio_dt_ids,
 145         },
 146 };
 147 
 148 module_platform_driver(hisi_femac_mdio_driver);
 149 
 150 MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC MDIO interface driver");
 151 MODULE_AUTHOR("Dongpo Li <lidongpo@hisilicon.com>");
 152 MODULE_LICENSE("GPL");

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