fixed_phy.c 9.1 KB

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