sun6i-prcm.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2014 Free Electrons
  4. *
  5. * Author: Boris BREZILLON <[email protected]>
  6. *
  7. * Allwinner PRCM (Power/Reset/Clock Management) driver
  8. */
  9. #include <linux/mfd/core.h>
  10. #include <linux/init.h>
  11. #include <linux/of.h>
  12. #define SUN8I_CODEC_ANALOG_BASE 0x1c0
  13. #define SUN8I_CODEC_ANALOG_SIZE 0x4
  14. struct prcm_data {
  15. int nsubdevs;
  16. const struct mfd_cell *subdevs;
  17. };
  18. static const struct resource sun6i_a31_ar100_clk_res[] = {
  19. DEFINE_RES_MEM(0x0, 4)
  20. };
  21. static const struct resource sun6i_a31_apb0_clk_res[] = {
  22. DEFINE_RES_MEM(0xc, 4)
  23. };
  24. static const struct resource sun6i_a31_apb0_gates_clk_res[] = {
  25. DEFINE_RES_MEM(0x28, 4)
  26. };
  27. static const struct resource sun6i_a31_ir_clk_res[] = {
  28. DEFINE_RES_MEM(0x54, 4)
  29. };
  30. static const struct resource sun6i_a31_apb0_rstc_res[] = {
  31. DEFINE_RES_MEM(0xb0, 4)
  32. };
  33. static const struct resource sun8i_codec_analog_res[] = {
  34. DEFINE_RES_MEM(SUN8I_CODEC_ANALOG_BASE, SUN8I_CODEC_ANALOG_SIZE),
  35. };
  36. static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
  37. {
  38. .name = "sun6i-a31-ar100-clk",
  39. .of_compatible = "allwinner,sun6i-a31-ar100-clk",
  40. .num_resources = ARRAY_SIZE(sun6i_a31_ar100_clk_res),
  41. .resources = sun6i_a31_ar100_clk_res,
  42. },
  43. {
  44. .name = "sun6i-a31-apb0-clk",
  45. .of_compatible = "allwinner,sun6i-a31-apb0-clk",
  46. .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res),
  47. .resources = sun6i_a31_apb0_clk_res,
  48. },
  49. {
  50. .name = "sun6i-a31-apb0-gates-clk",
  51. .of_compatible = "allwinner,sun6i-a31-apb0-gates-clk",
  52. .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res),
  53. .resources = sun6i_a31_apb0_gates_clk_res,
  54. },
  55. {
  56. .name = "sun6i-a31-ir-clk",
  57. .of_compatible = "allwinner,sun4i-a10-mod0-clk",
  58. .num_resources = ARRAY_SIZE(sun6i_a31_ir_clk_res),
  59. .resources = sun6i_a31_ir_clk_res,
  60. },
  61. {
  62. .name = "sun6i-a31-apb0-clock-reset",
  63. .of_compatible = "allwinner,sun6i-a31-clock-reset",
  64. .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
  65. .resources = sun6i_a31_apb0_rstc_res,
  66. },
  67. };
  68. static const struct mfd_cell sun8i_a23_prcm_subdevs[] = {
  69. {
  70. .name = "sun8i-a23-apb0-clk",
  71. .of_compatible = "allwinner,sun8i-a23-apb0-clk",
  72. .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res),
  73. .resources = sun6i_a31_apb0_clk_res,
  74. },
  75. {
  76. .name = "sun6i-a31-apb0-gates-clk",
  77. .of_compatible = "allwinner,sun8i-a23-apb0-gates-clk",
  78. .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res),
  79. .resources = sun6i_a31_apb0_gates_clk_res,
  80. },
  81. {
  82. .name = "sun6i-a31-apb0-clock-reset",
  83. .of_compatible = "allwinner,sun6i-a31-clock-reset",
  84. .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
  85. .resources = sun6i_a31_apb0_rstc_res,
  86. },
  87. {
  88. .name = "sun8i-codec-analog",
  89. .of_compatible = "allwinner,sun8i-a23-codec-analog",
  90. .num_resources = ARRAY_SIZE(sun8i_codec_analog_res),
  91. .resources = sun8i_codec_analog_res,
  92. },
  93. };
  94. static const struct prcm_data sun6i_a31_prcm_data = {
  95. .nsubdevs = ARRAY_SIZE(sun6i_a31_prcm_subdevs),
  96. .subdevs = sun6i_a31_prcm_subdevs,
  97. };
  98. static const struct prcm_data sun8i_a23_prcm_data = {
  99. .nsubdevs = ARRAY_SIZE(sun8i_a23_prcm_subdevs),
  100. .subdevs = sun8i_a23_prcm_subdevs,
  101. };
  102. static const struct of_device_id sun6i_prcm_dt_ids[] = {
  103. {
  104. .compatible = "allwinner,sun6i-a31-prcm",
  105. .data = &sun6i_a31_prcm_data,
  106. },
  107. {
  108. .compatible = "allwinner,sun8i-a23-prcm",
  109. .data = &sun8i_a23_prcm_data,
  110. },
  111. { /* sentinel */ },
  112. };
  113. static int sun6i_prcm_probe(struct platform_device *pdev)
  114. {
  115. const struct of_device_id *match;
  116. const struct prcm_data *data;
  117. struct resource *res;
  118. int ret;
  119. match = of_match_node(sun6i_prcm_dt_ids, pdev->dev.of_node);
  120. if (!match)
  121. return -EINVAL;
  122. data = match->data;
  123. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  124. if (!res) {
  125. dev_err(&pdev->dev, "no prcm memory region provided\n");
  126. return -ENOENT;
  127. }
  128. ret = mfd_add_devices(&pdev->dev, 0, data->subdevs, data->nsubdevs,
  129. res, -1, NULL);
  130. if (ret) {
  131. dev_err(&pdev->dev, "failed to add subdevices\n");
  132. return ret;
  133. }
  134. return 0;
  135. }
  136. static struct platform_driver sun6i_prcm_driver = {
  137. .driver = {
  138. .name = "sun6i-prcm",
  139. .of_match_table = sun6i_prcm_dt_ids,
  140. },
  141. .probe = sun6i_prcm_probe,
  142. };
  143. builtin_platform_driver(sun6i_prcm_driver);