1 /* 2 * Copyright (C) 2016 Socionext Inc. 3 * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16 #include <linux/clk-provider.h> 17 #include <linux/device.h> 18 #include <linux/regmap.h> 19 20 #include "clk-uniphier.h" 21 22 struct uniphier_clk_gate { 23 struct clk_hw hw; 24 struct regmap *regmap; 25 unsigned int reg; 26 unsigned int bit; 27 }; 28 29 #define to_uniphier_clk_gate(_hw) \ 30 container_of(_hw, struct uniphier_clk_gate, hw) 31 32 static int uniphier_clk_gate_endisable(struct clk_hw *hw, int enable) 33 { 34 struct uniphier_clk_gate *gate = to_uniphier_clk_gate(hw); 35 36 return regmap_write_bits(gate->regmap, gate->reg, BIT(gate->bit), 37 enable ? BIT(gate->bit) : 0); 38 } 39 40 static int uniphier_clk_gate_enable(struct clk_hw *hw) 41 { 42 return uniphier_clk_gate_endisable(hw, 1); 43 } 44 45 static void uniphier_clk_gate_disable(struct clk_hw *hw) 46 { 47 if (uniphier_clk_gate_endisable(hw, 0) < 0) 48 pr_warn("failed to disable clk\n"); 49 } 50 51 static int uniphier_clk_gate_is_enabled(struct clk_hw *hw) 52 { 53 struct uniphier_clk_gate *gate = to_uniphier_clk_gate(hw); 54 unsigned int val; 55 56 if (regmap_read(gate->regmap, gate->reg, &val) < 0) 57 pr_warn("is_enabled() may return wrong result\n"); 58 59 return !!(val & BIT(gate->bit)); 60 } 61 62 static const struct clk_ops uniphier_clk_gate_ops = { 63 .enable = uniphier_clk_gate_enable, 64 .disable = uniphier_clk_gate_disable, 65 .is_enabled = uniphier_clk_gate_is_enabled, 66 }; 67 68 struct clk_hw *uniphier_clk_register_gate(struct device *dev, 69 struct regmap *regmap, 70 const char *name, 71 const struct uniphier_clk_gate_data *data) 72 { 73 struct uniphier_clk_gate *gate; 74 struct clk_init_data init; 75 int ret; 76 77 gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); 78 if (!gate) 79 return ERR_PTR(-ENOMEM); 80 81 init.name = name; 82 init.ops = &uniphier_clk_gate_ops; 83 init.flags = data->parent_name ? CLK_SET_RATE_PARENT : 0; 84 init.parent_names = data->parent_name ? &data->parent_name : NULL; 85 init.num_parents = data->parent_name ? 1 : 0; 86 87 gate->regmap = regmap; 88 gate->reg = data->reg; 89 gate->bit = data->bit; 90 gate->hw.init = &init; 91 92 ret = devm_clk_hw_register(dev, &gate->hw); 93 if (ret) 94 return ERR_PTR(ret); 95 96 return &gate->hw; 97 } 98