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 #include "ccu.h"
7 #include "ccu_frac.h"
8 #include <hal_log.h>
9 
ccu_frac_helper_is_enabled(struct ccu_common * common,struct ccu_frac_internal * cf)10 bool ccu_frac_helper_is_enabled(struct ccu_common *common,
11                                 struct ccu_frac_internal *cf)
12 {
13     if (!(common->features & CCU_FEATURE_FRACTIONAL))
14     {
15         return false;
16     }
17 
18     return !(readl(common->base + common->reg) & cf->enable);
19 }
20 
ccu_frac_helper_enable(struct ccu_common * common,struct ccu_frac_internal * cf)21 void ccu_frac_helper_enable(struct ccu_common *common,
22                             struct ccu_frac_internal *cf)
23 {
24     u32 reg;
25     u32 __cspr;
26 
27     if (!(common->features & CCU_FEATURE_FRACTIONAL))
28     {
29         return;
30     }
31 
32     __cspr = hal_spin_lock_irqsave(&common->lock);
33     reg = readl(common->base + common->reg);
34     writel(reg & ~cf->enable, common->base + common->reg);
35     hal_spin_unlock_irqrestore(&common->lock, __cspr);
36 }
37 
ccu_frac_helper_disable(struct ccu_common * common,struct ccu_frac_internal * cf)38 void ccu_frac_helper_disable(struct ccu_common *common,
39                              struct ccu_frac_internal *cf)
40 {
41     u32 reg;
42     u32 __cspr;
43 
44     if (!(common->features & CCU_FEATURE_FRACTIONAL))
45     {
46         return;
47     }
48 
49     __cspr = hal_spin_lock_irqsave(&common->lock);
50     reg = readl(common->base + common->reg);
51     writel(reg | cf->enable, common->base + common->reg);
52     hal_spin_unlock_irqrestore(&common->lock, __cspr);
53 }
54 
ccu_frac_helper_has_rate(struct ccu_common * common,struct ccu_frac_internal * cf,unsigned long rate)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     {
61         return false;
62     }
63 
64     return (cf->rates[0] == rate) || (cf->rates[1] == rate);
65 }
66 
ccu_frac_helper_read_rate(struct ccu_common * common,struct ccu_frac_internal * cf)67 unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
68                                         struct ccu_frac_internal *cf)
69 {
70     u32 reg;
71 
72     hal_log_debug("%s: Read fractional\n", clk_hw_get_name(&common->hw));
73 
74     if (!(common->features & CCU_FEATURE_FRACTIONAL))
75     {
76         return 0;
77     }
78 
79     hal_log_debug("%s: clock is fractional (rates %lu and %lu)\n",
80                   clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
81 
82     reg = readl(common->base + common->reg);
83 
84     hal_log_debug("%s: clock reg is 0x%x (select is 0x%x)\n",
85                   clk_hw_get_name(&common->hw), reg, cf->select);
86 
87     return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
88 }
89 
ccu_frac_helper_set_rate(struct ccu_common * common,struct ccu_frac_internal * cf,unsigned long rate,u32 lock)90 int ccu_frac_helper_set_rate(struct ccu_common *common,
91                              struct ccu_frac_internal *cf,
92                              unsigned long rate, u32 lock)
93 {
94     u32 reg, sel;
95     u32 __cspr;
96 
97     if (!(common->features & CCU_FEATURE_FRACTIONAL))
98     {
99         return -1;
100     }
101 
102     if (cf->rates[0] == rate)
103     {
104         sel = 0;
105     }
106     else if (cf->rates[1] == rate)
107     {
108         sel = cf->select;
109     }
110     else
111     {
112         return -1;
113     }
114 
115     __cspr = hal_spin_lock_irqsave(&common->lock);
116     reg = readl(common->base + common->reg);
117     reg &= ~cf->select;
118     writel(reg | sel, common->base + common->reg);
119     hal_spin_unlock_irqrestore(&common->lock, __cspr);
120 
121     ccu_helper_wait_for_lock(common, lock);
122     return 0;
123 }
124