1 /* 2 * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16 17 #include <linux/clk-provider.h> 18 #include <linux/io.h> 19 20 #include "clk.h" 21 22 static inline struct tegra_clk_periph_fixed * 23 to_tegra_clk_periph_fixed(struct clk_hw *hw) 24 { 25 return container_of(hw, struct tegra_clk_periph_fixed, hw); 26 } 27 28 static int tegra_clk_periph_fixed_is_enabled(struct clk_hw *hw) 29 { 30 struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); 31 u32 mask = 1 << (fixed->num % 32), value; 32 33 value = readl(fixed->base + fixed->regs->enb_reg); 34 if (value & mask) { 35 value = readl(fixed->base + fixed->regs->rst_reg); 36 if ((value & mask) == 0) 37 return 1; 38 } 39 40 return 0; 41 } 42 43 static int tegra_clk_periph_fixed_enable(struct clk_hw *hw) 44 { 45 struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); 46 u32 mask = 1 << (fixed->num % 32); 47 48 writel(mask, fixed->base + fixed->regs->enb_set_reg); 49 50 return 0; 51 } 52 53 static void tegra_clk_periph_fixed_disable(struct clk_hw *hw) 54 { 55 struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); 56 u32 mask = 1 << (fixed->num % 32); 57 58 writel(mask, fixed->base + fixed->regs->enb_clr_reg); 59 } 60 61 static unsigned long 62 tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw, 63 unsigned long parent_rate) 64 { 65 struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); 66 unsigned long long rate; 67 68 rate = (unsigned long long)parent_rate * fixed->mul; 69 do_div(rate, fixed->div); 70 71 return (unsigned long)rate; 72 } 73 74 static const struct clk_ops tegra_clk_periph_fixed_ops = { 75 .is_enabled = tegra_clk_periph_fixed_is_enabled, 76 .enable = tegra_clk_periph_fixed_enable, 77 .disable = tegra_clk_periph_fixed_disable, 78 .recalc_rate = tegra_clk_periph_fixed_recalc_rate, 79 }; 80 81 struct clk *tegra_clk_register_periph_fixed(const char *name, 82 const char *parent, 83 unsigned long flags, 84 void __iomem *base, 85 unsigned int mul, 86 unsigned int div, 87 unsigned int num) 88 { 89 const struct tegra_clk_periph_regs *regs; 90 struct tegra_clk_periph_fixed *fixed; 91 struct clk_init_data init; 92 struct clk *clk; 93 94 regs = get_reg_bank(num); 95 if (!regs) 96 return ERR_PTR(-EINVAL); 97 98 fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); 99 if (!fixed) 100 return ERR_PTR(-ENOMEM); 101 102 init.name = name; 103 init.flags = flags; 104 init.parent_names = parent ? &parent : NULL; 105 init.num_parents = parent ? 1 : 0; 106 init.ops = &tegra_clk_periph_fixed_ops; 107 108 fixed->base = base; 109 fixed->regs = regs; 110 fixed->mul = mul; 111 fixed->div = div; 112 fixed->num = num; 113 114 fixed->hw.init = &init; 115 116 clk = clk_register(NULL, &fixed->hw); 117 if (IS_ERR(clk)) 118 kfree(fixed); 119 120 return clk; 121 } 122