Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / clk / imx / clk-lpcg-scu.c
blob6376557a3c3d03130ca8168a6cb69eda73c43abe
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright 2018 NXP
4 * Dong Aisheng <aisheng.dong@nxp.com>
5 */
7 #include <linux/bits.h>
8 #include <linux/clk-provider.h>
9 #include <linux/delay.h>
10 #include <linux/err.h>
11 #include <linux/io.h>
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
14 #include <linux/units.h>
16 #include "clk-scu.h"
18 static DEFINE_SPINLOCK(imx_lpcg_scu_lock);
20 #define CLK_GATE_SCU_LPCG_MASK 0x3
21 #define CLK_GATE_SCU_LPCG_HW_SEL BIT(0)
22 #define CLK_GATE_SCU_LPCG_SW_SEL BIT(1)
25 * struct clk_lpcg_scu - Description of LPCG clock
27 * @hw: clk_hw of this LPCG
28 * @reg: register of this LPCG clock
29 * @bit_idx: bit index of this LPCG clock
30 * @hw_gate: HW auto gate enable
32 * This structure describes one LPCG clock
34 struct clk_lpcg_scu {
35 struct clk_hw hw;
36 void __iomem *reg;
37 u8 bit_idx;
38 bool hw_gate;
40 /* for state save&restore */
41 u32 state;
44 #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
46 /* e10858 -LPCG clock gating register synchronization errata */
47 static void lpcg_e10858_writel(unsigned long rate, void __iomem *reg, u32 val)
49 writel(val, reg);
51 if (rate >= 24 * HZ_PER_MHZ || rate == 0) {
53 * The time taken to access the LPCG registers from the AP core
54 * through the interconnect is longer than the minimum delay
55 * of 4 clock cycles required by the errata.
56 * Adding a readl will provide sufficient delay to prevent
57 * back-to-back writes.
59 readl(reg);
60 } else {
62 * For clocks running below 24MHz, wait a minimum of
63 * 4 clock cycles.
65 ndelay(4 * (DIV_ROUND_UP(1000 * HZ_PER_MHZ, rate)));
69 static int clk_lpcg_scu_enable(struct clk_hw *hw)
71 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
72 unsigned long flags;
73 u32 reg, val;
75 spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
77 reg = readl_relaxed(clk->reg);
78 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
80 val = CLK_GATE_SCU_LPCG_SW_SEL;
81 if (clk->hw_gate)
82 val |= CLK_GATE_SCU_LPCG_HW_SEL;
84 reg |= val << clk->bit_idx;
86 lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg);
88 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
90 return 0;
93 static void clk_lpcg_scu_disable(struct clk_hw *hw)
95 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
96 unsigned long flags;
97 u32 reg;
99 spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
101 reg = readl_relaxed(clk->reg);
102 reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
103 lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg);
105 spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
108 static const struct clk_ops clk_lpcg_scu_ops = {
109 .enable = clk_lpcg_scu_enable,
110 .disable = clk_lpcg_scu_disable,
113 struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
114 const char *parent_name, unsigned long flags,
115 void __iomem *reg, u8 bit_idx, bool hw_gate)
117 struct clk_lpcg_scu *clk;
118 struct clk_init_data init;
119 struct clk_hw *hw;
120 int ret;
122 clk = kzalloc(sizeof(*clk), GFP_KERNEL);
123 if (!clk)
124 return ERR_PTR(-ENOMEM);
126 clk->reg = reg;
127 clk->bit_idx = bit_idx;
128 clk->hw_gate = hw_gate;
130 init.name = name;
131 init.ops = &clk_lpcg_scu_ops;
132 init.flags = CLK_SET_RATE_PARENT | flags;
133 init.parent_names = parent_name ? &parent_name : NULL;
134 init.num_parents = parent_name ? 1 : 0;
136 clk->hw.init = &init;
138 hw = &clk->hw;
139 ret = clk_hw_register(dev, hw);
140 if (ret) {
141 kfree(clk);
142 hw = ERR_PTR(ret);
143 return hw;
146 if (dev)
147 dev_set_drvdata(dev, clk);
149 return hw;
152 void imx_clk_lpcg_scu_unregister(struct clk_hw *hw)
154 struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
156 clk_hw_unregister(&clk->hw);
157 kfree(clk);
160 static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
162 struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
164 if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
165 return 0;
167 clk->state = readl_relaxed(clk->reg);
168 dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
170 return 0;
173 static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
175 struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
177 if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
178 return 0;
180 writel(clk->state, clk->reg);
181 lpcg_e10858_writel(0, clk->reg, clk->state);
182 dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
184 return 0;
187 const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = {
188 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend,
189 imx_clk_lpcg_scu_resume)