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(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(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(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, &apmu->hw); 88 89 if (IS_ERR(clk)) 90 kfree(apmu); 91 92 return clk; 93 } 94