1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. 4 */ 5 6 #include <linux/clk-provider.h> 7 #include <linux/io.h> 8 9 #include "clk.h" 10 11 static inline struct tegra_clk_periph_fixed * 12 to_tegra_clk_periph_fixed(struct clk_hw *hw) 13 { 14 return container_of(hw, struct tegra_clk_periph_fixed, hw); 15 } 16 17 static int tegra_clk_periph_fixed_is_enabled(struct clk_hw *hw) 18 { 19 struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); 20 u32 mask = 1 << (fixed->num % 32), value; 21 22 value = readl(fixed->base + fixed->regs->enb_reg); 23 if (value & mask) { 24 value = readl(fixed->base + fixed->regs->rst_reg); 25 if ((value & mask) == 0) 26 return 1; 27 } 28 29 return 0; 30 } 31 32 static int tegra_clk_periph_fixed_enable(struct clk_hw *hw) 33 { 34 struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); 35 u32 mask = 1 << (fixed->num % 32); 36 37 writel(mask, fixed->base + fixed->regs->enb_set_reg); 38 39 return 0; 40 } 41 42 static void tegra_clk_periph_fixed_disable(struct clk_hw *hw) 43 { 44 struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); 45 u32 mask = 1 << (fixed->num % 32); 46 47 writel(mask, fixed->base + fixed->regs->enb_clr_reg); 48 } 49 50 static unsigned long 51 tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw, 52 unsigned long parent_rate) 53 { 54 struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw); 55 unsigned long long rate; 56 57 rate = (unsigned long long)parent_rate * fixed->mul; 58 do_div(rate, fixed->div); 59 60 return (unsigned long)rate; 61 } 62 63 static const struct clk_ops tegra_clk_periph_fixed_ops = { 64 .is_enabled = tegra_clk_periph_fixed_is_enabled, 65 .enable = tegra_clk_periph_fixed_enable, 66 .disable = tegra_clk_periph_fixed_disable, 67 .recalc_rate = tegra_clk_periph_fixed_recalc_rate, 68 }; 69 70 struct clk *tegra_clk_register_periph_fixed(const char *name, 71 const char *parent, 72 unsigned long flags, 73 void __iomem *base, 74 unsigned int mul, 75 unsigned int div, 76 unsigned int num) 77 { 78 const struct tegra_clk_periph_regs *regs; 79 struct tegra_clk_periph_fixed *fixed; 80 struct clk_init_data init; 81 struct clk *clk; 82 83 regs = get_reg_bank(num); 84 if (!regs) 85 return ERR_PTR(-EINVAL); 86 87 fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); 88 if (!fixed) 89 return ERR_PTR(-ENOMEM); 90 91 init.name = name; 92 init.flags = flags; 93 init.parent_names = parent ? &parent : NULL; 94 init.num_parents = parent ? 1 : 0; 95 init.ops = &tegra_clk_periph_fixed_ops; 96 97 fixed->base = base; 98 fixed->regs = regs; 99 fixed->mul = mul; 100 fixed->div = div; 101 fixed->num = num; 102 103 fixed->hw.init = &init; 104 105 clk = clk_register(NULL, &fixed->hw); 106 if (IS_ERR(clk)) 107 kfree(fixed); 108 109 return clk; 110 } 111