forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.3 KiB
91 lines
2.3 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
// |
|
// Spreadtrum divider clock driver |
|
// |
|
// Copyright (C) 2017 Spreadtrum, Inc. |
|
// Author: Chunyan Zhang <[email protected]> |
|
|
|
#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, |
|
div->width); |
|
} |
|
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);
|
|
|