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