clk-sun4i-pll3.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * Copyright 2015 Maxime Ripard
  3. *
  4. * Maxime Ripard <maxime.ripard@free-electrons.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/clk-provider.h>
  17. #include <linux/of.h>
  18. #include <linux/of_address.h>
  19. #include <linux/slab.h>
  20. #include <linux/spinlock.h>
  21. #define SUN4I_A10_PLL3_GATE_BIT 31
  22. #define SUN4I_A10_PLL3_DIV_WIDTH 7
  23. #define SUN4I_A10_PLL3_DIV_SHIFT 0
  24. static DEFINE_SPINLOCK(sun4i_a10_pll3_lock);
  25. static void __init sun4i_a10_pll3_setup(struct device_node *node)
  26. {
  27. const char *clk_name = node->name, *parent;
  28. struct clk_multiplier *mult;
  29. struct clk_gate *gate;
  30. struct resource res;
  31. void __iomem *reg;
  32. struct clk *clk;
  33. int ret;
  34. of_property_read_string(node, "clock-output-names", &clk_name);
  35. parent = of_clk_get_parent_name(node, 0);
  36. reg = of_io_request_and_map(node, 0, of_node_full_name(node));
  37. if (IS_ERR(reg)) {
  38. pr_err("%s: Could not map the clock registers\n", clk_name);
  39. return;
  40. }
  41. gate = kzalloc(sizeof(*gate), GFP_KERNEL);
  42. if (!gate)
  43. goto err_unmap;
  44. gate->reg = reg;
  45. gate->bit_idx = SUN4I_A10_PLL3_GATE_BIT;
  46. gate->lock = &sun4i_a10_pll3_lock;
  47. mult = kzalloc(sizeof(*mult), GFP_KERNEL);
  48. if (!mult)
  49. goto err_free_gate;
  50. mult->reg = reg;
  51. mult->shift = SUN4I_A10_PLL3_DIV_SHIFT;
  52. mult->width = SUN4I_A10_PLL3_DIV_WIDTH;
  53. mult->lock = &sun4i_a10_pll3_lock;
  54. clk = clk_register_composite(NULL, clk_name,
  55. &parent, 1,
  56. NULL, NULL,
  57. &mult->hw, &clk_multiplier_ops,
  58. &gate->hw, &clk_gate_ops,
  59. 0);
  60. if (IS_ERR(clk)) {
  61. pr_err("%s: Couldn't register the clock\n", clk_name);
  62. goto err_free_mult;
  63. }
  64. ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
  65. if (ret) {
  66. pr_err("%s: Couldn't register DT provider\n",
  67. clk_name);
  68. goto err_clk_unregister;
  69. }
  70. return;
  71. err_clk_unregister:
  72. clk_unregister_composite(clk);
  73. err_free_mult:
  74. kfree(mult);
  75. err_free_gate:
  76. kfree(gate);
  77. err_unmap:
  78. iounmap(reg);
  79. of_address_to_resource(node, 0, &res);
  80. release_mem_region(res.start, resource_size(&res));
  81. }
  82. CLK_OF_DECLARE(sun4i_a10_pll3, "allwinner,sun4i-a10-pll3-clk",
  83. sun4i_a10_pll3_setup);