root/drivers/net/phy/mdio-mux-bcm-iproc.c

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

DEFINITIONS

This source file includes following definitions.
  1. mdio_mux_iproc_config
  2. iproc_mdio_wait_for_idle
  3. start_miim_ops
  4. iproc_mdiomux_read
  5. iproc_mdiomux_write
  6. mdio_mux_iproc_switch_fn
  7. mdio_mux_iproc_probe
  8. mdio_mux_iproc_remove
  9. mdio_mux_iproc_suspend
  10. mdio_mux_iproc_resume

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright 2016 Broadcom
   4  */
   5 #include <linux/clk.h>
   6 #include <linux/platform_device.h>
   7 #include <linux/device.h>
   8 #include <linux/of_mdio.h>
   9 #include <linux/module.h>
  10 #include <linux/phy.h>
  11 #include <linux/mdio-mux.h>
  12 #include <linux/delay.h>
  13 
  14 #define MDIO_RATE_ADJ_EXT_OFFSET        0x000
  15 #define MDIO_RATE_ADJ_INT_OFFSET        0x004
  16 #define MDIO_RATE_ADJ_DIVIDENT_SHIFT    16
  17 
  18 #define MDIO_SCAN_CTRL_OFFSET           0x008
  19 #define MDIO_SCAN_CTRL_OVRIDE_EXT_MSTR  28
  20 
  21 #define MDIO_PARAM_OFFSET               0x23c
  22 #define MDIO_PARAM_MIIM_CYCLE           29
  23 #define MDIO_PARAM_INTERNAL_SEL         25
  24 #define MDIO_PARAM_BUS_ID               22
  25 #define MDIO_PARAM_C45_SEL              21
  26 #define MDIO_PARAM_PHY_ID               16
  27 #define MDIO_PARAM_PHY_DATA             0
  28 
  29 #define MDIO_READ_OFFSET                0x240
  30 #define MDIO_READ_DATA_MASK             0xffff
  31 #define MDIO_ADDR_OFFSET                0x244
  32 
  33 #define MDIO_CTRL_OFFSET                0x248
  34 #define MDIO_CTRL_WRITE_OP              0x1
  35 #define MDIO_CTRL_READ_OP               0x2
  36 
  37 #define MDIO_STAT_OFFSET                0x24c
  38 #define MDIO_STAT_DONE                  1
  39 
  40 #define BUS_MAX_ADDR                    32
  41 #define EXT_BUS_START_ADDR              16
  42 
  43 #define MDIO_REG_ADDR_SPACE_SIZE        0x250
  44 
  45 #define MDIO_OPERATING_FREQUENCY        11000000
  46 #define MDIO_RATE_ADJ_DIVIDENT          1
  47 
  48 struct iproc_mdiomux_desc {
  49         void *mux_handle;
  50         void __iomem *base;
  51         struct device *dev;
  52         struct mii_bus *mii_bus;
  53         struct clk *core_clk;
  54 };
  55 
  56 static void mdio_mux_iproc_config(struct iproc_mdiomux_desc *md)
  57 {
  58         u32 divisor;
  59         u32 val;
  60 
  61         /* Disable external mdio master access */
  62         val = readl(md->base + MDIO_SCAN_CTRL_OFFSET);
  63         val |= BIT(MDIO_SCAN_CTRL_OVRIDE_EXT_MSTR);
  64         writel(val, md->base + MDIO_SCAN_CTRL_OFFSET);
  65 
  66         if (md->core_clk) {
  67                 /* use rate adjust regs to derrive the mdio's operating
  68                  * frequency from the specified core clock
  69                  */
  70                 divisor = clk_get_rate(md->core_clk) / MDIO_OPERATING_FREQUENCY;
  71                 divisor = divisor / (MDIO_RATE_ADJ_DIVIDENT + 1);
  72                 val = divisor;
  73                 val |= MDIO_RATE_ADJ_DIVIDENT << MDIO_RATE_ADJ_DIVIDENT_SHIFT;
  74                 writel(val, md->base + MDIO_RATE_ADJ_EXT_OFFSET);
  75                 writel(val, md->base + MDIO_RATE_ADJ_INT_OFFSET);
  76         }
  77 }
  78 
  79 static int iproc_mdio_wait_for_idle(void __iomem *base, bool result)
  80 {
  81         unsigned int timeout = 1000; /* loop for 1s */
  82         u32 val;
  83 
  84         do {
  85                 val = readl(base + MDIO_STAT_OFFSET);
  86                 if ((val & MDIO_STAT_DONE) == result)
  87                         return 0;
  88 
  89                 usleep_range(1000, 2000);
  90         } while (timeout--);
  91 
  92         return -ETIMEDOUT;
  93 }
  94 
  95 /* start_miim_ops- Program and start MDIO transaction over mdio bus.
  96  * @base: Base address
  97  * @phyid: phyid of the selected bus.
  98  * @reg: register offset to be read/written.
  99  * @val :0 if read op else value to be written in @reg;
 100  * @op: Operation that need to be carried out.
 101  *      MDIO_CTRL_READ_OP: Read transaction.
 102  *      MDIO_CTRL_WRITE_OP: Write transaction.
 103  *
 104  * Return value: Successful Read operation returns read reg values and write
 105  *      operation returns 0. Failure operation returns negative error code.
 106  */
 107 static int start_miim_ops(void __iomem *base,
 108                           u16 phyid, u32 reg, u16 val, u32 op)
 109 {
 110         u32 param;
 111         int ret;
 112 
 113         writel(0, base + MDIO_CTRL_OFFSET);
 114         ret = iproc_mdio_wait_for_idle(base, 0);
 115         if (ret)
 116                 goto err;
 117 
 118         param = readl(base + MDIO_PARAM_OFFSET);
 119         param |= phyid << MDIO_PARAM_PHY_ID;
 120         param |= val << MDIO_PARAM_PHY_DATA;
 121         if (reg & MII_ADDR_C45)
 122                 param |= BIT(MDIO_PARAM_C45_SEL);
 123 
 124         writel(param, base + MDIO_PARAM_OFFSET);
 125 
 126         writel(reg, base + MDIO_ADDR_OFFSET);
 127 
 128         writel(op, base + MDIO_CTRL_OFFSET);
 129 
 130         ret = iproc_mdio_wait_for_idle(base, 1);
 131         if (ret)
 132                 goto err;
 133 
 134         if (op == MDIO_CTRL_READ_OP)
 135                 ret = readl(base + MDIO_READ_OFFSET) & MDIO_READ_DATA_MASK;
 136 err:
 137         return ret;
 138 }
 139 
 140 static int iproc_mdiomux_read(struct mii_bus *bus, int phyid, int reg)
 141 {
 142         struct iproc_mdiomux_desc *md = bus->priv;
 143         int ret;
 144 
 145         ret = start_miim_ops(md->base, phyid, reg, 0, MDIO_CTRL_READ_OP);
 146         if (ret < 0)
 147                 dev_err(&bus->dev, "mdiomux read operation failed!!!");
 148 
 149         return ret;
 150 }
 151 
 152 static int iproc_mdiomux_write(struct mii_bus *bus,
 153                                int phyid, int reg, u16 val)
 154 {
 155         struct iproc_mdiomux_desc *md = bus->priv;
 156         int ret;
 157 
 158         /* Write val at reg offset */
 159         ret = start_miim_ops(md->base, phyid, reg, val, MDIO_CTRL_WRITE_OP);
 160         if (ret < 0)
 161                 dev_err(&bus->dev, "mdiomux write operation failed!!!");
 162 
 163         return ret;
 164 }
 165 
 166 static int mdio_mux_iproc_switch_fn(int current_child, int desired_child,
 167                                     void *data)
 168 {
 169         struct iproc_mdiomux_desc *md = data;
 170         u32 param, bus_id;
 171         bool bus_dir;
 172 
 173         /* select bus and its properties */
 174         bus_dir = (desired_child < EXT_BUS_START_ADDR);
 175         bus_id = bus_dir ? desired_child : (desired_child - EXT_BUS_START_ADDR);
 176 
 177         param = (bus_dir ? 1 : 0) << MDIO_PARAM_INTERNAL_SEL;
 178         param |= (bus_id << MDIO_PARAM_BUS_ID);
 179 
 180         writel(param, md->base + MDIO_PARAM_OFFSET);
 181         return 0;
 182 }
 183 
 184 static int mdio_mux_iproc_probe(struct platform_device *pdev)
 185 {
 186         struct iproc_mdiomux_desc *md;
 187         struct mii_bus *bus;
 188         struct resource *res;
 189         int rc;
 190 
 191         md = devm_kzalloc(&pdev->dev, sizeof(*md), GFP_KERNEL);
 192         if (!md)
 193                 return -ENOMEM;
 194         md->dev = &pdev->dev;
 195 
 196         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 197         if (res->start & 0xfff) {
 198                 /* For backward compatibility in case the
 199                  * base address is specified with an offset.
 200                  */
 201                 dev_info(&pdev->dev, "fix base address in dt-blob\n");
 202                 res->start &= ~0xfff;
 203                 res->end = res->start + MDIO_REG_ADDR_SPACE_SIZE - 1;
 204         }
 205         md->base = devm_ioremap_resource(&pdev->dev, res);
 206         if (IS_ERR(md->base)) {
 207                 dev_err(&pdev->dev, "failed to ioremap register\n");
 208                 return PTR_ERR(md->base);
 209         }
 210 
 211         md->mii_bus = devm_mdiobus_alloc(&pdev->dev);
 212         if (!md->mii_bus) {
 213                 dev_err(&pdev->dev, "mdiomux bus alloc failed\n");
 214                 return -ENOMEM;
 215         }
 216 
 217         md->core_clk = devm_clk_get(&pdev->dev, NULL);
 218         if (md->core_clk == ERR_PTR(-ENOENT) ||
 219             md->core_clk == ERR_PTR(-EINVAL))
 220                 md->core_clk = NULL;
 221         else if (IS_ERR(md->core_clk))
 222                 return PTR_ERR(md->core_clk);
 223 
 224         rc = clk_prepare_enable(md->core_clk);
 225         if (rc) {
 226                 dev_err(&pdev->dev, "failed to enable core clk\n");
 227                 return rc;
 228         }
 229 
 230         bus = md->mii_bus;
 231         bus->priv = md;
 232         bus->name = "iProc MDIO mux bus";
 233         snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
 234         bus->parent = &pdev->dev;
 235         bus->read = iproc_mdiomux_read;
 236         bus->write = iproc_mdiomux_write;
 237 
 238         bus->phy_mask = ~0;
 239         bus->dev.of_node = pdev->dev.of_node;
 240         rc = mdiobus_register(bus);
 241         if (rc) {
 242                 dev_err(&pdev->dev, "mdiomux registration failed\n");
 243                 goto out_clk;
 244         }
 245 
 246         platform_set_drvdata(pdev, md);
 247 
 248         rc = mdio_mux_init(md->dev, md->dev->of_node, mdio_mux_iproc_switch_fn,
 249                            &md->mux_handle, md, md->mii_bus);
 250         if (rc) {
 251                 dev_info(md->dev, "mdiomux initialization failed\n");
 252                 goto out_register;
 253         }
 254 
 255         mdio_mux_iproc_config(md);
 256 
 257         dev_info(md->dev, "iProc mdiomux registered\n");
 258         return 0;
 259 
 260 out_register:
 261         mdiobus_unregister(bus);
 262 out_clk:
 263         clk_disable_unprepare(md->core_clk);
 264         return rc;
 265 }
 266 
 267 static int mdio_mux_iproc_remove(struct platform_device *pdev)
 268 {
 269         struct iproc_mdiomux_desc *md = platform_get_drvdata(pdev);
 270 
 271         mdio_mux_uninit(md->mux_handle);
 272         mdiobus_unregister(md->mii_bus);
 273         clk_disable_unprepare(md->core_clk);
 274 
 275         return 0;
 276 }
 277 
 278 #ifdef CONFIG_PM_SLEEP
 279 static int mdio_mux_iproc_suspend(struct device *dev)
 280 {
 281         struct iproc_mdiomux_desc *md = dev_get_drvdata(dev);
 282 
 283         clk_disable_unprepare(md->core_clk);
 284 
 285         return 0;
 286 }
 287 
 288 static int mdio_mux_iproc_resume(struct device *dev)
 289 {
 290         struct iproc_mdiomux_desc *md = dev_get_drvdata(dev);
 291         int rc;
 292 
 293         rc = clk_prepare_enable(md->core_clk);
 294         if (rc) {
 295                 dev_err(md->dev, "failed to enable core clk\n");
 296                 return rc;
 297         }
 298         mdio_mux_iproc_config(md);
 299 
 300         return 0;
 301 }
 302 #endif
 303 
 304 static SIMPLE_DEV_PM_OPS(mdio_mux_iproc_pm_ops,
 305                          mdio_mux_iproc_suspend, mdio_mux_iproc_resume);
 306 
 307 static const struct of_device_id mdio_mux_iproc_match[] = {
 308         {
 309                 .compatible = "brcm,mdio-mux-iproc",
 310         },
 311         {},
 312 };
 313 MODULE_DEVICE_TABLE(of, mdio_mux_iproc_match);
 314 
 315 static struct platform_driver mdiomux_iproc_driver = {
 316         .driver = {
 317                 .name           = "mdio-mux-iproc",
 318                 .of_match_table = mdio_mux_iproc_match,
 319                 .pm             = &mdio_mux_iproc_pm_ops,
 320         },
 321         .probe          = mdio_mux_iproc_probe,
 322         .remove         = mdio_mux_iproc_remove,
 323 };
 324 
 325 module_platform_driver(mdiomux_iproc_driver);
 326 
 327 MODULE_DESCRIPTION("iProc MDIO Mux Bus Driver");
 328 MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>");
 329 MODULE_LICENSE("GPL v2");

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