]>
Commit | Line | Data |
---|---|---|
89a3dfb7 MR |
1 | /* |
2 | * Copyright (C) 2016 Maxime Ripard | |
3 | * Maxime Ripard <[email protected]> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License as | |
7 | * published by the Free Software Foundation; either version 2 of | |
8 | * the License, or (at your option) any later version. | |
9 | */ | |
10 | ||
11 | #include <linux/clk-provider.h> | |
12 | #include <linux/spinlock.h> | |
13 | ||
14 | #include "ccu_frac.h" | |
15 | ||
16 | bool ccu_frac_helper_is_enabled(struct ccu_common *common, | |
a501a14e | 17 | struct ccu_frac_internal *cf) |
89a3dfb7 MR |
18 | { |
19 | if (!(common->features & CCU_FEATURE_FRACTIONAL)) | |
20 | return false; | |
21 | ||
22 | return !(readl(common->base + common->reg) & cf->enable); | |
23 | } | |
24 | ||
25 | void ccu_frac_helper_enable(struct ccu_common *common, | |
a501a14e | 26 | struct ccu_frac_internal *cf) |
89a3dfb7 MR |
27 | { |
28 | unsigned long flags; | |
29 | u32 reg; | |
30 | ||
31 | if (!(common->features & CCU_FEATURE_FRACTIONAL)) | |
32 | return; | |
33 | ||
34 | spin_lock_irqsave(common->lock, flags); | |
35 | reg = readl(common->base + common->reg); | |
36 | writel(reg & ~cf->enable, common->base + common->reg); | |
37 | spin_unlock_irqrestore(common->lock, flags); | |
38 | } | |
39 | ||
40 | void ccu_frac_helper_disable(struct ccu_common *common, | |
a501a14e | 41 | struct ccu_frac_internal *cf) |
89a3dfb7 MR |
42 | { |
43 | unsigned long flags; | |
44 | u32 reg; | |
45 | ||
46 | if (!(common->features & CCU_FEATURE_FRACTIONAL)) | |
47 | return; | |
48 | ||
49 | spin_lock_irqsave(common->lock, flags); | |
50 | reg = readl(common->base + common->reg); | |
51 | writel(reg | cf->enable, common->base + common->reg); | |
52 | spin_unlock_irqrestore(common->lock, flags); | |
53 | } | |
54 | ||
55 | bool ccu_frac_helper_has_rate(struct ccu_common *common, | |
a501a14e | 56 | struct ccu_frac_internal *cf, |
89a3dfb7 MR |
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 | ||
65 | unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, | |
a501a14e | 66 | struct ccu_frac_internal *cf) |
89a3dfb7 MR |
67 | { |
68 | u32 reg; | |
69 | ||
b655f36e | 70 | pr_debug("%s: Read fractional\n", clk_hw_get_name(&common->hw)); |
89a3dfb7 MR |
71 | |
72 | if (!(common->features & CCU_FEATURE_FRACTIONAL)) | |
73 | return 0; | |
74 | ||
b655f36e JS |
75 | pr_debug("%s: clock is fractional (rates %lu and %lu)\n", |
76 | clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]); | |
89a3dfb7 MR |
77 | |
78 | reg = readl(common->base + common->reg); | |
79 | ||
b655f36e JS |
80 | pr_debug("%s: clock reg is 0x%x (select is 0x%x)\n", |
81 | clk_hw_get_name(&common->hw), reg, cf->select); | |
89a3dfb7 MR |
82 | |
83 | return (reg & cf->select) ? cf->rates[1] : cf->rates[0]; | |
84 | } | |
85 | ||
86 | int ccu_frac_helper_set_rate(struct ccu_common *common, | |
a501a14e | 87 | struct ccu_frac_internal *cf, |
1d42460a | 88 | unsigned long rate, u32 lock) |
89a3dfb7 MR |
89 | { |
90 | unsigned long flags; | |
91 | u32 reg, sel; | |
92 | ||
93 | if (!(common->features & CCU_FEATURE_FRACTIONAL)) | |
94 | return -EINVAL; | |
95 | ||
96 | if (cf->rates[0] == rate) | |
97 | sel = 0; | |
98 | else if (cf->rates[1] == rate) | |
99 | sel = cf->select; | |
100 | else | |
101 | return -EINVAL; | |
102 | ||
103 | spin_lock_irqsave(common->lock, flags); | |
104 | reg = readl(common->base + common->reg); | |
105 | reg &= ~cf->select; | |
106 | writel(reg | sel, common->base + common->reg); | |
107 | spin_unlock_irqrestore(common->lock, flags); | |
108 | ||
1d42460a JS |
109 | ccu_helper_wait_for_lock(common, lock); |
110 | ||
89a3dfb7 MR |
111 | return 0; |
112 | } |