xref: /linux/drivers/clk/imx/clk-lpcg-scu.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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/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>
15 
16 #include "clk-scu.h"
17 
18 static DEFINE_SPINLOCK(imx_lpcg_scu_lock);
19 
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)
23 
24 /*
25  * struct clk_lpcg_scu - Description of LPCG clock
26  *
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
31  *
32  * This structure describes one LPCG clock
33  */
34 struct clk_lpcg_scu {
35 	struct clk_hw hw;
36 	void __iomem *reg;
37 	u8 bit_idx;
38 	bool hw_gate;
39 
40 	/* for state save&restore */
41 	u32 state;
42 };
43 
44 #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
45 
46 /* e10858 -LPCG clock gating register synchronization errata */
47 static void lpcg_e10858_writel(unsigned long rate, void __iomem *reg, u32 val)
48 {
49 	writel(val, reg);
50 
51 	if (rate >= 24 * HZ_PER_MHZ || rate == 0) {
52 		/*
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.
58 		 */
59 		readl(reg);
60 	} else {
61 		/*
62 		 * For clocks running below 24MHz, wait a minimum of
63 		 * 4 clock cycles.
64 		 */
65 		ndelay(4 * (DIV_ROUND_UP(1000 * HZ_PER_MHZ, rate)));
66 	}
67 }
68 
69 static int clk_lpcg_scu_enable(struct clk_hw *hw)
70 {
71 	struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
72 	unsigned long flags;
73 	u32 reg, val;
74 
75 	spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
76 
77 	reg = readl_relaxed(clk->reg);
78 	reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
79 
80 	val = CLK_GATE_SCU_LPCG_SW_SEL;
81 	if (clk->hw_gate)
82 		val |= CLK_GATE_SCU_LPCG_HW_SEL;
83 
84 	reg |= val << clk->bit_idx;
85 
86 	lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg);
87 
88 	spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
89 
90 	return 0;
91 }
92 
93 static void clk_lpcg_scu_disable(struct clk_hw *hw)
94 {
95 	struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
96 	unsigned long flags;
97 	u32 reg;
98 
99 	spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
100 
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);
104 
105 	spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
106 }
107 
108 static const struct clk_ops clk_lpcg_scu_ops = {
109 	.enable = clk_lpcg_scu_enable,
110 	.disable = clk_lpcg_scu_disable,
111 };
112 
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)
116 {
117 	struct clk_lpcg_scu *clk;
118 	struct clk_init_data init;
119 	struct clk_hw *hw;
120 	int ret;
121 
122 	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
123 	if (!clk)
124 		return ERR_PTR(-ENOMEM);
125 
126 	clk->reg = reg;
127 	clk->bit_idx = bit_idx;
128 	clk->hw_gate = hw_gate;
129 
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;
135 
136 	clk->hw.init = &init;
137 
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;
144 	}
145 
146 	if (dev)
147 		dev_set_drvdata(dev, clk);
148 
149 	return hw;
150 }
151 
152 void imx_clk_lpcg_scu_unregister(struct clk_hw *hw)
153 {
154 	struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
155 
156 	clk_hw_unregister(&clk->hw);
157 	kfree(clk);
158 }
159 
160 static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
161 {
162 	struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
163 
164 	if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
165 		return 0;
166 
167 	clk->state = readl_relaxed(clk->reg);
168 	dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
169 
170 	return 0;
171 }
172 
173 static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
174 {
175 	struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
176 
177 	if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
178 		return 0;
179 
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);
183 
184 	return 0;
185 }
186 
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)
190 };
191