1/* 2 * Fixed MDIO bus (MDIO bus emulation with fixed PHYs) 3 * 4 * Author: Vitaly Bordug <vbordug@ru.mvista.com> 5 * Anton Vorontsov <avorontsov@ru.mvista.com> 6 * 7 * Copyright (c) 2006-2007 MontaVista Software, Inc. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 15#include <linux/kernel.h> 16#include <linux/module.h> 17#include <linux/platform_device.h> 18#include <linux/list.h> 19#include <linux/mii.h> 20#include <linux/phy.h> 21#include <linux/phy_fixed.h> 22#include <linux/err.h> 23#include <linux/slab.h> 24#include <linux/of.h> 25#include <linux/gpio.h> 26 27#define MII_REGS_NUM 29 28 29struct fixed_mdio_bus { 30 int irqs[PHY_MAX_ADDR]; 31 struct mii_bus *mii_bus; 32 struct list_head phys; 33}; 34 35struct fixed_phy { 36 int addr; 37 u16 regs[MII_REGS_NUM]; 38 struct phy_device *phydev; 39 struct fixed_phy_status status; 40 int (*link_update)(struct net_device *, struct fixed_phy_status *); 41 struct list_head node; 42 int link_gpio; 43}; 44 45static struct platform_device *pdev; 46static struct fixed_mdio_bus platform_fmb = { 47 .phys = LIST_HEAD_INIT(platform_fmb.phys), 48}; 49 50static int fixed_phy_update_regs(struct fixed_phy *fp) 51{ 52 u16 bmsr = BMSR_ANEGCAPABLE; 53 u16 bmcr = 0; 54 u16 lpagb = 0; 55 u16 lpa = 0; 56 57 if (gpio_is_valid(fp->link_gpio)) 58 fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio); 59 60 if (fp->status.duplex) { 61 switch (fp->status.speed) { 62 case 1000: 63 bmsr |= BMSR_ESTATEN; 64 break; 65 case 100: 66 bmsr |= BMSR_100FULL; 67 break; 68 case 10: 69 bmsr |= BMSR_10FULL; 70 break; 71 default: 72 break; 73 } 74 } else { 75 switch (fp->status.speed) { 76 case 1000: 77 bmsr |= BMSR_ESTATEN; 78 break; 79 case 100: 80 bmsr |= BMSR_100HALF; 81 break; 82 case 10: 83 bmsr |= BMSR_10HALF; 84 break; 85 default: 86 break; 87 } 88 } 89 90 if (fp->status.link) { 91 bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; 92 93 if (fp->status.duplex) { 94 bmcr |= BMCR_FULLDPLX; 95 96 switch (fp->status.speed) { 97 case 1000: 98 bmcr |= BMCR_SPEED1000; 99 lpagb |= LPA_1000FULL; 100 break; 101 case 100: 102 bmcr |= BMCR_SPEED100; 103 lpa |= LPA_100FULL; 104 break; 105 case 10: 106 lpa |= LPA_10FULL; 107 break; 108 default: 109 pr_warn("fixed phy: unknown speed\n"); 110 return -EINVAL; 111 } 112 } else { 113 switch (fp->status.speed) { 114 case 1000: 115 bmcr |= BMCR_SPEED1000; 116 lpagb |= LPA_1000HALF; 117 break; 118 case 100: 119 bmcr |= BMCR_SPEED100; 120 lpa |= LPA_100HALF; 121 break; 122 case 10: 123 lpa |= LPA_10HALF; 124 break; 125 default: 126 pr_warn("fixed phy: unknown speed\n"); 127 return -EINVAL; 128 } 129 } 130 131 if (fp->status.pause) 132 lpa |= LPA_PAUSE_CAP; 133 134 if (fp->status.asym_pause) 135 lpa |= LPA_PAUSE_ASYM; 136 } 137 138 fp->regs[MII_PHYSID1] = 0; 139 fp->regs[MII_PHYSID2] = 0; 140 141 fp->regs[MII_BMSR] = bmsr; 142 fp->regs[MII_BMCR] = bmcr; 143 fp->regs[MII_LPA] = lpa; 144 fp->regs[MII_STAT1000] = lpagb; 145 146 return 0; 147} 148 149static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num) 150{ 151 struct fixed_mdio_bus *fmb = bus->priv; 152 struct fixed_phy *fp; 153 154 if (reg_num >= MII_REGS_NUM) 155 return -1; 156 157 /* We do not support emulating Clause 45 over Clause 22 register reads 158 * return an error instead of bogus data. 159 */ 160 switch (reg_num) { 161 case MII_MMD_CTRL: 162 case MII_MMD_DATA: 163 return -1; 164 default: 165 break; 166 } 167 168 list_for_each_entry(fp, &fmb->phys, node) { 169 if (fp->addr == phy_addr) { 170 /* Issue callback if user registered it. */ 171 if (fp->link_update) { 172 fp->link_update(fp->phydev->attached_dev, 173 &fp->status); 174 fixed_phy_update_regs(fp); 175 } 176 return fp->regs[reg_num]; 177 } 178 } 179 180 return 0xFFFF; 181} 182 183static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num, 184 u16 val) 185{ 186 return 0; 187} 188 189/* 190 * If something weird is required to be done with link/speed, 191 * network driver is able to assign a function to implement this. 192 * May be useful for PHY's that need to be software-driven. 193 */ 194int fixed_phy_set_link_update(struct phy_device *phydev, 195 int (*link_update)(struct net_device *, 196 struct fixed_phy_status *)) 197{ 198 struct fixed_mdio_bus *fmb = &platform_fmb; 199 struct fixed_phy *fp; 200 201 if (!phydev || !phydev->bus) 202 return -EINVAL; 203 204 list_for_each_entry(fp, &fmb->phys, node) { 205 if (fp->addr == phydev->addr) { 206 fp->link_update = link_update; 207 fp->phydev = phydev; 208 return 0; 209 } 210 } 211 212 return -ENOENT; 213} 214EXPORT_SYMBOL_GPL(fixed_phy_set_link_update); 215 216int fixed_phy_update_state(struct phy_device *phydev, 217 const struct fixed_phy_status *status, 218 const struct fixed_phy_status *changed) 219{ 220 struct fixed_mdio_bus *fmb = &platform_fmb; 221 struct fixed_phy *fp; 222 223 if (!phydev || phydev->bus != fmb->mii_bus) 224 return -EINVAL; 225 226 list_for_each_entry(fp, &fmb->phys, node) { 227 if (fp->addr == phydev->addr) { 228#define _UPD(x) if (changed->x) \ 229 fp->status.x = status->x 230 _UPD(link); 231 _UPD(speed); 232 _UPD(duplex); 233 _UPD(pause); 234 _UPD(asym_pause); 235#undef _UPD 236 fixed_phy_update_regs(fp); 237 return 0; 238 } 239 } 240 241 return -ENOENT; 242} 243EXPORT_SYMBOL(fixed_phy_update_state); 244 245int fixed_phy_add(unsigned int irq, int phy_addr, 246 struct fixed_phy_status *status, 247 int link_gpio) 248{ 249 int ret; 250 struct fixed_mdio_bus *fmb = &platform_fmb; 251 struct fixed_phy *fp; 252 253 fp = kzalloc(sizeof(*fp), GFP_KERNEL); 254 if (!fp) 255 return -ENOMEM; 256 257 memset(fp->regs, 0xFF, sizeof(fp->regs[0]) * MII_REGS_NUM); 258 259 fmb->irqs[phy_addr] = irq; 260 261 fp->addr = phy_addr; 262 fp->status = *status; 263 fp->link_gpio = link_gpio; 264 265 if (gpio_is_valid(fp->link_gpio)) { 266 ret = gpio_request_one(fp->link_gpio, GPIOF_DIR_IN, 267 "fixed-link-gpio-link"); 268 if (ret) 269 goto err_regs; 270 } 271 272 ret = fixed_phy_update_regs(fp); 273 if (ret) 274 goto err_gpio; 275 276 list_add_tail(&fp->node, &fmb->phys); 277 278 return 0; 279 280err_gpio: 281 if (gpio_is_valid(fp->link_gpio)) 282 gpio_free(fp->link_gpio); 283err_regs: 284 kfree(fp); 285 return ret; 286} 287EXPORT_SYMBOL_GPL(fixed_phy_add); 288 289void fixed_phy_del(int phy_addr) 290{ 291 struct fixed_mdio_bus *fmb = &platform_fmb; 292 struct fixed_phy *fp, *tmp; 293 294 list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { 295 if (fp->addr == phy_addr) { 296 list_del(&fp->node); 297 if (gpio_is_valid(fp->link_gpio)) 298 gpio_free(fp->link_gpio); 299 kfree(fp); 300 return; 301 } 302 } 303} 304EXPORT_SYMBOL_GPL(fixed_phy_del); 305 306static int phy_fixed_addr; 307static DEFINE_SPINLOCK(phy_fixed_addr_lock); 308 309struct phy_device *fixed_phy_register(unsigned int irq, 310 struct fixed_phy_status *status, 311 int link_gpio, 312 struct device_node *np) 313{ 314 struct fixed_mdio_bus *fmb = &platform_fmb; 315 struct phy_device *phy; 316 int phy_addr; 317 int ret; 318 319 /* Get the next available PHY address, up to PHY_MAX_ADDR */ 320 spin_lock(&phy_fixed_addr_lock); 321 if (phy_fixed_addr == PHY_MAX_ADDR) { 322 spin_unlock(&phy_fixed_addr_lock); 323 return ERR_PTR(-ENOSPC); 324 } 325 phy_addr = phy_fixed_addr++; 326 spin_unlock(&phy_fixed_addr_lock); 327 328 ret = fixed_phy_add(irq, phy_addr, status, link_gpio); 329 if (ret < 0) 330 return ERR_PTR(ret); 331 332 phy = get_phy_device(fmb->mii_bus, phy_addr, false); 333 if (!phy || IS_ERR(phy)) { 334 fixed_phy_del(phy_addr); 335 return ERR_PTR(-EINVAL); 336 } 337 338 /* propagate the fixed link values to struct phy_device */ 339 phy->link = status->link; 340 if (status->link) { 341 phy->speed = status->speed; 342 phy->duplex = status->duplex; 343 phy->pause = status->pause; 344 phy->asym_pause = status->asym_pause; 345 } 346 347 of_node_get(np); 348 phy->dev.of_node = np; 349 phy->is_pseudo_fixed_link = true; 350 351 switch (status->speed) { 352 case SPEED_1000: 353 phy->supported = PHY_1000BT_FEATURES; 354 break; 355 case SPEED_100: 356 phy->supported = PHY_100BT_FEATURES; 357 break; 358 case SPEED_10: 359 default: 360 phy->supported = PHY_10BT_FEATURES; 361 } 362 363 ret = phy_device_register(phy); 364 if (ret) { 365 phy_device_free(phy); 366 of_node_put(np); 367 fixed_phy_del(phy_addr); 368 return ERR_PTR(ret); 369 } 370 371 return phy; 372} 373EXPORT_SYMBOL_GPL(fixed_phy_register); 374 375static int __init fixed_mdio_bus_init(void) 376{ 377 struct fixed_mdio_bus *fmb = &platform_fmb; 378 int ret; 379 380 pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0); 381 if (IS_ERR(pdev)) { 382 ret = PTR_ERR(pdev); 383 goto err_pdev; 384 } 385 386 fmb->mii_bus = mdiobus_alloc(); 387 if (fmb->mii_bus == NULL) { 388 ret = -ENOMEM; 389 goto err_mdiobus_reg; 390 } 391 392 snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0"); 393 fmb->mii_bus->name = "Fixed MDIO Bus"; 394 fmb->mii_bus->priv = fmb; 395 fmb->mii_bus->parent = &pdev->dev; 396 fmb->mii_bus->read = &fixed_mdio_read; 397 fmb->mii_bus->write = &fixed_mdio_write; 398 fmb->mii_bus->irq = fmb->irqs; 399 400 ret = mdiobus_register(fmb->mii_bus); 401 if (ret) 402 goto err_mdiobus_alloc; 403 404 return 0; 405 406err_mdiobus_alloc: 407 mdiobus_free(fmb->mii_bus); 408err_mdiobus_reg: 409 platform_device_unregister(pdev); 410err_pdev: 411 return ret; 412} 413module_init(fixed_mdio_bus_init); 414 415static void __exit fixed_mdio_bus_exit(void) 416{ 417 struct fixed_mdio_bus *fmb = &platform_fmb; 418 struct fixed_phy *fp, *tmp; 419 420 mdiobus_unregister(fmb->mii_bus); 421 mdiobus_free(fmb->mii_bus); 422 platform_device_unregister(pdev); 423 424 list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { 425 list_del(&fp->node); 426 kfree(fp); 427 } 428} 429module_exit(fixed_mdio_bus_exit); 430 431MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)"); 432MODULE_AUTHOR("Vitaly Bordug"); 433MODULE_LICENSE("GPL"); 434