ocelot-core.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /*
  3. * Core driver for the Ocelot chip family.
  4. *
  5. * The VSC7511, 7512, 7513, and 7514 can be controlled internally via an
  6. * on-chip MIPS processor, or externally via SPI, I2C, PCIe. This core driver is
  7. * intended to be the bus-agnostic glue between, for example, the SPI bus and
  8. * the child devices.
  9. *
  10. * Copyright 2021-2022 Innovative Advantage Inc.
  11. *
  12. * Author: Colin Foster <[email protected]>
  13. */
  14. #include <linux/bits.h>
  15. #include <linux/device.h>
  16. #include <linux/export.h>
  17. #include <linux/iopoll.h>
  18. #include <linux/ioport.h>
  19. #include <linux/kernel.h>
  20. #include <linux/mfd/core.h>
  21. #include <linux/mfd/ocelot.h>
  22. #include <linux/module.h>
  23. #include <linux/regmap.h>
  24. #include <linux/types.h>
  25. #include <soc/mscc/ocelot.h>
  26. #include "ocelot.h"
  27. #define REG_GCB_SOFT_RST 0x0008
  28. #define BIT_SOFT_CHIP_RST BIT(0)
  29. #define VSC7512_MIIM0_RES_START 0x7107009c
  30. #define VSC7512_MIIM1_RES_START 0x710700c0
  31. #define VSC7512_MIIM_RES_SIZE 0x024
  32. #define VSC7512_PHY_RES_START 0x710700f0
  33. #define VSC7512_PHY_RES_SIZE 0x004
  34. #define VSC7512_GPIO_RES_START 0x71070034
  35. #define VSC7512_GPIO_RES_SIZE 0x06c
  36. #define VSC7512_SIO_CTRL_RES_START 0x710700f8
  37. #define VSC7512_SIO_CTRL_RES_SIZE 0x100
  38. #define VSC7512_GCB_RST_SLEEP_US 100
  39. #define VSC7512_GCB_RST_TIMEOUT_US 100000
  40. static int ocelot_gcb_chip_rst_status(struct ocelot_ddata *ddata)
  41. {
  42. int val, err;
  43. err = regmap_read(ddata->gcb_regmap, REG_GCB_SOFT_RST, &val);
  44. if (err)
  45. return err;
  46. return val;
  47. }
  48. int ocelot_chip_reset(struct device *dev)
  49. {
  50. struct ocelot_ddata *ddata = dev_get_drvdata(dev);
  51. int ret, val;
  52. /*
  53. * Reset the entire chip here to put it into a completely known state.
  54. * Other drivers may want to reset their own subsystems. The register
  55. * self-clears, so one write is all that is needed and wait for it to
  56. * clear.
  57. */
  58. ret = regmap_write(ddata->gcb_regmap, REG_GCB_SOFT_RST, BIT_SOFT_CHIP_RST);
  59. if (ret)
  60. return ret;
  61. return readx_poll_timeout(ocelot_gcb_chip_rst_status, ddata, val, !val,
  62. VSC7512_GCB_RST_SLEEP_US, VSC7512_GCB_RST_TIMEOUT_US);
  63. }
  64. EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT);
  65. static const struct resource vsc7512_miim0_resources[] = {
  66. DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"),
  67. DEFINE_RES_REG_NAMED(VSC7512_PHY_RES_START, VSC7512_PHY_RES_SIZE, "gcb_phy"),
  68. };
  69. static const struct resource vsc7512_miim1_resources[] = {
  70. DEFINE_RES_REG_NAMED(VSC7512_MIIM1_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim1"),
  71. };
  72. static const struct resource vsc7512_pinctrl_resources[] = {
  73. DEFINE_RES_REG_NAMED(VSC7512_GPIO_RES_START, VSC7512_GPIO_RES_SIZE, "gcb_gpio"),
  74. };
  75. static const struct resource vsc7512_sgpio_resources[] = {
  76. DEFINE_RES_REG_NAMED(VSC7512_SIO_CTRL_RES_START, VSC7512_SIO_CTRL_RES_SIZE, "gcb_sio"),
  77. };
  78. static const struct mfd_cell vsc7512_devs[] = {
  79. {
  80. .name = "ocelot-pinctrl",
  81. .of_compatible = "mscc,ocelot-pinctrl",
  82. .num_resources = ARRAY_SIZE(vsc7512_pinctrl_resources),
  83. .resources = vsc7512_pinctrl_resources,
  84. }, {
  85. .name = "ocelot-sgpio",
  86. .of_compatible = "mscc,ocelot-sgpio",
  87. .num_resources = ARRAY_SIZE(vsc7512_sgpio_resources),
  88. .resources = vsc7512_sgpio_resources,
  89. }, {
  90. .name = "ocelot-miim0",
  91. .of_compatible = "mscc,ocelot-miim",
  92. .of_reg = VSC7512_MIIM0_RES_START,
  93. .use_of_reg = true,
  94. .num_resources = ARRAY_SIZE(vsc7512_miim0_resources),
  95. .resources = vsc7512_miim0_resources,
  96. }, {
  97. .name = "ocelot-miim1",
  98. .of_compatible = "mscc,ocelot-miim",
  99. .of_reg = VSC7512_MIIM1_RES_START,
  100. .use_of_reg = true,
  101. .num_resources = ARRAY_SIZE(vsc7512_miim1_resources),
  102. .resources = vsc7512_miim1_resources,
  103. },
  104. };
  105. static void ocelot_core_try_add_regmap(struct device *dev,
  106. const struct resource *res)
  107. {
  108. if (dev_get_regmap(dev, res->name))
  109. return;
  110. ocelot_spi_init_regmap(dev, res);
  111. }
  112. static void ocelot_core_try_add_regmaps(struct device *dev,
  113. const struct mfd_cell *cell)
  114. {
  115. int i;
  116. for (i = 0; i < cell->num_resources; i++)
  117. ocelot_core_try_add_regmap(dev, &cell->resources[i]);
  118. }
  119. int ocelot_core_init(struct device *dev)
  120. {
  121. int i, ndevs;
  122. ndevs = ARRAY_SIZE(vsc7512_devs);
  123. for (i = 0; i < ndevs; i++)
  124. ocelot_core_try_add_regmaps(dev, &vsc7512_devs[i]);
  125. return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL);
  126. }
  127. EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT);
  128. MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver");
  129. MODULE_AUTHOR("Colin Foster <[email protected]>");
  130. MODULE_LICENSE("GPL");
  131. MODULE_IMPORT_NS(MFD_OCELOT_SPI);