clk-lpcg-scu.c (3510B)
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 16static 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 */ 32struct clk_lpcg_scu { 33 struct clk_hw hw; 34 void __iomem *reg; 35 u8 bit_idx; 36 bool hw_gate; 37 38 /* for state save&restore */ 39 u32 state; 40}; 41 42#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) 43 44static int clk_lpcg_scu_enable(struct clk_hw *hw) 45{ 46 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); 47 unsigned long flags; 48 u32 reg, val; 49 50 spin_lock_irqsave(&imx_lpcg_scu_lock, flags); 51 52 reg = readl_relaxed(clk->reg); 53 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx); 54 55 val = CLK_GATE_SCU_LPCG_SW_SEL; 56 if (clk->hw_gate) 57 val |= CLK_GATE_SCU_LPCG_HW_SEL; 58 59 reg |= val << clk->bit_idx; 60 writel(reg, clk->reg); 61 62 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); 63 64 return 0; 65} 66 67static void clk_lpcg_scu_disable(struct clk_hw *hw) 68{ 69 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); 70 unsigned long flags; 71 u32 reg; 72 73 spin_lock_irqsave(&imx_lpcg_scu_lock, flags); 74 75 reg = readl_relaxed(clk->reg); 76 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx); 77 writel(reg, clk->reg); 78 79 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); 80} 81 82static const struct clk_ops clk_lpcg_scu_ops = { 83 .enable = clk_lpcg_scu_enable, 84 .disable = clk_lpcg_scu_disable, 85}; 86 87struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name, 88 const char *parent_name, unsigned long flags, 89 void __iomem *reg, u8 bit_idx, bool hw_gate) 90{ 91 struct clk_lpcg_scu *clk; 92 struct clk_init_data init; 93 struct clk_hw *hw; 94 int ret; 95 96 clk = kzalloc(sizeof(*clk), GFP_KERNEL); 97 if (!clk) 98 return ERR_PTR(-ENOMEM); 99 100 clk->reg = reg; 101 clk->bit_idx = bit_idx; 102 clk->hw_gate = hw_gate; 103 104 init.name = name; 105 init.ops = &clk_lpcg_scu_ops; 106 init.flags = CLK_SET_RATE_PARENT | flags; 107 init.parent_names = parent_name ? &parent_name : NULL; 108 init.num_parents = parent_name ? 1 : 0; 109 110 clk->hw.init = &init; 111 112 hw = &clk->hw; 113 ret = clk_hw_register(dev, hw); 114 if (ret) { 115 kfree(clk); 116 hw = ERR_PTR(ret); 117 return hw; 118 } 119 120 if (dev) 121 dev_set_drvdata(dev, clk); 122 123 return hw; 124} 125 126void imx_clk_lpcg_scu_unregister(struct clk_hw *hw) 127{ 128 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); 129 130 clk_hw_unregister(&clk->hw); 131 kfree(clk); 132} 133 134static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev) 135{ 136 struct clk_lpcg_scu *clk = dev_get_drvdata(dev); 137 138 clk->state = readl_relaxed(clk->reg); 139 dev_dbg(dev, "save lpcg state 0x%x\n", clk->state); 140 141 return 0; 142} 143 144static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) 145{ 146 struct clk_lpcg_scu *clk = dev_get_drvdata(dev); 147 148 /* 149 * FIXME: Sometimes writes don't work unless the CPU issues 150 * them twice 151 */ 152 153 writel(clk->state, clk->reg); 154 writel(clk->state, clk->reg); 155 dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state); 156 157 return 0; 158} 159 160const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = { 161 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend, 162 imx_clk_lpcg_scu_resume) 163};