Merge patch series "RISC-V: Align the shadow stack"
[linux-block.git] / drivers / clk / sunxi-ng / ccu_frac.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2016 Maxime Ripard
4  * Maxime Ripard <maxime.ripard@free-electrons.com>
5  */
6
7 #include <linux/clk-provider.h>
8 #include <linux/io.h>
9 #include <linux/spinlock.h>
10
11 #include "ccu_frac.h"
12
13 bool ccu_frac_helper_is_enabled(struct ccu_common *common,
14                                 struct ccu_frac_internal *cf)
15 {
16         if (!(common->features & CCU_FEATURE_FRACTIONAL))
17                 return false;
18
19         return !(readl(common->base + common->reg) & cf->enable);
20 }
21 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_is_enabled, SUNXI_CCU);
22
23 void ccu_frac_helper_enable(struct ccu_common *common,
24                             struct ccu_frac_internal *cf)
25 {
26         unsigned long flags;
27         u32 reg;
28
29         if (!(common->features & CCU_FEATURE_FRACTIONAL))
30                 return;
31
32         spin_lock_irqsave(common->lock, flags);
33         reg = readl(common->base + common->reg);
34         writel(reg & ~cf->enable, common->base + common->reg);
35         spin_unlock_irqrestore(common->lock, flags);
36 }
37 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_enable, SUNXI_CCU);
38
39 void ccu_frac_helper_disable(struct ccu_common *common,
40                              struct ccu_frac_internal *cf)
41 {
42         unsigned long flags;
43         u32 reg;
44
45         if (!(common->features & CCU_FEATURE_FRACTIONAL))
46                 return;
47
48         spin_lock_irqsave(common->lock, flags);
49         reg = readl(common->base + common->reg);
50         writel(reg | cf->enable, common->base + common->reg);
51         spin_unlock_irqrestore(common->lock, flags);
52 }
53 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_disable, SUNXI_CCU);
54
55 bool ccu_frac_helper_has_rate(struct ccu_common *common,
56                               struct ccu_frac_internal *cf,
57                               unsigned long rate)
58 {
59         if (!(common->features & CCU_FEATURE_FRACTIONAL))
60                 return false;
61
62         return (cf->rates[0] == rate) || (cf->rates[1] == rate);
63 }
64 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_has_rate, SUNXI_CCU);
65
66 unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
67                                         struct ccu_frac_internal *cf)
68 {
69         u32 reg;
70
71         pr_debug("%s: Read fractional\n", clk_hw_get_name(&common->hw));
72
73         if (!(common->features & CCU_FEATURE_FRACTIONAL))
74                 return 0;
75
76         pr_debug("%s: clock is fractional (rates %lu and %lu)\n",
77                  clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
78
79         reg = readl(common->base + common->reg);
80
81         pr_debug("%s: clock reg is 0x%x (select is 0x%x)\n",
82                  clk_hw_get_name(&common->hw), reg, cf->select);
83
84         return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
85 }
86 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_read_rate, SUNXI_CCU);
87
88 int ccu_frac_helper_set_rate(struct ccu_common *common,
89                              struct ccu_frac_internal *cf,
90                              unsigned long rate, u32 lock)
91 {
92         unsigned long flags;
93         u32 reg, sel;
94
95         if (!(common->features & CCU_FEATURE_FRACTIONAL))
96                 return -EINVAL;
97
98         if (cf->rates[0] == rate)
99                 sel = 0;
100         else if (cf->rates[1] == rate)
101                 sel = cf->select;
102         else
103                 return -EINVAL;
104
105         spin_lock_irqsave(common->lock, flags);
106         reg = readl(common->base + common->reg);
107         reg &= ~cf->select;
108         writel(reg | sel, common->base + common->reg);
109         spin_unlock_irqrestore(common->lock, flags);
110
111         ccu_helper_wait_for_lock(common, lock);
112
113         return 0;
114 }
115 EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_set_rate, SUNXI_CCU);