111 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 11static inline struct tegra_clk_periph_fixed *12to_tegra_clk_periph_fixed(struct clk_hw *hw)13{14 return container_of(hw, struct tegra_clk_periph_fixed, hw);15}16 17static 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 32static 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 42static 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 50static unsigned long51tegra_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 63static 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 70struct 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