1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
6 #include <linux/kernel.h>
9 #include <linux/delay.h>
10 #include <linux/slab.h>
11 #include <linux/clk-provider.h>
15 #define pll_out_enb(p) (BIT(p->enb_bit_idx))
16 #define pll_out_rst(p) (BIT(p->rst_bit_idx))
18 static int clk_pll_out_is_enabled(struct clk_hw
*hw
)
20 struct tegra_clk_pll_out
*pll_out
= to_clk_pll_out(hw
);
21 u32 val
= readl_relaxed(pll_out
->reg
);
24 state
= (val
& pll_out_enb(pll_out
)) ? 1 : 0;
25 if (!(val
& (pll_out_rst(pll_out
))))
30 static int clk_pll_out_enable(struct clk_hw
*hw
)
32 struct tegra_clk_pll_out
*pll_out
= to_clk_pll_out(hw
);
33 unsigned long flags
= 0;
37 spin_lock_irqsave(pll_out
->lock
, flags
);
39 val
= readl_relaxed(pll_out
->reg
);
41 val
|= (pll_out_enb(pll_out
) | pll_out_rst(pll_out
));
43 writel_relaxed(val
, pll_out
->reg
);
47 spin_unlock_irqrestore(pll_out
->lock
, flags
);
52 static void clk_pll_out_disable(struct clk_hw
*hw
)
54 struct tegra_clk_pll_out
*pll_out
= to_clk_pll_out(hw
);
55 unsigned long flags
= 0;
59 spin_lock_irqsave(pll_out
->lock
, flags
);
61 val
= readl_relaxed(pll_out
->reg
);
63 val
&= ~(pll_out_enb(pll_out
) | pll_out_rst(pll_out
));
65 writel_relaxed(val
, pll_out
->reg
);
69 spin_unlock_irqrestore(pll_out
->lock
, flags
);
72 static void tegra_clk_pll_out_restore_context(struct clk_hw
*hw
)
74 if (!__clk_get_enable_count(hw
->clk
))
75 clk_pll_out_disable(hw
);
77 clk_pll_out_enable(hw
);
80 const struct clk_ops tegra_clk_pll_out_ops
= {
81 .is_enabled
= clk_pll_out_is_enabled
,
82 .enable
= clk_pll_out_enable
,
83 .disable
= clk_pll_out_disable
,
84 .restore_context
= tegra_clk_pll_out_restore_context
,
87 struct clk
*tegra_clk_register_pll_out(const char *name
,
88 const char *parent_name
, void __iomem
*reg
, u8 enb_bit_idx
,
89 u8 rst_bit_idx
, unsigned long flags
, u8 pll_out_flags
,
92 struct tegra_clk_pll_out
*pll_out
;
94 struct clk_init_data init
;
96 pll_out
= kzalloc(sizeof(*pll_out
), GFP_KERNEL
);
98 return ERR_PTR(-ENOMEM
);
101 init
.ops
= &tegra_clk_pll_out_ops
;
102 init
.parent_names
= (parent_name
? &parent_name
: NULL
);
103 init
.num_parents
= (parent_name
? 1 : 0);
107 pll_out
->enb_bit_idx
= enb_bit_idx
;
108 pll_out
->rst_bit_idx
= rst_bit_idx
;
109 pll_out
->flags
= pll_out_flags
;
110 pll_out
->lock
= lock
;
112 /* Data in .init is copied by clk_register(), so stack variable OK */
113 pll_out
->hw
.init
= &init
;
115 clk
= clk_register(NULL
, &pll_out
->hw
);