-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Some clocks on the Spreadtrum's SoCs are just simple gates. Add support for those clocks. Signed-off-by: Chunyan Zhang <chunyan.zhang@spreadtrum.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
- Loading branch information
Chunyan Zhang
authored and
Stephen Boyd
committed
Dec 21, 2017
1 parent
d41f59f
commit cdb09f6
Showing
3 changed files
with
171 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
obj-$(CONFIG_SPRD_COMMON_CLK) += clk-sprd.o | ||
|
||
clk-sprd-y += common.o | ||
clk-sprd-y += gate.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// | ||
// Spreadtrum gate clock driver | ||
// | ||
// Copyright (C) 2017 Spreadtrum, Inc. | ||
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com> | ||
|
||
#include <linux/clk-provider.h> | ||
#include <linux/regmap.h> | ||
|
||
#include "gate.h" | ||
|
||
static void clk_gate_toggle(const struct sprd_gate *sg, bool en) | ||
{ | ||
const struct sprd_clk_common *common = &sg->common; | ||
unsigned int reg; | ||
bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? true : false; | ||
|
||
set ^= en; | ||
|
||
regmap_read(common->regmap, common->reg, ®); | ||
|
||
if (set) | ||
reg |= sg->enable_mask; | ||
else | ||
reg &= ~sg->enable_mask; | ||
|
||
regmap_write(common->regmap, common->reg, reg); | ||
} | ||
|
||
static void clk_sc_gate_toggle(const struct sprd_gate *sg, bool en) | ||
{ | ||
const struct sprd_clk_common *common = &sg->common; | ||
bool set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; | ||
unsigned int offset; | ||
|
||
set ^= en; | ||
|
||
/* | ||
* Each set/clear gate clock has three registers: | ||
* common->reg - base register | ||
* common->reg + offset - set register | ||
* common->reg + 2 * offset - clear register | ||
*/ | ||
offset = set ? sg->sc_offset : sg->sc_offset * 2; | ||
|
||
regmap_write(common->regmap, common->reg + offset, | ||
sg->enable_mask); | ||
} | ||
|
||
static void sprd_gate_disable(struct clk_hw *hw) | ||
{ | ||
struct sprd_gate *sg = hw_to_sprd_gate(hw); | ||
|
||
clk_gate_toggle(sg, false); | ||
} | ||
|
||
static int sprd_gate_enable(struct clk_hw *hw) | ||
{ | ||
struct sprd_gate *sg = hw_to_sprd_gate(hw); | ||
|
||
clk_gate_toggle(sg, true); | ||
|
||
return 0; | ||
} | ||
|
||
static void sprd_sc_gate_disable(struct clk_hw *hw) | ||
{ | ||
struct sprd_gate *sg = hw_to_sprd_gate(hw); | ||
|
||
clk_sc_gate_toggle(sg, false); | ||
} | ||
|
||
static int sprd_sc_gate_enable(struct clk_hw *hw) | ||
{ | ||
struct sprd_gate *sg = hw_to_sprd_gate(hw); | ||
|
||
clk_sc_gate_toggle(sg, true); | ||
|
||
return 0; | ||
} | ||
static int sprd_gate_is_enabled(struct clk_hw *hw) | ||
{ | ||
struct sprd_gate *sg = hw_to_sprd_gate(hw); | ||
struct sprd_clk_common *common = &sg->common; | ||
unsigned int reg; | ||
|
||
regmap_read(common->regmap, common->reg, ®); | ||
|
||
if (sg->flags & CLK_GATE_SET_TO_DISABLE) | ||
reg ^= sg->enable_mask; | ||
|
||
reg &= sg->enable_mask; | ||
|
||
return reg ? 1 : 0; | ||
} | ||
|
||
const struct clk_ops sprd_gate_ops = { | ||
.disable = sprd_gate_disable, | ||
.enable = sprd_gate_enable, | ||
.is_enabled = sprd_gate_is_enabled, | ||
}; | ||
EXPORT_SYMBOL_GPL(sprd_gate_ops); | ||
|
||
const struct clk_ops sprd_sc_gate_ops = { | ||
.disable = sprd_sc_gate_disable, | ||
.enable = sprd_sc_gate_enable, | ||
.is_enabled = sprd_gate_is_enabled, | ||
}; | ||
EXPORT_SYMBOL_GPL(sprd_sc_gate_ops); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// | ||
// Spreadtrum gate clock driver | ||
// | ||
// Copyright (C) 2017 Spreadtrum, Inc. | ||
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com> | ||
|
||
#ifndef _SPRD_GATE_H_ | ||
#define _SPRD_GATE_H_ | ||
|
||
#include "common.h" | ||
|
||
struct sprd_gate { | ||
u32 enable_mask; | ||
u16 flags; | ||
u16 sc_offset; | ||
|
||
struct sprd_clk_common common; | ||
}; | ||
|
||
#define SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \ | ||
_enable_mask, _flags, _gate_flags, _ops) \ | ||
struct sprd_gate _struct = { \ | ||
.enable_mask = _enable_mask, \ | ||
.sc_offset = _sc_offset, \ | ||
.flags = _gate_flags, \ | ||
.common = { \ | ||
.regmap = NULL, \ | ||
.reg = _reg, \ | ||
.hw.init = CLK_HW_INIT(_name, \ | ||
_parent, \ | ||
_ops, \ | ||
_flags), \ | ||
} \ | ||
} | ||
|
||
#define SPRD_GATE_CLK(_struct, _name, _parent, _reg, \ | ||
_enable_mask, _flags, _gate_flags) \ | ||
SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, 0, \ | ||
_enable_mask, _flags, _gate_flags, \ | ||
&sprd_gate_ops) | ||
|
||
#define SPRD_SC_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \ | ||
_enable_mask, _flags, _gate_flags) \ | ||
SPRD_SC_GATE_CLK_OPS(_struct, _name, _parent, _reg, _sc_offset, \ | ||
_enable_mask, _flags, _gate_flags, \ | ||
&sprd_sc_gate_ops) | ||
|
||
static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw) | ||
{ | ||
struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); | ||
|
||
return container_of(common, struct sprd_gate, common); | ||
} | ||
|
||
extern const struct clk_ops sprd_gate_ops; | ||
extern const struct clk_ops sprd_sc_gate_ops; | ||
|
||
#endif /* _SPRD_GATE_H_ */ |