xref: /openbmc/linux/drivers/clk/sprd/gate.c (revision 8b4f6b8d)
1cdb09f67SChunyan Zhang // SPDX-License-Identifier: GPL-2.0
2cdb09f67SChunyan Zhang //
3cdb09f67SChunyan Zhang // Spreadtrum gate clock driver
4cdb09f67SChunyan Zhang //
5cdb09f67SChunyan Zhang // Copyright (C) 2017 Spreadtrum, Inc.
6cdb09f67SChunyan Zhang // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
7cdb09f67SChunyan Zhang 
8cdb09f67SChunyan Zhang #include <linux/clk-provider.h>
9cdb09f67SChunyan Zhang #include <linux/regmap.h>
10cdb09f67SChunyan Zhang 
11cdb09f67SChunyan Zhang #include "gate.h"
12cdb09f67SChunyan Zhang 
clk_gate_toggle(const struct sprd_gate * sg,bool en)13cdb09f67SChunyan Zhang static void clk_gate_toggle(const struct sprd_gate *sg, bool en)
14cdb09f67SChunyan Zhang {
15cdb09f67SChunyan Zhang 	const struct sprd_clk_common *common = &sg->common;
16cdb09f67SChunyan Zhang 	unsigned int reg;
17cdb09f67SChunyan Zhang 	bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? true : false;
18cdb09f67SChunyan Zhang 
19cdb09f67SChunyan Zhang 	set ^= en;
20cdb09f67SChunyan Zhang 
21cdb09f67SChunyan Zhang 	regmap_read(common->regmap, common->reg, &reg);
22cdb09f67SChunyan Zhang 
23cdb09f67SChunyan Zhang 	if (set)
24cdb09f67SChunyan Zhang 		reg |= sg->enable_mask;
25cdb09f67SChunyan Zhang 	else
26cdb09f67SChunyan Zhang 		reg &= ~sg->enable_mask;
27cdb09f67SChunyan Zhang 
28cdb09f67SChunyan Zhang 	regmap_write(common->regmap, common->reg, reg);
29cdb09f67SChunyan Zhang }
30cdb09f67SChunyan Zhang 
clk_sc_gate_toggle(const struct sprd_gate * sg,bool en)31cdb09f67SChunyan Zhang static void clk_sc_gate_toggle(const struct sprd_gate *sg, bool en)
32cdb09f67SChunyan Zhang {
33cdb09f67SChunyan Zhang 	const struct sprd_clk_common *common = &sg->common;
34cdb09f67SChunyan Zhang 	bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
35cdb09f67SChunyan Zhang 	unsigned int offset;
36cdb09f67SChunyan Zhang 
37cdb09f67SChunyan Zhang 	set ^= en;
38cdb09f67SChunyan Zhang 
39cdb09f67SChunyan Zhang 	/*
40cdb09f67SChunyan Zhang 	 * Each set/clear gate clock has three registers:
41cdb09f67SChunyan Zhang 	 * common->reg			- base register
42cdb09f67SChunyan Zhang 	 * common->reg + offset		- set register
43cdb09f67SChunyan Zhang 	 * common->reg + 2 * offset	- clear register
44cdb09f67SChunyan Zhang 	 */
45cdb09f67SChunyan Zhang 	offset = set ? sg->sc_offset : sg->sc_offset * 2;
46cdb09f67SChunyan Zhang 
47cdb09f67SChunyan Zhang 	regmap_write(common->regmap, common->reg + offset,
48cdb09f67SChunyan Zhang 			  sg->enable_mask);
49cdb09f67SChunyan Zhang }
50cdb09f67SChunyan Zhang 
sprd_gate_disable(struct clk_hw * hw)51cdb09f67SChunyan Zhang static void sprd_gate_disable(struct clk_hw *hw)
52cdb09f67SChunyan Zhang {
53cdb09f67SChunyan Zhang 	struct sprd_gate *sg = hw_to_sprd_gate(hw);
54cdb09f67SChunyan Zhang 
55cdb09f67SChunyan Zhang 	clk_gate_toggle(sg, false);
56cdb09f67SChunyan Zhang }
57cdb09f67SChunyan Zhang 
sprd_gate_enable(struct clk_hw * hw)58cdb09f67SChunyan Zhang static int sprd_gate_enable(struct clk_hw *hw)
59cdb09f67SChunyan Zhang {
60cdb09f67SChunyan Zhang 	struct sprd_gate *sg = hw_to_sprd_gate(hw);
61cdb09f67SChunyan Zhang 
62cdb09f67SChunyan Zhang 	clk_gate_toggle(sg, true);
63cdb09f67SChunyan Zhang 
64cdb09f67SChunyan Zhang 	return 0;
65cdb09f67SChunyan Zhang }
66cdb09f67SChunyan Zhang 
sprd_sc_gate_disable(struct clk_hw * hw)67cdb09f67SChunyan Zhang static void sprd_sc_gate_disable(struct clk_hw *hw)
68cdb09f67SChunyan Zhang {
69cdb09f67SChunyan Zhang 	struct sprd_gate *sg = hw_to_sprd_gate(hw);
70cdb09f67SChunyan Zhang 
71cdb09f67SChunyan Zhang 	clk_sc_gate_toggle(sg, false);
72cdb09f67SChunyan Zhang }
73cdb09f67SChunyan Zhang 
sprd_sc_gate_enable(struct clk_hw * hw)74cdb09f67SChunyan Zhang static int sprd_sc_gate_enable(struct clk_hw *hw)
75cdb09f67SChunyan Zhang {
76cdb09f67SChunyan Zhang 	struct sprd_gate *sg = hw_to_sprd_gate(hw);
77cdb09f67SChunyan Zhang 
78cdb09f67SChunyan Zhang 	clk_sc_gate_toggle(sg, true);
79cdb09f67SChunyan Zhang 
80cdb09f67SChunyan Zhang 	return 0;
81cdb09f67SChunyan Zhang }
82187e5cd2SXiaolong Zhang 
sprd_pll_sc_gate_prepare(struct clk_hw * hw)83187e5cd2SXiaolong Zhang static int sprd_pll_sc_gate_prepare(struct clk_hw *hw)
84187e5cd2SXiaolong Zhang {
85187e5cd2SXiaolong Zhang 	struct sprd_gate *sg = hw_to_sprd_gate(hw);
86187e5cd2SXiaolong Zhang 
87187e5cd2SXiaolong Zhang 	clk_sc_gate_toggle(sg, true);
88187e5cd2SXiaolong Zhang 	udelay(sg->udelay);
89187e5cd2SXiaolong Zhang 
90187e5cd2SXiaolong Zhang 	return 0;
91187e5cd2SXiaolong Zhang }
92187e5cd2SXiaolong Zhang 
sprd_gate_is_enabled(struct clk_hw * hw)93cdb09f67SChunyan Zhang static int sprd_gate_is_enabled(struct clk_hw *hw)
94cdb09f67SChunyan Zhang {
95cdb09f67SChunyan Zhang 	struct sprd_gate *sg = hw_to_sprd_gate(hw);
96cdb09f67SChunyan Zhang 	struct sprd_clk_common *common = &sg->common;
978b4f6b8dSChunyan Zhang 	struct clk_hw *parent;
98cdb09f67SChunyan Zhang 	unsigned int reg;
99cdb09f67SChunyan Zhang 
1008b4f6b8dSChunyan Zhang 	if (sg->flags & SPRD_GATE_NON_AON) {
1018b4f6b8dSChunyan Zhang 		parent = clk_hw_get_parent(hw);
1028b4f6b8dSChunyan Zhang 		if (!parent || !clk_hw_is_enabled(parent))
1038b4f6b8dSChunyan Zhang 			return 0;
1048b4f6b8dSChunyan Zhang 	}
1058b4f6b8dSChunyan Zhang 
106cdb09f67SChunyan Zhang 	regmap_read(common->regmap, common->reg, &reg);
107cdb09f67SChunyan Zhang 
108cdb09f67SChunyan Zhang 	if (sg->flags & CLK_GATE_SET_TO_DISABLE)
109cdb09f67SChunyan Zhang 		reg ^= sg->enable_mask;
110cdb09f67SChunyan Zhang 
111cdb09f67SChunyan Zhang 	reg &= sg->enable_mask;
112cdb09f67SChunyan Zhang 
113cdb09f67SChunyan Zhang 	return reg ? 1 : 0;
114cdb09f67SChunyan Zhang }
115cdb09f67SChunyan Zhang 
116cdb09f67SChunyan Zhang const struct clk_ops sprd_gate_ops = {
117cdb09f67SChunyan Zhang 	.disable	= sprd_gate_disable,
118cdb09f67SChunyan Zhang 	.enable		= sprd_gate_enable,
119cdb09f67SChunyan Zhang 	.is_enabled	= sprd_gate_is_enabled,
120cdb09f67SChunyan Zhang };
121cdb09f67SChunyan Zhang EXPORT_SYMBOL_GPL(sprd_gate_ops);
122cdb09f67SChunyan Zhang 
123cdb09f67SChunyan Zhang const struct clk_ops sprd_sc_gate_ops = {
124cdb09f67SChunyan Zhang 	.disable	= sprd_sc_gate_disable,
125cdb09f67SChunyan Zhang 	.enable		= sprd_sc_gate_enable,
126cdb09f67SChunyan Zhang 	.is_enabled	= sprd_gate_is_enabled,
127cdb09f67SChunyan Zhang };
128cdb09f67SChunyan Zhang EXPORT_SYMBOL_GPL(sprd_sc_gate_ops);
129cdb09f67SChunyan Zhang 
130187e5cd2SXiaolong Zhang const struct clk_ops sprd_pll_sc_gate_ops = {
131187e5cd2SXiaolong Zhang 	.unprepare	= sprd_sc_gate_disable,
132187e5cd2SXiaolong Zhang 	.prepare	= sprd_pll_sc_gate_prepare,
133187e5cd2SXiaolong Zhang 	.is_enabled	= sprd_gate_is_enabled,
134187e5cd2SXiaolong Zhang };
135187e5cd2SXiaolong Zhang EXPORT_SYMBOL_GPL(sprd_pll_sc_gate_ops);
136