hip04_mdio.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /* Copyright (c) 2014 Linaro Ltd.
  2. * Copyright (c) 2014 Hisilicon Limited.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <linux/module.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/io.h>
  12. #include <linux/of_mdio.h>
  13. #include <linux/delay.h>
  14. #define MDIO_CMD_REG 0x0
  15. #define MDIO_ADDR_REG 0x4
  16. #define MDIO_WDATA_REG 0x8
  17. #define MDIO_RDATA_REG 0xc
  18. #define MDIO_STA_REG 0x10
  19. #define MDIO_START BIT(14)
  20. #define MDIO_R_VALID BIT(1)
  21. #define MDIO_READ (BIT(12) | BIT(11) | MDIO_START)
  22. #define MDIO_WRITE (BIT(12) | BIT(10) | MDIO_START)
  23. struct hip04_mdio_priv {
  24. void __iomem *base;
  25. };
  26. #define WAIT_TIMEOUT 10
  27. static int hip04_mdio_wait_ready(struct mii_bus *bus)
  28. {
  29. struct hip04_mdio_priv *priv = bus->priv;
  30. int i;
  31. for (i = 0; readl_relaxed(priv->base + MDIO_CMD_REG) & MDIO_START; i++) {
  32. if (i == WAIT_TIMEOUT)
  33. return -ETIMEDOUT;
  34. msleep(20);
  35. }
  36. return 0;
  37. }
  38. static int hip04_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
  39. {
  40. struct hip04_mdio_priv *priv = bus->priv;
  41. u32 val;
  42. int ret;
  43. ret = hip04_mdio_wait_ready(bus);
  44. if (ret < 0)
  45. goto out;
  46. val = regnum | (mii_id << 5) | MDIO_READ;
  47. writel_relaxed(val, priv->base + MDIO_CMD_REG);
  48. ret = hip04_mdio_wait_ready(bus);
  49. if (ret < 0)
  50. goto out;
  51. val = readl_relaxed(priv->base + MDIO_STA_REG);
  52. if (val & MDIO_R_VALID) {
  53. dev_err(bus->parent, "SMI bus read not valid\n");
  54. ret = -ENODEV;
  55. goto out;
  56. }
  57. val = readl_relaxed(priv->base + MDIO_RDATA_REG);
  58. ret = val & 0xFFFF;
  59. out:
  60. return ret;
  61. }
  62. static int hip04_mdio_write(struct mii_bus *bus, int mii_id,
  63. int regnum, u16 value)
  64. {
  65. struct hip04_mdio_priv *priv = bus->priv;
  66. u32 val;
  67. int ret;
  68. ret = hip04_mdio_wait_ready(bus);
  69. if (ret < 0)
  70. goto out;
  71. writel_relaxed(value, priv->base + MDIO_WDATA_REG);
  72. val = regnum | (mii_id << 5) | MDIO_WRITE;
  73. writel_relaxed(val, priv->base + MDIO_CMD_REG);
  74. out:
  75. return ret;
  76. }
  77. static int hip04_mdio_reset(struct mii_bus *bus)
  78. {
  79. int temp, i;
  80. for (i = 0; i < PHY_MAX_ADDR; i++) {
  81. hip04_mdio_write(bus, i, 22, 0);
  82. temp = hip04_mdio_read(bus, i, MII_BMCR);
  83. if (temp < 0)
  84. continue;
  85. temp |= BMCR_RESET;
  86. if (hip04_mdio_write(bus, i, MII_BMCR, temp) < 0)
  87. continue;
  88. }
  89. mdelay(500);
  90. return 0;
  91. }
  92. static int hip04_mdio_probe(struct platform_device *pdev)
  93. {
  94. struct resource *r;
  95. struct mii_bus *bus;
  96. struct hip04_mdio_priv *priv;
  97. int ret;
  98. bus = mdiobus_alloc_size(sizeof(struct hip04_mdio_priv));
  99. if (!bus) {
  100. dev_err(&pdev->dev, "Cannot allocate MDIO bus\n");
  101. return -ENOMEM;
  102. }
  103. bus->name = "hip04_mdio_bus";
  104. bus->read = hip04_mdio_read;
  105. bus->write = hip04_mdio_write;
  106. bus->reset = hip04_mdio_reset;
  107. snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
  108. bus->parent = &pdev->dev;
  109. priv = bus->priv;
  110. r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  111. priv->base = devm_ioremap_resource(&pdev->dev, r);
  112. if (IS_ERR(priv->base)) {
  113. ret = PTR_ERR(priv->base);
  114. goto out_mdio;
  115. }
  116. ret = of_mdiobus_register(bus, pdev->dev.of_node);
  117. if (ret < 0) {
  118. dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
  119. goto out_mdio;
  120. }
  121. platform_set_drvdata(pdev, bus);
  122. return 0;
  123. out_mdio:
  124. mdiobus_free(bus);
  125. return ret;
  126. }
  127. static int hip04_mdio_remove(struct platform_device *pdev)
  128. {
  129. struct mii_bus *bus = platform_get_drvdata(pdev);
  130. mdiobus_unregister(bus);
  131. mdiobus_free(bus);
  132. return 0;
  133. }
  134. static const struct of_device_id hip04_mdio_match[] = {
  135. { .compatible = "hisilicon,hip04-mdio" },
  136. { }
  137. };
  138. MODULE_DEVICE_TABLE(of, hip04_mdio_match);
  139. static struct platform_driver hip04_mdio_driver = {
  140. .probe = hip04_mdio_probe,
  141. .remove = hip04_mdio_remove,
  142. .driver = {
  143. .name = "hip04-mdio",
  144. .owner = THIS_MODULE,
  145. .of_match_table = hip04_mdio_match,
  146. },
  147. };
  148. module_platform_driver(hip04_mdio_driver);
  149. MODULE_DESCRIPTION("HISILICON P04 MDIO interface driver");
  150. MODULE_LICENSE("GPL v2");
  151. MODULE_ALIAS("platform:hip04-mdio");