clk-sun8i-apb0.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * Copyright (C) 2014 Chen-Yu Tsai
  3. * Author: Chen-Yu Tsai <wens@csie.org>
  4. *
  5. * Allwinner A23 APB0 clock driver
  6. *
  7. * License Terms: GNU General Public License v2
  8. *
  9. * Based on clk-sun6i-apb0.c
  10. * Allwinner A31 APB0 clock driver
  11. *
  12. * Copyright (C) 2014 Free Electrons
  13. * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
  14. *
  15. */
  16. #include <linux/clk-provider.h>
  17. #include <linux/init.h>
  18. #include <linux/of.h>
  19. #include <linux/of_address.h>
  20. #include <linux/platform_device.h>
  21. static struct clk *sun8i_a23_apb0_register(struct device_node *node,
  22. void __iomem *reg)
  23. {
  24. const char *clk_name = node->name;
  25. const char *clk_parent;
  26. struct clk *clk;
  27. int ret;
  28. clk_parent = of_clk_get_parent_name(node, 0);
  29. if (!clk_parent)
  30. return ERR_PTR(-EINVAL);
  31. of_property_read_string(node, "clock-output-names", &clk_name);
  32. /* The A23 APB0 clock is a standard 2 bit wide divider clock */
  33. clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
  34. 0, 2, 0, NULL);
  35. if (IS_ERR(clk))
  36. return clk;
  37. ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
  38. if (ret)
  39. goto err_unregister;
  40. return clk;
  41. err_unregister:
  42. clk_unregister_divider(clk);
  43. return ERR_PTR(ret);
  44. }
  45. static void sun8i_a23_apb0_setup(struct device_node *node)
  46. {
  47. void __iomem *reg;
  48. struct resource res;
  49. struct clk *clk;
  50. reg = of_io_request_and_map(node, 0, of_node_full_name(node));
  51. if (IS_ERR(reg)) {
  52. /*
  53. * This happens with clk nodes instantiated through mfd,
  54. * as those do not have their resources assigned in the
  55. * device tree. Do not print an error in this case.
  56. */
  57. if (PTR_ERR(reg) != -EINVAL)
  58. pr_err("Could not get registers for a23-apb0-clk\n");
  59. return;
  60. }
  61. clk = sun8i_a23_apb0_register(node, reg);
  62. if (IS_ERR(clk))
  63. goto err_unmap;
  64. return;
  65. err_unmap:
  66. iounmap(reg);
  67. of_address_to_resource(node, 0, &res);
  68. release_mem_region(res.start, resource_size(&res));
  69. }
  70. CLK_OF_DECLARE_DRIVER(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
  71. sun8i_a23_apb0_setup);
  72. static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
  73. {
  74. struct device_node *np = pdev->dev.of_node;
  75. struct resource *r;
  76. void __iomem *reg;
  77. struct clk *clk;
  78. r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  79. reg = devm_ioremap_resource(&pdev->dev, r);
  80. if (IS_ERR(reg))
  81. return PTR_ERR(reg);
  82. clk = sun8i_a23_apb0_register(np, reg);
  83. if (IS_ERR(clk))
  84. return PTR_ERR(clk);
  85. return 0;
  86. }
  87. static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {
  88. { .compatible = "allwinner,sun8i-a23-apb0-clk" },
  89. { /* sentinel */ }
  90. };
  91. static struct platform_driver sun8i_a23_apb0_clk_driver = {
  92. .driver = {
  93. .name = "sun8i-a23-apb0-clk",
  94. .of_match_table = sun8i_a23_apb0_clk_dt_ids,
  95. },
  96. .probe = sun8i_a23_apb0_clk_probe,
  97. };
  98. builtin_platform_driver(sun8i_a23_apb0_clk_driver);