1*71ffeafbSRoman Beranek // SPDX-License-Identifier: GPL-2.0-or-later 2*71ffeafbSRoman Beranek /* 3*71ffeafbSRoman Beranek * Copyright (C) 2016 Free Electrons 4*71ffeafbSRoman Beranek * Copyright (C) 2016 NextThing Co 5*71ffeafbSRoman Beranek * 6*71ffeafbSRoman Beranek * Maxime Ripard <maxime.ripard@free-electrons.com> 7*71ffeafbSRoman Beranek */ 8*71ffeafbSRoman Beranek 9*71ffeafbSRoman Beranek #include <linux/clk-provider.h> 10*71ffeafbSRoman Beranek #include <linux/regmap.h> 11*71ffeafbSRoman Beranek 12*71ffeafbSRoman Beranek #include "sun4i_tcon.h" 13*71ffeafbSRoman Beranek #include "sun4i_tcon_dclk.h" 14*71ffeafbSRoman Beranek 15*71ffeafbSRoman Beranek struct sun4i_dclk { 16*71ffeafbSRoman Beranek struct clk_hw hw; 17*71ffeafbSRoman Beranek struct regmap *regmap; 18*71ffeafbSRoman Beranek struct sun4i_tcon *tcon; 19*71ffeafbSRoman Beranek }; 20*71ffeafbSRoman Beranek 21*71ffeafbSRoman Beranek static inline struct sun4i_dclk *hw_to_dclk(struct clk_hw *hw) 22*71ffeafbSRoman Beranek { 23*71ffeafbSRoman Beranek return container_of(hw, struct sun4i_dclk, hw); 24*71ffeafbSRoman Beranek } 25*71ffeafbSRoman Beranek 26*71ffeafbSRoman Beranek static void sun4i_dclk_disable(struct clk_hw *hw) 27*71ffeafbSRoman Beranek { 28*71ffeafbSRoman Beranek struct sun4i_dclk *dclk = hw_to_dclk(hw); 29*71ffeafbSRoman Beranek 30*71ffeafbSRoman Beranek regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG, 31*71ffeafbSRoman Beranek BIT(SUN4I_TCON0_DCLK_GATE_BIT), 0); 32*71ffeafbSRoman Beranek } 33*71ffeafbSRoman Beranek 34*71ffeafbSRoman Beranek static int sun4i_dclk_enable(struct clk_hw *hw) 35*71ffeafbSRoman Beranek { 36*71ffeafbSRoman Beranek struct sun4i_dclk *dclk = hw_to_dclk(hw); 37*71ffeafbSRoman Beranek 38*71ffeafbSRoman Beranek return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG, 39*71ffeafbSRoman Beranek BIT(SUN4I_TCON0_DCLK_GATE_BIT), 40*71ffeafbSRoman Beranek BIT(SUN4I_TCON0_DCLK_GATE_BIT)); 41*71ffeafbSRoman Beranek } 42*71ffeafbSRoman Beranek 43*71ffeafbSRoman Beranek static int sun4i_dclk_is_enabled(struct clk_hw *hw) 44*71ffeafbSRoman Beranek { 45*71ffeafbSRoman Beranek struct sun4i_dclk *dclk = hw_to_dclk(hw); 46*71ffeafbSRoman Beranek u32 val; 47*71ffeafbSRoman Beranek 48*71ffeafbSRoman Beranek regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val); 49*71ffeafbSRoman Beranek 50*71ffeafbSRoman Beranek return val & BIT(SUN4I_TCON0_DCLK_GATE_BIT); 51*71ffeafbSRoman Beranek } 52*71ffeafbSRoman Beranek 53*71ffeafbSRoman Beranek static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw, 54*71ffeafbSRoman Beranek unsigned long parent_rate) 55*71ffeafbSRoman Beranek { 56*71ffeafbSRoman Beranek struct sun4i_dclk *dclk = hw_to_dclk(hw); 57*71ffeafbSRoman Beranek u32 val; 58*71ffeafbSRoman Beranek 59*71ffeafbSRoman Beranek regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val); 60*71ffeafbSRoman Beranek 61*71ffeafbSRoman Beranek val >>= SUN4I_TCON0_DCLK_DIV_SHIFT; 62*71ffeafbSRoman Beranek val &= (1 << SUN4I_TCON0_DCLK_DIV_WIDTH) - 1; 63*71ffeafbSRoman Beranek 64*71ffeafbSRoman Beranek if (!val) 65*71ffeafbSRoman Beranek val = 1; 66*71ffeafbSRoman Beranek 67*71ffeafbSRoman Beranek return parent_rate / val; 68*71ffeafbSRoman Beranek } 69*71ffeafbSRoman Beranek 70*71ffeafbSRoman Beranek static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate, 71*71ffeafbSRoman Beranek unsigned long *parent_rate) 72*71ffeafbSRoman Beranek { 73*71ffeafbSRoman Beranek struct sun4i_dclk *dclk = hw_to_dclk(hw); 74*71ffeafbSRoman Beranek struct sun4i_tcon *tcon = dclk->tcon; 75*71ffeafbSRoman Beranek unsigned long best_parent = 0; 76*71ffeafbSRoman Beranek u8 best_div = 1; 77*71ffeafbSRoman Beranek int i; 78*71ffeafbSRoman Beranek 79*71ffeafbSRoman Beranek for (i = tcon->dclk_min_div; i <= tcon->dclk_max_div; i++) { 80*71ffeafbSRoman Beranek u64 ideal = (u64)rate * i; 81*71ffeafbSRoman Beranek unsigned long rounded; 82*71ffeafbSRoman Beranek 83*71ffeafbSRoman Beranek /* 84*71ffeafbSRoman Beranek * ideal has overflowed the max value that can be stored in an 85*71ffeafbSRoman Beranek * unsigned long, and every clk operation we might do on a 86*71ffeafbSRoman Beranek * truncated u64 value will give us incorrect results. 87*71ffeafbSRoman Beranek * Let's just stop there since bigger dividers will result in 88*71ffeafbSRoman Beranek * the same overflow issue. 89*71ffeafbSRoman Beranek */ 90*71ffeafbSRoman Beranek if (ideal > ULONG_MAX) 91*71ffeafbSRoman Beranek goto out; 92*71ffeafbSRoman Beranek 93*71ffeafbSRoman Beranek rounded = clk_hw_round_rate(clk_hw_get_parent(hw), 94*71ffeafbSRoman Beranek ideal); 95*71ffeafbSRoman Beranek 96*71ffeafbSRoman Beranek if (rounded == ideal) { 97*71ffeafbSRoman Beranek best_parent = rounded; 98*71ffeafbSRoman Beranek best_div = i; 99*71ffeafbSRoman Beranek goto out; 100*71ffeafbSRoman Beranek } 101*71ffeafbSRoman Beranek 102*71ffeafbSRoman Beranek if (abs(rate - rounded / i) < 103*71ffeafbSRoman Beranek abs(rate - best_parent / best_div)) { 104*71ffeafbSRoman Beranek best_parent = rounded; 105*71ffeafbSRoman Beranek best_div = i; 106*71ffeafbSRoman Beranek } 107*71ffeafbSRoman Beranek } 108*71ffeafbSRoman Beranek 109*71ffeafbSRoman Beranek out: 110*71ffeafbSRoman Beranek *parent_rate = best_parent; 111*71ffeafbSRoman Beranek 112*71ffeafbSRoman Beranek return best_parent / best_div; 113*71ffeafbSRoman Beranek } 114*71ffeafbSRoman Beranek 115*71ffeafbSRoman Beranek static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate, 116*71ffeafbSRoman Beranek unsigned long parent_rate) 117*71ffeafbSRoman Beranek { 118*71ffeafbSRoman Beranek struct sun4i_dclk *dclk = hw_to_dclk(hw); 119*71ffeafbSRoman Beranek u8 div = parent_rate / rate; 120*71ffeafbSRoman Beranek 121*71ffeafbSRoman Beranek return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG, 122*71ffeafbSRoman Beranek GENMASK(6, 0), div); 123*71ffeafbSRoman Beranek } 124*71ffeafbSRoman Beranek 125*71ffeafbSRoman Beranek static int sun4i_dclk_get_phase(struct clk_hw *hw) 126*71ffeafbSRoman Beranek { 127*71ffeafbSRoman Beranek struct sun4i_dclk *dclk = hw_to_dclk(hw); 128*71ffeafbSRoman Beranek u32 val; 129*71ffeafbSRoman Beranek 130*71ffeafbSRoman Beranek regmap_read(dclk->regmap, SUN4I_TCON0_IO_POL_REG, &val); 131*71ffeafbSRoman Beranek 132*71ffeafbSRoman Beranek val >>= 28; 133*71ffeafbSRoman Beranek val &= 3; 134*71ffeafbSRoman Beranek 135*71ffeafbSRoman Beranek return val * 120; 136*71ffeafbSRoman Beranek } 137*71ffeafbSRoman Beranek 138*71ffeafbSRoman Beranek static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) 139*71ffeafbSRoman Beranek { 140*71ffeafbSRoman Beranek struct sun4i_dclk *dclk = hw_to_dclk(hw); 141*71ffeafbSRoman Beranek u32 val = degrees / 120; 142*71ffeafbSRoman Beranek 143*71ffeafbSRoman Beranek val <<= 28; 144*71ffeafbSRoman Beranek 145*71ffeafbSRoman Beranek regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, 146*71ffeafbSRoman Beranek GENMASK(29, 28), 147*71ffeafbSRoman Beranek val); 148*71ffeafbSRoman Beranek 149*71ffeafbSRoman Beranek return 0; 150*71ffeafbSRoman Beranek } 151*71ffeafbSRoman Beranek 152*71ffeafbSRoman Beranek static const struct clk_ops sun4i_dclk_ops = { 153*71ffeafbSRoman Beranek .disable = sun4i_dclk_disable, 154*71ffeafbSRoman Beranek .enable = sun4i_dclk_enable, 155*71ffeafbSRoman Beranek .is_enabled = sun4i_dclk_is_enabled, 156*71ffeafbSRoman Beranek 157*71ffeafbSRoman Beranek .recalc_rate = sun4i_dclk_recalc_rate, 158*71ffeafbSRoman Beranek .round_rate = sun4i_dclk_round_rate, 159*71ffeafbSRoman Beranek .set_rate = sun4i_dclk_set_rate, 160*71ffeafbSRoman Beranek 161*71ffeafbSRoman Beranek .get_phase = sun4i_dclk_get_phase, 162*71ffeafbSRoman Beranek .set_phase = sun4i_dclk_set_phase, 163*71ffeafbSRoman Beranek }; 164*71ffeafbSRoman Beranek 165*71ffeafbSRoman Beranek int sun4i_dclk_create(struct device *dev, struct sun4i_tcon *tcon) 166*71ffeafbSRoman Beranek { 167*71ffeafbSRoman Beranek const char *clk_name, *parent_name; 168*71ffeafbSRoman Beranek struct clk_init_data init; 169*71ffeafbSRoman Beranek struct sun4i_dclk *dclk; 170*71ffeafbSRoman Beranek int ret; 171*71ffeafbSRoman Beranek 172*71ffeafbSRoman Beranek parent_name = __clk_get_name(tcon->sclk0); 173*71ffeafbSRoman Beranek ret = of_property_read_string_index(dev->of_node, 174*71ffeafbSRoman Beranek "clock-output-names", 0, 175*71ffeafbSRoman Beranek &clk_name); 176*71ffeafbSRoman Beranek if (ret) 177*71ffeafbSRoman Beranek return ret; 178*71ffeafbSRoman Beranek 179*71ffeafbSRoman Beranek dclk = devm_kzalloc(dev, sizeof(*dclk), GFP_KERNEL); 180*71ffeafbSRoman Beranek if (!dclk) 181*71ffeafbSRoman Beranek return -ENOMEM; 182*71ffeafbSRoman Beranek dclk->tcon = tcon; 183*71ffeafbSRoman Beranek 184*71ffeafbSRoman Beranek init.name = clk_name; 185*71ffeafbSRoman Beranek init.ops = &sun4i_dclk_ops; 186*71ffeafbSRoman Beranek init.parent_names = &parent_name; 187*71ffeafbSRoman Beranek init.num_parents = 1; 188*71ffeafbSRoman Beranek init.flags = CLK_SET_RATE_PARENT; 189*71ffeafbSRoman Beranek 190*71ffeafbSRoman Beranek dclk->regmap = tcon->regs; 191*71ffeafbSRoman Beranek dclk->hw.init = &init; 192*71ffeafbSRoman Beranek 193*71ffeafbSRoman Beranek tcon->dclk = clk_register(dev, &dclk->hw); 194*71ffeafbSRoman Beranek if (IS_ERR(tcon->dclk)) 195*71ffeafbSRoman Beranek return PTR_ERR(tcon->dclk); 196*71ffeafbSRoman Beranek 197*71ffeafbSRoman Beranek return 0; 198*71ffeafbSRoman Beranek } 199*71ffeafbSRoman Beranek EXPORT_SYMBOL(sun4i_dclk_create); 200*71ffeafbSRoman Beranek 201*71ffeafbSRoman Beranek int sun4i_dclk_free(struct sun4i_tcon *tcon) 202*71ffeafbSRoman Beranek { 203*71ffeafbSRoman Beranek clk_unregister(tcon->dclk); 204*71ffeafbSRoman Beranek return 0; 205*71ffeafbSRoman Beranek } 206*71ffeafbSRoman Beranek EXPORT_SYMBOL(sun4i_dclk_free); 207