110-clk-sunxi-add-ve-for-sun457i.patch 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. From 3cdd9f5c4953465abb87ec757159cc0576ae6b0a Mon Sep 17 00:00:00 2001
  2. From: Chen-Yu Tsai <wens@csie.org>
  3. Date: Sat, 5 Dec 2015 21:16:43 +0800
  4. Subject: [PATCH] clk: sunxi: Add VE (Video Engine) module clock driver for
  5. sun[457]i
  6. The video engine has its own special module clock, consisting of a clock
  7. gate, configurable dividers, and a reset control.
  8. On later (sun[68]i) families, the reset control is moved out of this
  9. piece of hardware and grouped with reset controls of other peripherals.
  10. Signed-off-by: Chen-Yu Tsai <wens@csie.org>
  11. Tested-by: Jens Kuske <jenskuske@gmail.com>
  12. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
  13. ---
  14. Documentation/devicetree/bindings/clock/sunxi.txt | 4 +
  15. drivers/clk/sunxi/Makefile | 1 +
  16. drivers/clk/sunxi/clk-a10-ve.c | 171 ++++++++++++++++++++++
  17. 3 files changed, 176 insertions(+)
  18. create mode 100644 drivers/clk/sunxi/clk-a10-ve.c
  19. --- a/Documentation/devicetree/bindings/clock/sunxi.txt
  20. +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
  21. @@ -73,6 +73,7 @@ Required properties:
  22. "allwinner,sun8i-h3-usb-clk" - for usb gates + resets on H3
  23. "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
  24. "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
  25. + "allwinner,sun4i-a10-ve-clk" - for the Video Engine clock
  26. Required properties for all clocks:
  27. - reg : shall be the control register address for the clock.
  28. @@ -92,6 +93,9 @@ Required properties for all clocks:
  29. And "allwinner,*-usb-clk" clocks also require:
  30. - reset-cells : shall be set to 1
  31. +The "allwinner,sun4i-a10-ve-clk" clock also requires:
  32. +- reset-cells : shall be set to 0
  33. +
  34. The "allwinner,sun9i-a80-mmc-config-clk" clock also requires:
  35. - #reset-cells : shall be set to 1
  36. - resets : shall be the reset control phandle for the mmc block.
  37. --- a/drivers/clk/sunxi/Makefile
  38. +++ b/drivers/clk/sunxi/Makefile
  39. @@ -7,6 +7,7 @@ obj-y += clk-a10-codec.o
  40. obj-y += clk-a10-hosc.o
  41. obj-y += clk-a10-mod1.o
  42. obj-y += clk-a10-pll2.o
  43. +obj-y += clk-a10-ve.o
  44. obj-y += clk-a20-gmac.o
  45. obj-y += clk-mod0.o
  46. obj-y += clk-simple-gates.o
  47. --- /dev/null
  48. +++ b/drivers/clk/sunxi/clk-a10-ve.c
  49. @@ -0,0 +1,171 @@
  50. +/*
  51. + * Copyright 2015 Chen-Yu Tsai
  52. + *
  53. + * Chen-Yu Tsai <wens@csie.org>
  54. + *
  55. + * This program is free software; you can redistribute it and/or modify
  56. + * it under the terms of the GNU General Public License as published by
  57. + * the Free Software Foundation; either version 2 of the License, or
  58. + * (at your option) any later version.
  59. + *
  60. + * This program is distributed in the hope that it will be useful,
  61. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  62. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  63. + * GNU General Public License for more details.
  64. + */
  65. +
  66. +#include <linux/clk-provider.h>
  67. +#include <linux/of.h>
  68. +#include <linux/of_address.h>
  69. +#include <linux/reset-controller.h>
  70. +#include <linux/slab.h>
  71. +#include <linux/spinlock.h>
  72. +
  73. +static DEFINE_SPINLOCK(ve_lock);
  74. +
  75. +#define SUN4I_VE_ENABLE 31
  76. +#define SUN4I_VE_DIVIDER_SHIFT 16
  77. +#define SUN4I_VE_DIVIDER_WIDTH 3
  78. +#define SUN4I_VE_RESET 0
  79. +
  80. +/**
  81. + * sunxi_ve_reset... - reset bit in ve clk registers handling
  82. + */
  83. +
  84. +struct ve_reset_data {
  85. + void __iomem *reg;
  86. + spinlock_t *lock;
  87. + struct reset_controller_dev rcdev;
  88. +};
  89. +
  90. +static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev,
  91. + unsigned long id)
  92. +{
  93. + struct ve_reset_data *data = container_of(rcdev,
  94. + struct ve_reset_data,
  95. + rcdev);
  96. + unsigned long flags;
  97. + u32 reg;
  98. +
  99. + spin_lock_irqsave(data->lock, flags);
  100. +
  101. + reg = readl(data->reg);
  102. + writel(reg & ~BIT(SUN4I_VE_RESET), data->reg);
  103. +
  104. + spin_unlock_irqrestore(data->lock, flags);
  105. +
  106. + return 0;
  107. +}
  108. +
  109. +static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev,
  110. + unsigned long id)
  111. +{
  112. + struct ve_reset_data *data = container_of(rcdev,
  113. + struct ve_reset_data,
  114. + rcdev);
  115. + unsigned long flags;
  116. + u32 reg;
  117. +
  118. + spin_lock_irqsave(data->lock, flags);
  119. +
  120. + reg = readl(data->reg);
  121. + writel(reg | BIT(SUN4I_VE_RESET), data->reg);
  122. +
  123. + spin_unlock_irqrestore(data->lock, flags);
  124. +
  125. + return 0;
  126. +}
  127. +
  128. +static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,
  129. + const struct of_phandle_args *reset_spec)
  130. +{
  131. + if (WARN_ON(reset_spec->args_count != 0))
  132. + return -EINVAL;
  133. +
  134. + return 0;
  135. +}
  136. +
  137. +static struct reset_control_ops sunxi_ve_reset_ops = {
  138. + .assert = sunxi_ve_reset_assert,
  139. + .deassert = sunxi_ve_reset_deassert,
  140. +};
  141. +
  142. +static void __init sun4i_ve_clk_setup(struct device_node *node)
  143. +{
  144. + struct clk *clk;
  145. + struct clk_divider *div;
  146. + struct clk_gate *gate;
  147. + struct ve_reset_data *reset_data;
  148. + const char *parent;
  149. + const char *clk_name = node->name;
  150. + void __iomem *reg;
  151. + int err;
  152. +
  153. + reg = of_io_request_and_map(node, 0, of_node_full_name(node));
  154. + if (IS_ERR(reg))
  155. + return;
  156. +
  157. + div = kzalloc(sizeof(*div), GFP_KERNEL);
  158. + if (!div)
  159. + goto err_unmap;
  160. +
  161. + gate = kzalloc(sizeof(*gate), GFP_KERNEL);
  162. + if (!gate)
  163. + goto err_free_div;
  164. +
  165. + of_property_read_string(node, "clock-output-names", &clk_name);
  166. + parent = of_clk_get_parent_name(node, 0);
  167. +
  168. + gate->reg = reg;
  169. + gate->bit_idx = SUN4I_VE_ENABLE;
  170. + gate->lock = &ve_lock;
  171. +
  172. + div->reg = reg;
  173. + div->shift = SUN4I_VE_DIVIDER_SHIFT;
  174. + div->width = SUN4I_VE_DIVIDER_WIDTH;
  175. + div->lock = &ve_lock;
  176. +
  177. + clk = clk_register_composite(NULL, clk_name, &parent, 1,
  178. + NULL, NULL,
  179. + &div->hw, &clk_divider_ops,
  180. + &gate->hw, &clk_gate_ops,
  181. + CLK_SET_RATE_PARENT);
  182. + if (IS_ERR(clk))
  183. + goto err_free_gate;
  184. +
  185. + err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
  186. + if (err)
  187. + goto err_unregister_clk;
  188. +
  189. + reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
  190. + if (!reset_data)
  191. + goto err_del_provider;
  192. +
  193. + reset_data->reg = reg;
  194. + reset_data->lock = &ve_lock;
  195. + reset_data->rcdev.nr_resets = 1;
  196. + reset_data->rcdev.ops = &sunxi_ve_reset_ops;
  197. + reset_data->rcdev.of_node = node;
  198. + reset_data->rcdev.of_xlate = sunxi_ve_of_xlate;
  199. + reset_data->rcdev.of_reset_n_cells = 0;
  200. + err = reset_controller_register(&reset_data->rcdev);
  201. + if (err)
  202. + goto err_free_reset;
  203. +
  204. + return;
  205. +
  206. +err_free_reset:
  207. + kfree(reset_data);
  208. +err_del_provider:
  209. + of_clk_del_provider(node);
  210. +err_unregister_clk:
  211. + clk_unregister(clk);
  212. +err_free_gate:
  213. + kfree(gate);
  214. +err_free_div:
  215. + kfree(div);
  216. +err_unmap:
  217. + iounmap(reg);
  218. +}
  219. +CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk",
  220. + sun4i_ve_clk_setup);