ksz8863_smi.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Microchip KSZ8863 series register access through SMI
  4. *
  5. * Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de>
  6. */
  7. #include <linux/mod_devicetable.h>
  8. #include <linux/property.h>
  9. #include "ksz8.h"
  10. #include "ksz_common.h"
  11. /* Serial Management Interface (SMI) uses the following frame format:
  12. *
  13. * preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle
  14. * |frame| OP code |address |address| | |
  15. * read | 32x1´s | 01 | 00 | 1xRRR | RRRRR |Z0| 00000000DDDDDDDD | Z
  16. * write| 32x1´s | 01 | 00 | 0xRRR | RRRRR |10| xxxxxxxxDDDDDDDD | Z
  17. *
  18. */
  19. #define SMI_KSZ88XX_READ_PHY BIT(4)
  20. static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
  21. void *val_buf, size_t val_len)
  22. {
  23. struct ksz_device *dev = ctx;
  24. struct mdio_device *mdev;
  25. u8 reg = *(u8 *)reg_buf;
  26. u8 *val = val_buf;
  27. int i, ret = 0;
  28. mdev = dev->priv;
  29. mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);
  30. for (i = 0; i < val_len; i++) {
  31. int tmp = reg + i;
  32. ret = __mdiobus_read(mdev->bus, ((tmp & 0xE0) >> 5) |
  33. SMI_KSZ88XX_READ_PHY, tmp);
  34. if (ret < 0)
  35. goto out;
  36. val[i] = ret;
  37. }
  38. ret = 0;
  39. out:
  40. mutex_unlock(&mdev->bus->mdio_lock);
  41. return ret;
  42. }
  43. static int ksz8863_mdio_write(void *ctx, const void *data, size_t count)
  44. {
  45. struct ksz_device *dev = ctx;
  46. struct mdio_device *mdev;
  47. int i, ret = 0;
  48. u32 reg;
  49. u8 *val;
  50. mdev = dev->priv;
  51. val = (u8 *)(data + 4);
  52. reg = *(u32 *)data;
  53. mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);
  54. for (i = 0; i < (count - 4); i++) {
  55. int tmp = reg + i;
  56. ret = __mdiobus_write(mdev->bus, ((tmp & 0xE0) >> 5),
  57. tmp, val[i]);
  58. if (ret < 0)
  59. goto out;
  60. }
  61. out:
  62. mutex_unlock(&mdev->bus->mdio_lock);
  63. return ret;
  64. }
  65. static const struct regmap_bus regmap_smi[] = {
  66. {
  67. .read = ksz8863_mdio_read,
  68. .write = ksz8863_mdio_write,
  69. },
  70. {
  71. .read = ksz8863_mdio_read,
  72. .write = ksz8863_mdio_write,
  73. .val_format_endian_default = REGMAP_ENDIAN_BIG,
  74. },
  75. {
  76. .read = ksz8863_mdio_read,
  77. .write = ksz8863_mdio_write,
  78. .val_format_endian_default = REGMAP_ENDIAN_BIG,
  79. }
  80. };
  81. static const struct regmap_config ksz8863_regmap_config[] = {
  82. {
  83. .name = "#8",
  84. .reg_bits = 8,
  85. .pad_bits = 24,
  86. .val_bits = 8,
  87. .cache_type = REGCACHE_NONE,
  88. .lock = ksz_regmap_lock,
  89. .unlock = ksz_regmap_unlock,
  90. .max_register = U8_MAX,
  91. },
  92. {
  93. .name = "#16",
  94. .reg_bits = 8,
  95. .pad_bits = 24,
  96. .val_bits = 16,
  97. .cache_type = REGCACHE_NONE,
  98. .lock = ksz_regmap_lock,
  99. .unlock = ksz_regmap_unlock,
  100. .max_register = U8_MAX,
  101. },
  102. {
  103. .name = "#32",
  104. .reg_bits = 8,
  105. .pad_bits = 24,
  106. .val_bits = 32,
  107. .cache_type = REGCACHE_NONE,
  108. .lock = ksz_regmap_lock,
  109. .unlock = ksz_regmap_unlock,
  110. .max_register = U8_MAX,
  111. }
  112. };
  113. static int ksz8863_smi_probe(struct mdio_device *mdiodev)
  114. {
  115. struct device *ddev = &mdiodev->dev;
  116. const struct ksz_chip_data *chip;
  117. struct regmap_config rc;
  118. struct ksz_device *dev;
  119. int ret;
  120. int i;
  121. dev = ksz_switch_alloc(&mdiodev->dev, mdiodev);
  122. if (!dev)
  123. return -ENOMEM;
  124. chip = device_get_match_data(ddev);
  125. if (!chip)
  126. return -EINVAL;
  127. for (i = 0; i < __KSZ_NUM_REGMAPS; i++) {
  128. rc = ksz8863_regmap_config[i];
  129. rc.lock_arg = &dev->regmap_mutex;
  130. rc.wr_table = chip->wr_table;
  131. rc.rd_table = chip->rd_table;
  132. dev->regmap[i] = devm_regmap_init(&mdiodev->dev,
  133. &regmap_smi[i], dev,
  134. &rc);
  135. if (IS_ERR(dev->regmap[i])) {
  136. return dev_err_probe(&mdiodev->dev,
  137. PTR_ERR(dev->regmap[i]),
  138. "Failed to initialize regmap%i\n",
  139. ksz8863_regmap_config[i].val_bits);
  140. }
  141. }
  142. if (mdiodev->dev.platform_data)
  143. dev->pdata = mdiodev->dev.platform_data;
  144. ret = ksz_switch_register(dev);
  145. /* Main DSA driver may not be started yet. */
  146. if (ret)
  147. return ret;
  148. dev_set_drvdata(&mdiodev->dev, dev);
  149. return 0;
  150. }
  151. static void ksz8863_smi_remove(struct mdio_device *mdiodev)
  152. {
  153. struct ksz_device *dev = dev_get_drvdata(&mdiodev->dev);
  154. if (dev)
  155. ksz_switch_remove(dev);
  156. }
  157. static void ksz8863_smi_shutdown(struct mdio_device *mdiodev)
  158. {
  159. struct ksz_device *dev = dev_get_drvdata(&mdiodev->dev);
  160. if (dev)
  161. dsa_switch_shutdown(dev->ds);
  162. dev_set_drvdata(&mdiodev->dev, NULL);
  163. }
  164. static const struct of_device_id ksz8863_dt_ids[] = {
  165. {
  166. .compatible = "microchip,ksz8863",
  167. .data = &ksz_switch_chips[KSZ88X3]
  168. },
  169. {
  170. .compatible = "microchip,ksz8873",
  171. .data = &ksz_switch_chips[KSZ88X3]
  172. },
  173. { },
  174. };
  175. MODULE_DEVICE_TABLE(of, ksz8863_dt_ids);
  176. static struct mdio_driver ksz8863_driver = {
  177. .probe = ksz8863_smi_probe,
  178. .remove = ksz8863_smi_remove,
  179. .shutdown = ksz8863_smi_shutdown,
  180. .mdiodrv.driver = {
  181. .name = "ksz8863-switch",
  182. .of_match_table = ksz8863_dt_ids,
  183. },
  184. };
  185. mdio_module_driver(ksz8863_driver);
  186. MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>");
  187. MODULE_DESCRIPTION("Microchip KSZ8863 SMI Switch driver");
  188. MODULE_LICENSE("GPL v2");