Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.
0004  */
0005 
0006 #include <linux/clk-provider.h>
0007 #include <linux/io.h>
0008 
0009 #include "clk.h"
0010 
0011 static inline struct tegra_clk_periph_fixed *
0012 to_tegra_clk_periph_fixed(struct clk_hw *hw)
0013 {
0014     return container_of(hw, struct tegra_clk_periph_fixed, hw);
0015 }
0016 
0017 static int tegra_clk_periph_fixed_is_enabled(struct clk_hw *hw)
0018 {
0019     struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
0020     u32 mask = 1 << (fixed->num % 32), value;
0021 
0022     value = readl(fixed->base + fixed->regs->enb_reg);
0023     if (value & mask) {
0024         value = readl(fixed->base + fixed->regs->rst_reg);
0025         if ((value & mask) == 0)
0026             return 1;
0027     }
0028 
0029     return 0;
0030 }
0031 
0032 static int tegra_clk_periph_fixed_enable(struct clk_hw *hw)
0033 {
0034     struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
0035     u32 mask = 1 << (fixed->num % 32);
0036 
0037     writel(mask, fixed->base + fixed->regs->enb_set_reg);
0038 
0039     return 0;
0040 }
0041 
0042 static void tegra_clk_periph_fixed_disable(struct clk_hw *hw)
0043 {
0044     struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
0045     u32 mask = 1 << (fixed->num % 32);
0046 
0047     writel(mask, fixed->base + fixed->regs->enb_clr_reg);
0048 }
0049 
0050 static unsigned long
0051 tegra_clk_periph_fixed_recalc_rate(struct clk_hw *hw,
0052                    unsigned long parent_rate)
0053 {
0054     struct tegra_clk_periph_fixed *fixed = to_tegra_clk_periph_fixed(hw);
0055     unsigned long long rate;
0056 
0057     rate = (unsigned long long)parent_rate * fixed->mul;
0058     do_div(rate, fixed->div);
0059 
0060     return (unsigned long)rate;
0061 }
0062 
0063 static const struct clk_ops tegra_clk_periph_fixed_ops = {
0064     .is_enabled = tegra_clk_periph_fixed_is_enabled,
0065     .enable = tegra_clk_periph_fixed_enable,
0066     .disable = tegra_clk_periph_fixed_disable,
0067     .recalc_rate = tegra_clk_periph_fixed_recalc_rate,
0068 };
0069 
0070 struct clk *tegra_clk_register_periph_fixed(const char *name,
0071                         const char *parent,
0072                         unsigned long flags,
0073                         void __iomem *base,
0074                         unsigned int mul,
0075                         unsigned int div,
0076                         unsigned int num)
0077 {
0078     const struct tegra_clk_periph_regs *regs;
0079     struct tegra_clk_periph_fixed *fixed;
0080     struct clk_init_data init;
0081     struct clk *clk;
0082 
0083     regs = get_reg_bank(num);
0084     if (!regs)
0085         return ERR_PTR(-EINVAL);
0086 
0087     fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
0088     if (!fixed)
0089         return ERR_PTR(-ENOMEM);
0090 
0091     init.name = name;
0092     init.flags = flags;
0093     init.parent_names = parent ? &parent : NULL;
0094     init.num_parents = parent ? 1 : 0;
0095     init.ops = &tegra_clk_periph_fixed_ops;
0096 
0097     fixed->base = base;
0098     fixed->regs = regs;
0099     fixed->mul = mul;
0100     fixed->div = div;
0101     fixed->num = num;
0102 
0103     fixed->hw.init = &init;
0104 
0105     clk = clk_register(NULL, &fixed->hw);
0106     if (IS_ERR(clk))
0107         kfree(fixed);
0108 
0109     return clk;
0110 }