1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2018 NXP 4 * Dong Aisheng <aisheng.dong@nxp.com> 5 */ 6 7 #include <linux/bits.h> 8 #include <linux/clk-provider.h> 9 #include <linux/err.h> 10 #include <linux/io.h> 11 #include <linux/slab.h> 12 #include <linux/spinlock.h> 13 14 #include "clk-scu.h" 15 16 static DEFINE_SPINLOCK(imx_lpcg_scu_lock); 17 18 #define CLK_GATE_SCU_LPCG_MASK 0x3 19 #define CLK_GATE_SCU_LPCG_HW_SEL BIT(0) 20 #define CLK_GATE_SCU_LPCG_SW_SEL BIT(1) 21 22 /* 23 * struct clk_lpcg_scu - Description of LPCG clock 24 * 25 * @hw: clk_hw of this LPCG 26 * @reg: register of this LPCG clock 27 * @bit_idx: bit index of this LPCG clock 28 * @hw_gate: HW auto gate enable 29 * 30 * This structure describes one LPCG clock 31 */ 32 struct clk_lpcg_scu { 33 struct clk_hw hw; 34 void __iomem *reg; 35 u8 bit_idx; 36 bool hw_gate; 37 }; 38 39 #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) 40 41 static int clk_lpcg_scu_enable(struct clk_hw *hw) 42 { 43 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); 44 unsigned long flags; 45 u32 reg, val; 46 47 spin_lock_irqsave(&imx_lpcg_scu_lock, flags); 48 49 reg = readl_relaxed(clk->reg); 50 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx); 51 52 val = CLK_GATE_SCU_LPCG_SW_SEL; 53 if (clk->hw_gate) 54 val |= CLK_GATE_SCU_LPCG_HW_SEL; 55 56 reg |= val << clk->bit_idx; 57 writel(reg, clk->reg); 58 59 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); 60 61 return 0; 62 } 63 64 static void clk_lpcg_scu_disable(struct clk_hw *hw) 65 { 66 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); 67 unsigned long flags; 68 u32 reg; 69 70 spin_lock_irqsave(&imx_lpcg_scu_lock, flags); 71 72 reg = readl_relaxed(clk->reg); 73 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx); 74 writel(reg, clk->reg); 75 76 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); 77 } 78 79 static const struct clk_ops clk_lpcg_scu_ops = { 80 .enable = clk_lpcg_scu_enable, 81 .disable = clk_lpcg_scu_disable, 82 }; 83 84 struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, 85 unsigned long flags, void __iomem *reg, 86 u8 bit_idx, bool hw_gate) 87 { 88 struct clk_lpcg_scu *clk; 89 struct clk_init_data init; 90 struct clk_hw *hw; 91 int ret; 92 93 clk = kzalloc(sizeof(*clk), GFP_KERNEL); 94 if (!clk) 95 return ERR_PTR(-ENOMEM); 96 97 clk->reg = reg; 98 clk->bit_idx = bit_idx; 99 clk->hw_gate = hw_gate; 100 101 init.name = name; 102 init.ops = &clk_lpcg_scu_ops; 103 init.flags = CLK_SET_RATE_PARENT | flags; 104 init.parent_names = parent_name ? &parent_name : NULL; 105 init.num_parents = parent_name ? 1 : 0; 106 107 clk->hw.init = &init; 108 109 hw = &clk->hw; 110 ret = clk_hw_register(NULL, hw); 111 if (ret) { 112 kfree(clk); 113 hw = ERR_PTR(ret); 114 } 115 116 return hw; 117 } 118