1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * mmp AXI peripharal clock operation source file |
4 | * |
5 | * Copyright (C) 2012 Marvell |
6 | * Chao Xie <xiechao.mail@gmail.com> |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/io.h> |
11 | #include <linux/err.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/slab.h> |
14 | |
15 | #include "clk.h" |
16 | |
17 | #define to_clk_apmu(clk) (container_of(clk, struct clk_apmu, clk)) |
18 | struct clk_apmu { |
19 | struct clk_hw hw; |
20 | void __iomem *base; |
21 | u32 rst_mask; |
22 | u32 enable_mask; |
23 | spinlock_t *lock; |
24 | }; |
25 | |
26 | static int clk_apmu_enable(struct clk_hw *hw) |
27 | { |
28 | struct clk_apmu *apmu = to_clk_apmu(hw); |
29 | unsigned long data; |
30 | unsigned long flags = 0; |
31 | |
32 | if (apmu->lock) |
33 | spin_lock_irqsave(apmu->lock, flags); |
34 | |
35 | data = readl_relaxed(apmu->base) | apmu->enable_mask; |
36 | writel_relaxed(data, apmu->base); |
37 | |
38 | if (apmu->lock) |
39 | spin_unlock_irqrestore(lock: apmu->lock, flags); |
40 | |
41 | return 0; |
42 | } |
43 | |
44 | static void clk_apmu_disable(struct clk_hw *hw) |
45 | { |
46 | struct clk_apmu *apmu = to_clk_apmu(hw); |
47 | unsigned long data; |
48 | unsigned long flags = 0; |
49 | |
50 | if (apmu->lock) |
51 | spin_lock_irqsave(apmu->lock, flags); |
52 | |
53 | data = readl_relaxed(apmu->base) & ~apmu->enable_mask; |
54 | writel_relaxed(data, apmu->base); |
55 | |
56 | if (apmu->lock) |
57 | spin_unlock_irqrestore(lock: apmu->lock, flags); |
58 | } |
59 | |
60 | static const struct clk_ops clk_apmu_ops = { |
61 | .enable = clk_apmu_enable, |
62 | .disable = clk_apmu_disable, |
63 | }; |
64 | |
65 | struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name, |
66 | void __iomem *base, u32 enable_mask, spinlock_t *lock) |
67 | { |
68 | struct clk_apmu *apmu; |
69 | struct clk *clk; |
70 | struct clk_init_data init; |
71 | |
72 | apmu = kzalloc(size: sizeof(*apmu), GFP_KERNEL); |
73 | if (!apmu) |
74 | return NULL; |
75 | |
76 | init.name = name; |
77 | init.ops = &clk_apmu_ops; |
78 | init.flags = CLK_SET_RATE_PARENT; |
79 | init.parent_names = (parent_name ? &parent_name : NULL); |
80 | init.num_parents = (parent_name ? 1 : 0); |
81 | |
82 | apmu->base = base; |
83 | apmu->enable_mask = enable_mask; |
84 | apmu->lock = lock; |
85 | apmu->hw.init = &init; |
86 | |
87 | clk = clk_register(NULL, hw: &apmu->hw); |
88 | |
89 | if (IS_ERR(ptr: clk)) |
90 | kfree(objp: apmu); |
91 | |
92 | return clk; |
93 | } |
94 | |