clk-fixed-rate.c (5315B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com> 4 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> 5 * 6 * Fixed rate clock implementation 7 */ 8 9#include <linux/clk-provider.h> 10#include <linux/module.h> 11#include <linux/slab.h> 12#include <linux/io.h> 13#include <linux/err.h> 14#include <linux/of.h> 15#include <linux/platform_device.h> 16 17/* 18 * DOC: basic fixed-rate clock that cannot gate 19 * 20 * Traits of this clock: 21 * prepare - clk_(un)prepare only ensures parents are prepared 22 * enable - clk_enable only ensures parents are enabled 23 * rate - rate is always a fixed value. No clk_set_rate support 24 * parent - fixed parent. No clk_set_parent support 25 */ 26 27#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw) 28 29static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw, 30 unsigned long parent_rate) 31{ 32 return to_clk_fixed_rate(hw)->fixed_rate; 33} 34 35static unsigned long clk_fixed_rate_recalc_accuracy(struct clk_hw *hw, 36 unsigned long parent_accuracy) 37{ 38 struct clk_fixed_rate *fixed = to_clk_fixed_rate(hw); 39 40 if (fixed->flags & CLK_FIXED_RATE_PARENT_ACCURACY) 41 return parent_accuracy; 42 43 return fixed->fixed_accuracy; 44} 45 46const struct clk_ops clk_fixed_rate_ops = { 47 .recalc_rate = clk_fixed_rate_recalc_rate, 48 .recalc_accuracy = clk_fixed_rate_recalc_accuracy, 49}; 50EXPORT_SYMBOL_GPL(clk_fixed_rate_ops); 51 52struct clk_hw *__clk_hw_register_fixed_rate(struct device *dev, 53 struct device_node *np, const char *name, 54 const char *parent_name, const struct clk_hw *parent_hw, 55 const struct clk_parent_data *parent_data, unsigned long flags, 56 unsigned long fixed_rate, unsigned long fixed_accuracy, 57 unsigned long clk_fixed_flags) 58{ 59 struct clk_fixed_rate *fixed; 60 struct clk_hw *hw; 61 struct clk_init_data init = {}; 62 int ret = -EINVAL; 63 64 /* allocate fixed-rate clock */ 65 fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); 66 if (!fixed) 67 return ERR_PTR(-ENOMEM); 68 69 init.name = name; 70 init.ops = &clk_fixed_rate_ops; 71 init.flags = flags; 72 init.parent_names = parent_name ? &parent_name : NULL; 73 init.parent_hws = parent_hw ? &parent_hw : NULL; 74 init.parent_data = parent_data; 75 if (parent_name || parent_hw || parent_data) 76 init.num_parents = 1; 77 else 78 init.num_parents = 0; 79 80 /* struct clk_fixed_rate assignments */ 81 fixed->flags = clk_fixed_flags; 82 fixed->fixed_rate = fixed_rate; 83 fixed->fixed_accuracy = fixed_accuracy; 84 fixed->hw.init = &init; 85 86 /* register the clock */ 87 hw = &fixed->hw; 88 if (dev || !np) 89 ret = clk_hw_register(dev, hw); 90 else 91 ret = of_clk_hw_register(np, hw); 92 if (ret) { 93 kfree(fixed); 94 hw = ERR_PTR(ret); 95 } 96 97 return hw; 98} 99EXPORT_SYMBOL_GPL(__clk_hw_register_fixed_rate); 100 101struct clk *clk_register_fixed_rate(struct device *dev, const char *name, 102 const char *parent_name, unsigned long flags, 103 unsigned long fixed_rate) 104{ 105 struct clk_hw *hw; 106 107 hw = clk_hw_register_fixed_rate_with_accuracy(dev, name, parent_name, 108 flags, fixed_rate, 0); 109 if (IS_ERR(hw)) 110 return ERR_CAST(hw); 111 return hw->clk; 112} 113EXPORT_SYMBOL_GPL(clk_register_fixed_rate); 114 115void clk_unregister_fixed_rate(struct clk *clk) 116{ 117 struct clk_hw *hw; 118 119 hw = __clk_get_hw(clk); 120 if (!hw) 121 return; 122 123 clk_unregister(clk); 124 kfree(to_clk_fixed_rate(hw)); 125} 126EXPORT_SYMBOL_GPL(clk_unregister_fixed_rate); 127 128void clk_hw_unregister_fixed_rate(struct clk_hw *hw) 129{ 130 struct clk_fixed_rate *fixed; 131 132 fixed = to_clk_fixed_rate(hw); 133 134 clk_hw_unregister(hw); 135 kfree(fixed); 136} 137EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate); 138 139#ifdef CONFIG_OF 140static struct clk_hw *_of_fixed_clk_setup(struct device_node *node) 141{ 142 struct clk_hw *hw; 143 const char *clk_name = node->name; 144 u32 rate; 145 u32 accuracy = 0; 146 int ret; 147 148 if (of_property_read_u32(node, "clock-frequency", &rate)) 149 return ERR_PTR(-EIO); 150 151 of_property_read_u32(node, "clock-accuracy", &accuracy); 152 153 of_property_read_string(node, "clock-output-names", &clk_name); 154 155 hw = clk_hw_register_fixed_rate_with_accuracy(NULL, clk_name, NULL, 156 0, rate, accuracy); 157 if (IS_ERR(hw)) 158 return hw; 159 160 ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); 161 if (ret) { 162 clk_hw_unregister_fixed_rate(hw); 163 return ERR_PTR(ret); 164 } 165 166 return hw; 167} 168 169/** 170 * of_fixed_clk_setup() - Setup function for simple fixed rate clock 171 * @node: device node for the clock 172 */ 173void __init of_fixed_clk_setup(struct device_node *node) 174{ 175 _of_fixed_clk_setup(node); 176} 177CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup); 178 179static int of_fixed_clk_remove(struct platform_device *pdev) 180{ 181 struct clk_hw *hw = platform_get_drvdata(pdev); 182 183 of_clk_del_provider(pdev->dev.of_node); 184 clk_hw_unregister_fixed_rate(hw); 185 186 return 0; 187} 188 189static int of_fixed_clk_probe(struct platform_device *pdev) 190{ 191 struct clk_hw *hw; 192 193 /* 194 * This function is not executed when of_fixed_clk_setup 195 * succeeded. 196 */ 197 hw = _of_fixed_clk_setup(pdev->dev.of_node); 198 if (IS_ERR(hw)) 199 return PTR_ERR(hw); 200 201 platform_set_drvdata(pdev, hw); 202 203 return 0; 204} 205 206static const struct of_device_id of_fixed_clk_ids[] = { 207 { .compatible = "fixed-clock" }, 208 { } 209}; 210 211static struct platform_driver of_fixed_clk_driver = { 212 .driver = { 213 .name = "of_fixed_clk", 214 .of_match_table = of_fixed_clk_ids, 215 }, 216 .probe = of_fixed_clk_probe, 217 .remove = of_fixed_clk_remove, 218}; 219builtin_platform_driver(of_fixed_clk_driver); 220#endif