-
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.
clk: sprd: add divider clock support
This is a feature that can also be found in sprd composite clocks, provide a bunch of helpers that can be reused later on. 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
ab73cf2
commit e3f05d3
Showing
3 changed files
with
166 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
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,90 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// | ||
// Spreadtrum divider clock driver | ||
// | ||
// Copyright (C) 2017 Spreadtrum, Inc. | ||
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com> | ||
|
||
#include <linux/clk-provider.h> | ||
|
||
#include "div.h" | ||
|
||
long sprd_div_helper_round_rate(struct sprd_clk_common *common, | ||
const struct sprd_div_internal *div, | ||
unsigned long rate, | ||
unsigned long *parent_rate) | ||
{ | ||
return divider_round_rate(&common->hw, rate, parent_rate, | ||
NULL, div->width, 0); | ||
} | ||
EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate); | ||
|
||
static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate, | ||
unsigned long *parent_rate) | ||
{ | ||
struct sprd_div *cd = hw_to_sprd_div(hw); | ||
|
||
return sprd_div_helper_round_rate(&cd->common, &cd->div, | ||
rate, parent_rate); | ||
} | ||
|
||
unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, | ||
const struct sprd_div_internal *div, | ||
unsigned long parent_rate) | ||
{ | ||
unsigned long val; | ||
unsigned int reg; | ||
|
||
regmap_read(common->regmap, common->reg, ®); | ||
val = reg >> div->shift; | ||
val &= (1 << div->width) - 1; | ||
|
||
return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0); | ||
} | ||
EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate); | ||
|
||
static unsigned long sprd_div_recalc_rate(struct clk_hw *hw, | ||
unsigned long parent_rate) | ||
{ | ||
struct sprd_div *cd = hw_to_sprd_div(hw); | ||
|
||
return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate); | ||
} | ||
|
||
int sprd_div_helper_set_rate(const struct sprd_clk_common *common, | ||
const struct sprd_div_internal *div, | ||
unsigned long rate, | ||
unsigned long parent_rate) | ||
{ | ||
unsigned long val; | ||
unsigned int reg; | ||
|
||
val = divider_get_val(rate, parent_rate, NULL, | ||
div->width, 0); | ||
|
||
regmap_read(common->regmap, common->reg, ®); | ||
reg &= ~GENMASK(div->width + div->shift - 1, div->shift); | ||
|
||
regmap_write(common->regmap, common->reg, | ||
reg | (val << div->shift)); | ||
|
||
return 0; | ||
|
||
} | ||
EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate); | ||
|
||
static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate, | ||
unsigned long parent_rate) | ||
{ | ||
struct sprd_div *cd = hw_to_sprd_div(hw); | ||
|
||
return sprd_div_helper_set_rate(&cd->common, &cd->div, | ||
rate, parent_rate); | ||
} | ||
|
||
const struct clk_ops sprd_div_ops = { | ||
.recalc_rate = sprd_div_recalc_rate, | ||
.round_rate = sprd_div_round_rate, | ||
.set_rate = sprd_div_set_rate, | ||
}; | ||
EXPORT_SYMBOL_GPL(sprd_div_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,75 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// | ||
// Spreadtrum divider clock driver | ||
// | ||
// Copyright (C) 2017 Spreadtrum, Inc. | ||
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com> | ||
|
||
#ifndef _SPRD_DIV_H_ | ||
#define _SPRD_DIV_H_ | ||
|
||
#include "common.h" | ||
|
||
/** | ||
* struct sprd_div_internal - Internal divider description | ||
* @shift: Bit offset of the divider in its register | ||
* @width: Width of the divider field in its register | ||
* | ||
* That structure represents a single divider, and is meant to be | ||
* embedded in other structures representing the various clock | ||
* classes. | ||
*/ | ||
struct sprd_div_internal { | ||
u8 shift; | ||
u8 width; | ||
}; | ||
|
||
#define _SPRD_DIV_CLK(_shift, _width) \ | ||
{ \ | ||
.shift = _shift, \ | ||
.width = _width, \ | ||
} | ||
|
||
struct sprd_div { | ||
struct sprd_div_internal div; | ||
struct sprd_clk_common common; | ||
}; | ||
|
||
#define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \ | ||
_shift, _width, _flags) \ | ||
struct sprd_div _struct = { \ | ||
.div = _SPRD_DIV_CLK(_shift, _width), \ | ||
.common = { \ | ||
.regmap = NULL, \ | ||
.reg = _reg, \ | ||
.hw.init = CLK_HW_INIT(_name, \ | ||
_parent, \ | ||
&sprd_div_ops, \ | ||
_flags), \ | ||
} \ | ||
} | ||
|
||
static inline struct sprd_div *hw_to_sprd_div(const struct clk_hw *hw) | ||
{ | ||
struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); | ||
|
||
return container_of(common, struct sprd_div, common); | ||
} | ||
|
||
long sprd_div_helper_round_rate(struct sprd_clk_common *common, | ||
const struct sprd_div_internal *div, | ||
unsigned long rate, | ||
unsigned long *parent_rate); | ||
|
||
unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, | ||
const struct sprd_div_internal *div, | ||
unsigned long parent_rate); | ||
|
||
int sprd_div_helper_set_rate(const struct sprd_clk_common *common, | ||
const struct sprd_div_internal *div, | ||
unsigned long rate, | ||
unsigned long parent_rate); | ||
|
||
extern const struct clk_ops sprd_div_ops; | ||
|
||
#endif /* _SPRD_DIV_H_ */ |