mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
Allwinner clock changes for 7.3
Some cleanups to the Allwinner clock driver library and support for the Allwinner A733 RTC clocks added. -----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEE2nN1m/hhnkhOWjtHOJpUIZwPJDAFAmp4YtEQHHdlbnNAa2Vy bmVsLm9yZwAKCRA4mlQhnA8kMOIFEADkvYPkegyGZWpVRlRuvV1mzE0Uc16Ueo4G jisA5FSjOOjR1v8JcG16gvX0uvllWBTyHRQUJ/4VRexedRcL/QQewID7kZ4Ebh+M BGuSbEHiPUqLTDO0j9mNE5Cu6fmIvrMSCyffxFqCbmhfvb5XiCIPeNtA9Q9V18dK UMSIh9NUU2JKINnJJnBpL/3akPxUDUEBRx2MfuW85hb/0irsWaYAGEToFLNBYBhf r5QUcXnrMgV7mvFPLHjG0TytPWRDTiNR/aXlXtPuLPx7TgTuKMSwt2b7mGv7+kz0 rPooPw48TfpFVoGmBx22FmD4BJuHyi8BUTQfWluSpw+MZpwmURYDhfQiyPjPASAC nSDWIFL5s0i/R2Gtql+sbqpY3zDADxta/jRsUG/0azEALjcVNNuWWr9f/h0QxiDB MRLrUFKRx6TwQBSgyMRkk43wA0pWKn9koZaB1FFu3if03heRk/Qt/YOcg7mp0xP7 EW0PZfKq3GXBWtcQ0UlC6jOzF+X0MFWlNCOSxkNR460H+K2jQdMaU+rUx0N1qXnA qN9uoMzukXd9x6GazWDA4tOfbc6fYSQ8R40EQNLsrjCaYq6gf/ED1V83D60/2TnM 8rpxDagwTLndtT+oO2DkCEk60XVpnRodkyzLXlQ+wHNF0FjddDA/I29QLAcN5bvl kjsWWCFtTw== =1HWO -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAmp8DggUHHN3Ym95ZEBj aHJvbWl1bS5vcmcACgkQrQKIl8bklSXnBQ//fyZ0fFm5sAO5Dl4/d52hbv4i4SLa Wv/R+dEbrHrMlU5Vd1WSHImf0XqG97MZNlGlNor3fcM98Z9bQo3NZFOGTUkjJs6W yJGs/68mJpZvfqYHBXBk+PlYBDD7ULNOAgz8TSsrjuLS0ehpvmI40eYhcczqZLqe wupz/upveK81a9qDQfpfrIF7pb5Xf57YTQnkFRJkrL7Jyhu6+jSp0YhnqXpTOz+w RtPqHGSl+kquLPGgmzZmDS2lUZfRr/MrEbP2LsEhoqK2rBLQGnoYYtxlBBDKgtdc VEjpsp3dk8TnckgAZZF+Az13PoOYIXXP6EoSez+V5UANGCXjxB+Xh1JNdGmsYF5+ awI6fjlND8xKsGGz5tKMvZXuqf1a+cF8sqqI0cJ6roLN7DUQEc2lSPN5Ao6eaw+A ljV7hUe/7RyIS1rvJtMVy60g6+9hqGPtQqqM8xV+2brCguL/sj6aW16P9ZEy+wvv LLJev2Ojt0I2JCwyYkDqCX8EefNfZGFAVe3+fUUunNHahQjXlCv1IWe6vqbI78dR uTWP9n3ohTozg4PNDSxjOZxQaueGL6ZTfBwLTrXk6tVo4Q4pawMH0q+VIvr3Hzc7 ifOK5/NN6oq/dAfXIukRFBXdGSGRyMNt7sYfq9r2CxGP/9NqeF4g9H2Uxotu0q5C YyLtNcH2+pTsUUE= =3i3v -----END PGP SIGNATURE----- Merge tag 'sunxi-clk-for-7.3' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux into clk-allwinner Pull Allwinner clk driver updates from Chen-Yu Tsai: Some cleanups to the Allwinner clock driver library and support for the Allwinner A733 RTC clocks added. * tag 'sunxi-clk-for-7.3' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux: clk: sunxi-ng: sun6i-rtc: add a733 support clk: sunxi-ng: sun6i-rtc: split main oscillator div and gate clk: sunxi-ng: div: add read-only operation support clk: sunxi-ng: mux: fix determine helper rate propagation clk: sunxi-ng: mux: remove unneeded export clk: sunxi-ng: sun6i-rtc: Add feature bit for IOSC calibration clk: sunxi-ng: sun6i-rtc: clean up DT usage clk: sunxi-ng: fix ccu probe clock unregister on error dt-bindings: rtc: sun6i: add sun60i-a733 support dt-bindings: rtc: sun6i: no clock-output-names on h616/r329
This commit is contained in:
commit
d8a8d206a7
|
|
@ -33,6 +33,7 @@ properties:
|
|||
- enum:
|
||||
- allwinner,sun20i-d1-rtc
|
||||
- allwinner,sun55i-a523-rtc
|
||||
- allwinner,sun60i-a733-rtc
|
||||
- const: allwinner,sun50i-r329-rtc
|
||||
|
||||
reg:
|
||||
|
|
@ -175,6 +176,18 @@ allOf:
|
|||
interrupts:
|
||||
minItems: 2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun50i-h616-rtc
|
||||
- allwinner,sun50i-r329-rtc
|
||||
|
||||
then:
|
||||
properties:
|
||||
clock-output-names: false
|
||||
|
||||
required:
|
||||
- "#clock-cells"
|
||||
- compatible
|
||||
|
|
|
|||
|
|
@ -44,16 +44,20 @@
|
|||
#define DCXO_CTRL_REG 0x160
|
||||
#define DCXO_CTRL_CLK16M_RC_EN BIT(0)
|
||||
|
||||
#define DCXO_GATING_REG 0x16c
|
||||
|
||||
#define CLK_NUMBER_NO_GATES (CLK_OSC24M_32K_DIV + 1)
|
||||
|
||||
struct sun6i_rtc_match_data {
|
||||
bool have_ext_osc32k : 1;
|
||||
bool have_iosc_calibration : 1;
|
||||
bool have_dcxo_status : 1;
|
||||
bool have_phy_ref_gates : 1;
|
||||
bool rtc_32k_single_parent : 1;
|
||||
const struct clk_parent_data *osc32k_fanout_parents;
|
||||
u8 osc32k_fanout_nparents;
|
||||
};
|
||||
|
||||
static bool have_iosc_calibration;
|
||||
|
||||
static int ccu_iosc_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct ccu_common *cm = hw_to_ccu_common(hw);
|
||||
|
|
@ -80,7 +84,7 @@ static unsigned long ccu_iosc_recalc_rate(struct clk_hw *hw,
|
|||
{
|
||||
struct ccu_common *cm = hw_to_ccu_common(hw);
|
||||
|
||||
if (have_iosc_calibration) {
|
||||
if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
|
||||
u32 reg = readl(cm->base + IOSC_CLK_CALI_REG);
|
||||
|
||||
/*
|
||||
|
|
@ -119,7 +123,7 @@ static int ccu_iosc_32k_prepare(struct clk_hw *hw)
|
|||
struct ccu_common *cm = hw_to_ccu_common(hw);
|
||||
u32 val;
|
||||
|
||||
if (!have_iosc_calibration)
|
||||
if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
|
||||
return 0;
|
||||
|
||||
val = readl(cm->base + IOSC_CLK_CALI_REG);
|
||||
|
|
@ -134,7 +138,7 @@ static void ccu_iosc_32k_unprepare(struct clk_hw *hw)
|
|||
struct ccu_common *cm = hw_to_ccu_common(hw);
|
||||
u32 val;
|
||||
|
||||
if (!have_iosc_calibration)
|
||||
if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
|
||||
return;
|
||||
|
||||
val = readl(cm->base + IOSC_CLK_CALI_REG);
|
||||
|
|
@ -148,7 +152,7 @@ static unsigned long ccu_iosc_32k_recalc_rate(struct clk_hw *hw,
|
|||
struct ccu_common *cm = hw_to_ccu_common(hw);
|
||||
u32 val;
|
||||
|
||||
if (have_iosc_calibration) {
|
||||
if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
|
||||
val = readl(cm->base + IOSC_CLK_CALI_REG);
|
||||
|
||||
/* Assume the calibrated 32k clock is accurate. */
|
||||
|
|
@ -167,7 +171,7 @@ static unsigned long ccu_iosc_32k_recalc_accuracy(struct clk_hw *hw,
|
|||
struct ccu_common *cm = hw_to_ccu_common(hw);
|
||||
u32 val;
|
||||
|
||||
if (have_iosc_calibration) {
|
||||
if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
|
||||
val = readl(cm->base + IOSC_CLK_CALI_REG);
|
||||
|
||||
/* Assume the calibrated 32k clock is accurate. */
|
||||
|
|
@ -191,10 +195,8 @@ static struct ccu_common iosc_32k_clk = {
|
|||
CLK_GET_RATE_NOCACHE),
|
||||
};
|
||||
|
||||
static const struct clk_hw *ext_osc32k[] = { NULL }; /* updated during probe */
|
||||
|
||||
static SUNXI_CCU_GATE_HWS(ext_osc32k_gate_clk, "ext-osc32k-gate",
|
||||
ext_osc32k, 0x0, BIT(4), 0);
|
||||
static SUNXI_CCU_GATE_FW(ext_osc32k_gate_clk, "ext-osc32k-gate",
|
||||
"ext-osc32k", 0x0, BIT(4), 0);
|
||||
|
||||
static const struct clk_hw *osc32k_parents[] = {
|
||||
&iosc_32k_clk.hw,
|
||||
|
|
@ -217,22 +219,50 @@ static struct ccu_mux osc32k_clk = {
|
|||
},
|
||||
};
|
||||
|
||||
/* This falls back to the global name for fwnodes without a named reference. */
|
||||
/*
|
||||
* This falls back to the global name for fwnodes without a named reference.
|
||||
* NOTE: osc24M name might be misleading the oscillator could also be a 26MHz
|
||||
* or a 19.2MHz one starting with the a733. The original name is kept anyway
|
||||
* in case anything is relying on it.
|
||||
*/
|
||||
static const struct clk_parent_data osc24M[] = {
|
||||
{ .fw_name = "hosc", .name = "osc24M" }
|
||||
};
|
||||
|
||||
static struct ccu_gate osc24M_32k_clk = {
|
||||
.enable = BIT(16),
|
||||
static struct clk_fixed_factor osc24M_32k_div_clk = {
|
||||
.mult = 1,
|
||||
.div = 750,
|
||||
.hw.init = CLK_HW_INIT_PARENTS_DATA("osc24M-32k-div",
|
||||
osc24M,
|
||||
&clk_fixed_factor_ops,
|
||||
0),
|
||||
};
|
||||
|
||||
static struct clk_div_table osc24M_32k_div_a733_table[] = {
|
||||
{ .val = 0, .div = 732 },
|
||||
{ .val = 1, .div = 586 },
|
||||
{ .val = 2, .div = 793 },
|
||||
{ .val = 3, .div = 732 },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
static struct ccu_div osc24M_32k_div_a733_clk = {
|
||||
.enable = BIT(1),
|
||||
.div = _SUNXI_CCU_DIV_TABLE_FLAGS(14, 2,
|
||||
osc24M_32k_div_a733_table,
|
||||
CLK_DIVIDER_READ_ONLY),
|
||||
.common = {
|
||||
.reg = LOSC_OUT_GATING_REG,
|
||||
.prediv = 750,
|
||||
.features = CCU_FEATURE_ALL_PREDIV,
|
||||
.hw.init = CLK_HW_INIT_PARENTS_DATA("osc24M-32k", osc24M,
|
||||
&ccu_gate_ops, 0),
|
||||
.reg = DCXO_CTRL_REG,
|
||||
.hw.init = CLK_HW_INIT_PARENTS_DATA("osc24M-32k-div",
|
||||
osc24M,
|
||||
&ccu_rodiv_ops,
|
||||
0),
|
||||
},
|
||||
};
|
||||
|
||||
static SUNXI_CCU_GATE(osc24M_32k_clk, "osc24M-32k", "osc24M-32k-div",
|
||||
LOSC_OUT_GATING_REG, BIT(16), 0);
|
||||
|
||||
static const struct clk_hw *rtc_32k_parents[] = {
|
||||
&osc32k_clk.common.hw,
|
||||
&osc24M_32k_clk.common.hw
|
||||
|
|
@ -270,6 +300,15 @@ static struct ccu_mux osc32k_fanout_clk = {
|
|||
},
|
||||
};
|
||||
|
||||
static SUNXI_CCU_GATE_FW(hosc_serdes1_clk, "hosc-serdes1", "hosc",
|
||||
DCXO_GATING_REG, BIT(5), 0);
|
||||
static SUNXI_CCU_GATE_FW(hosc_serdes0_clk, "hosc-serdes0", "hosc",
|
||||
DCXO_GATING_REG, BIT(4), 0);
|
||||
static SUNXI_CCU_GATE_FW(hosc_hdmi_clk, "hosc-hdmi", "hosc",
|
||||
DCXO_GATING_REG, BIT(1), 0);
|
||||
static SUNXI_CCU_GATE_FW(hosc_ufs_clk, "hosc-ufs", "hosc",
|
||||
DCXO_GATING_REG, BIT(0), 0);
|
||||
|
||||
static struct ccu_common *sun6i_rtc_ccu_clks[] = {
|
||||
&iosc_clk,
|
||||
&iosc_32k_clk,
|
||||
|
|
@ -278,6 +317,11 @@ static struct ccu_common *sun6i_rtc_ccu_clks[] = {
|
|||
&osc24M_32k_clk.common,
|
||||
&rtc_32k_clk.common,
|
||||
&osc32k_fanout_clk.common,
|
||||
&osc24M_32k_div_a733_clk.common,
|
||||
&hosc_serdes1_clk.common,
|
||||
&hosc_serdes0_clk.common,
|
||||
&hosc_hdmi_clk.common,
|
||||
&hosc_ufs_clk.common,
|
||||
};
|
||||
|
||||
static struct clk_hw_onecell_data sun6i_rtc_ccu_hw_clks = {
|
||||
|
|
@ -290,6 +334,11 @@ static struct clk_hw_onecell_data sun6i_rtc_ccu_hw_clks = {
|
|||
[CLK_EXT_OSC32K_GATE] = &ext_osc32k_gate_clk.common.hw,
|
||||
[CLK_OSC24M_32K] = &osc24M_32k_clk.common.hw,
|
||||
[CLK_RTC_32K] = &rtc_32k_clk.common.hw,
|
||||
[CLK_OSC24M_32K_DIV] = &osc24M_32k_div_clk.hw,
|
||||
[CLK_HOSC_UFS] = &hosc_ufs_clk.common.hw,
|
||||
[CLK_HOSC_HDMI] = &hosc_hdmi_clk.common.hw,
|
||||
[CLK_HOSC_SERDES0] = &hosc_serdes0_clk.common.hw,
|
||||
[CLK_HOSC_SERDES1] = &hosc_serdes1_clk.common.hw,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -332,6 +381,15 @@ static const struct sun6i_rtc_match_data sun55i_a523_rtc_ccu_data = {
|
|||
.osc32k_fanout_nparents = ARRAY_SIZE(sun50i_r329_osc32k_fanout_parents),
|
||||
};
|
||||
|
||||
static const struct sun6i_rtc_match_data sun60i_a733_rtc_ccu_data = {
|
||||
.have_ext_osc32k = true,
|
||||
.have_iosc_calibration = true,
|
||||
.have_dcxo_status = true,
|
||||
.have_phy_ref_gates = true,
|
||||
.osc32k_fanout_parents = sun50i_r329_osc32k_fanout_parents,
|
||||
.osc32k_fanout_nparents = ARRAY_SIZE(sun50i_r329_osc32k_fanout_parents),
|
||||
};
|
||||
|
||||
static const struct of_device_id sun6i_rtc_ccu_match[] = {
|
||||
{
|
||||
.compatible = "allwinner,sun50i-h616-rtc",
|
||||
|
|
@ -345,6 +403,10 @@ static const struct of_device_id sun6i_rtc_ccu_match[] = {
|
|||
.compatible = "allwinner,sun55i-a523-rtc",
|
||||
.data = &sun55i_a523_rtc_ccu_data,
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun60i-a733-rtc",
|
||||
.data = &sun60i_a733_rtc_ccu_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun6i_rtc_ccu_match);
|
||||
|
|
@ -352,7 +414,6 @@ MODULE_DEVICE_TABLE(of, sun6i_rtc_ccu_match);
|
|||
int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
|
||||
{
|
||||
const struct sun6i_rtc_match_data *data;
|
||||
struct clk *ext_osc32k_clk = NULL;
|
||||
const struct of_device_id *match;
|
||||
|
||||
/* This driver is only used for newer variants of the hardware. */
|
||||
|
|
@ -361,23 +422,12 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
|
|||
return 0;
|
||||
|
||||
data = match->data;
|
||||
have_iosc_calibration = data->have_iosc_calibration;
|
||||
|
||||
if (data->have_ext_osc32k) {
|
||||
const char *fw_name;
|
||||
|
||||
/* ext-osc32k was the only input clock in the old binding. */
|
||||
fw_name = of_property_present(dev->of_node, "clock-names")
|
||||
? "ext-osc32k" : NULL;
|
||||
ext_osc32k_clk = devm_clk_get_optional(dev, fw_name);
|
||||
if (IS_ERR(ext_osc32k_clk))
|
||||
return PTR_ERR(ext_osc32k_clk);
|
||||
if (data->have_iosc_calibration) {
|
||||
iosc_clk.features |= CCU_FEATURE_IOSC_CALIBRATION;
|
||||
iosc_32k_clk.features |= CCU_FEATURE_IOSC_CALIBRATION;
|
||||
}
|
||||
|
||||
if (ext_osc32k_clk) {
|
||||
/* Link ext-osc32k-gate to its parent. */
|
||||
*ext_osc32k = __clk_get_hw(ext_osc32k_clk);
|
||||
} else {
|
||||
if (!data->have_ext_osc32k) {
|
||||
/* ext-osc32k-gate is an orphan, so do not register it. */
|
||||
sun6i_rtc_ccu_hw_clks.hws[CLK_EXT_OSC32K_GATE] = NULL;
|
||||
osc32k_init_data.num_parents = 1;
|
||||
|
|
@ -389,6 +439,13 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg)
|
|||
osc32k_fanout_init_data.parent_data = data->osc32k_fanout_parents;
|
||||
osc32k_fanout_init_data.num_parents = data->osc32k_fanout_nparents;
|
||||
|
||||
if (data->have_dcxo_status)
|
||||
sun6i_rtc_ccu_hw_clks.hws[CLK_OSC24M_32K_DIV] =
|
||||
&osc24M_32k_div_a733_clk.common.hw;
|
||||
|
||||
if (!data->have_phy_ref_gates)
|
||||
sun6i_rtc_ccu_hw_clks.num = CLK_NUMBER_NO_GATES;
|
||||
|
||||
return devm_sunxi_ccu_probe(dev, reg, &sun6i_rtc_ccu_desc);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
#define CLK_EXT_OSC32K_GATE 4
|
||||
#define CLK_OSC24M_32K 5
|
||||
#define CLK_RTC_32K 6
|
||||
#define CLK_OSC24M_32K_DIV 7
|
||||
|
||||
#define CLK_NUMBER (CLK_RTC_32K + 1)
|
||||
#define CLK_NUMBER (CLK_HOSC_SERDES1 + 1)
|
||||
|
||||
#endif /* _CCU_SUN6I_RTC_H */
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
|
|||
const struct sunxi_ccu_desc *desc)
|
||||
{
|
||||
struct ccu_reset *reset;
|
||||
int i, ret;
|
||||
int i, j, ret;
|
||||
|
||||
ccu->desc = desc;
|
||||
|
||||
|
|
@ -130,8 +130,8 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
|
|||
cclk->lock = &ccu->lock;
|
||||
}
|
||||
|
||||
for (i = 0; i < desc->hw_clks->num ; i++) {
|
||||
struct clk_hw *hw = desc->hw_clks->hws[i];
|
||||
for (j = 0; j < desc->hw_clks->num ; j++) {
|
||||
struct clk_hw *hw = desc->hw_clks->hws[j];
|
||||
const char *name;
|
||||
|
||||
if (!hw)
|
||||
|
|
@ -143,7 +143,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
|
|||
else
|
||||
ret = of_clk_hw_register(node, hw);
|
||||
if (ret) {
|
||||
pr_err("Couldn't register clock %d - %s\n", i, name);
|
||||
pr_err("Couldn't register clock %d - %s\n", j, name);
|
||||
goto err_clk_unreg;
|
||||
}
|
||||
}
|
||||
|
|
@ -186,8 +186,8 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
|
|||
err_del_provider:
|
||||
of_clk_del_provider(node);
|
||||
err_clk_unreg:
|
||||
while (--i >= 0) {
|
||||
struct clk_hw *hw = desc->hw_clks->hws[i];
|
||||
while (--j >= 0) {
|
||||
struct clk_hw *hw = desc->hw_clks->hws[j];
|
||||
|
||||
if (!hw)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#define CCU_FEATURE_CLOSEST_RATE BIT(9)
|
||||
#define CCU_FEATURE_DUAL_DIV BIT(10)
|
||||
#define CCU_FEATURE_UPDATE_BIT BIT(11)
|
||||
#define CCU_FEATURE_IOSC_CALIBRATION BIT(12)
|
||||
|
||||
/* MMC timing mode switch bit */
|
||||
#define CCU_MMC_NEW_TIMING_MODE BIT(30)
|
||||
|
|
|
|||
|
|
@ -20,8 +20,22 @@ static int ccu_div_determine_rate_helper(struct ccu_mux_internal *mux,
|
|||
if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
|
||||
req->rate *= cd->fixed_post_div;
|
||||
|
||||
ret = divider_determine_rate(&cd->common.hw, req, cd->div.table,
|
||||
cd->div.width, cd->div.flags);
|
||||
if (cd->div.flags & CLK_DIVIDER_READ_ONLY) {
|
||||
unsigned long val;
|
||||
u32 reg;
|
||||
|
||||
reg = readl(cd->common.base + cd->common.reg);
|
||||
val = reg >> cd->div.shift;
|
||||
val &= (1 << cd->div.width) - 1;
|
||||
|
||||
ret = divider_ro_determine_rate(&cd->common.hw, req, cd->div.table,
|
||||
cd->div.width, cd->div.flags, val);
|
||||
|
||||
} else {
|
||||
ret = divider_determine_rate(&cd->common.hw, req, cd->div.table,
|
||||
cd->div.width, cd->div.flags);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -143,3 +157,16 @@ const struct clk_ops ccu_div_ops = {
|
|||
.set_rate = ccu_div_set_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU");
|
||||
|
||||
const struct clk_ops ccu_rodiv_ops = {
|
||||
.disable = ccu_div_disable,
|
||||
.enable = ccu_div_enable,
|
||||
.is_enabled = ccu_div_is_enabled,
|
||||
|
||||
.get_parent = ccu_div_get_parent,
|
||||
.set_parent = ccu_div_set_parent,
|
||||
|
||||
.determine_rate = ccu_div_determine_rate,
|
||||
.recalc_rate = ccu_div_recalc_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(ccu_rodiv_ops, "SUNXI_CCU");
|
||||
|
|
|
|||
|
|
@ -300,5 +300,6 @@ static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw)
|
|||
}
|
||||
|
||||
extern const struct clk_ops ccu_div_ops;
|
||||
extern const struct clk_ops ccu_rodiv_ops;
|
||||
|
||||
#endif /* _CCU_DIV_H_ */
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common,
|
|||
{
|
||||
return parent_rate / ccu_mux_get_prediv(common, cm, parent_index);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_apply_prediv, "SUNXI_CCU");
|
||||
|
||||
static unsigned long ccu_mux_helper_unapply_prediv(struct ccu_common *common,
|
||||
struct ccu_mux_internal *cm,
|
||||
|
|
@ -93,66 +92,65 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common,
|
|||
struct clk_rate_request adj_req = *req;
|
||||
|
||||
best_parent = clk_hw_get_parent(hw);
|
||||
best_parent_rate = clk_hw_get_rate(best_parent);
|
||||
|
||||
adj_req.best_parent_rate = clk_hw_get_rate(best_parent);
|
||||
adj_req.best_parent_hw = best_parent;
|
||||
adj_req.best_parent_rate = ccu_mux_helper_apply_prediv(common, cm, -1,
|
||||
best_parent_rate);
|
||||
|
||||
/*
|
||||
* This effectively treats the predivider as a postdivider.
|
||||
* It stays mathematically correct and ensures whatever
|
||||
* round() will do stays correct while walking the tree.
|
||||
* It may query the parent rate too while handling rate
|
||||
* propagation.
|
||||
*/
|
||||
adj_req.rate = ccu_mux_helper_unapply_prediv(common, cm, -1,
|
||||
req->rate);
|
||||
|
||||
ret = round(cm, &adj_req, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
best_rate = adj_req.rate;
|
||||
|
||||
/*
|
||||
* best_parent_rate might have been modified by our clock.
|
||||
* Unapply the pre-divider if there's one, and give
|
||||
* the actual frequency the parent needs to run at.
|
||||
* parent_rate might have been modified by our clock as part
|
||||
* of the rate propagation mechanism. Same goes below.
|
||||
*/
|
||||
best_parent_rate = ccu_mux_helper_unapply_prediv(common, cm, -1,
|
||||
adj_req.best_parent_rate);
|
||||
best_parent_rate = adj_req.best_parent_rate;
|
||||
best_rate = ccu_mux_helper_apply_prediv(common, cm, -1,
|
||||
adj_req.rate);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
struct clk_rate_request tmp_req = *req;
|
||||
unsigned long parent_rate;
|
||||
unsigned long rate;
|
||||
struct clk_hw *parent;
|
||||
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
parent_rate = ccu_mux_helper_apply_prediv(common, cm, i,
|
||||
clk_hw_get_rate(parent));
|
||||
|
||||
tmp_req.best_parent_hw = parent;
|
||||
tmp_req.best_parent_rate = parent_rate;
|
||||
tmp_req.best_parent_rate = clk_hw_get_rate(parent);
|
||||
tmp_req.rate = ccu_mux_helper_unapply_prediv(common, cm, i,
|
||||
req->rate);
|
||||
|
||||
ret = round(cm, &tmp_req, data);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* parent_rate might have been modified by our clock.
|
||||
* Unapply the pre-divider if there's one, and give
|
||||
* the actual frequency the parent needs to run at.
|
||||
*/
|
||||
parent_rate = ccu_mux_helper_unapply_prediv(common, cm, i,
|
||||
tmp_req.best_parent_rate);
|
||||
rate = ccu_mux_helper_apply_prediv(common, cm, i,
|
||||
tmp_req.rate);
|
||||
|
||||
if (tmp_req.rate == req->rate) {
|
||||
if (rate == req->rate) {
|
||||
best_parent = parent;
|
||||
best_parent_rate = parent_rate;
|
||||
best_rate = tmp_req.rate;
|
||||
best_parent_rate = tmp_req.best_parent_rate;
|
||||
best_rate = rate;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ccu_is_better_rate(common, req->rate, tmp_req.rate, best_rate)) {
|
||||
best_rate = tmp_req.rate;
|
||||
best_parent_rate = parent_rate;
|
||||
if (ccu_is_better_rate(common, req->rate, rate, best_rate)) {
|
||||
best_rate = rate;
|
||||
best_parent_rate = tmp_req.best_parent_rate;
|
||||
best_parent = parent;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,9 @@
|
|||
#define CLK_OSC32K 0
|
||||
#define CLK_OSC32K_FANOUT 1
|
||||
#define CLK_IOSC 2
|
||||
#define CLK_HOSC_UFS 8
|
||||
#define CLK_HOSC_HDMI 9
|
||||
#define CLK_HOSC_SERDES0 10
|
||||
#define CLK_HOSC_SERDES1 11
|
||||
|
||||
#endif /* _DT_BINDINGS_CLK_SUN6I_RTC_H_ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user