14116076eSJosh Cartwright /* 24116076eSJosh Cartwright * Copyright (c) 2014, The Linux Foundation. All rights reserved. 34116076eSJosh Cartwright * 44116076eSJosh Cartwright * This software is licensed under the terms of the GNU General Public 54116076eSJosh Cartwright * License version 2, as published by the Free Software Foundation, and 64116076eSJosh Cartwright * may be copied, distributed, and modified under those terms. 74116076eSJosh Cartwright * 84116076eSJosh Cartwright * This program is distributed in the hope that it will be useful, 94116076eSJosh Cartwright * but WITHOUT ANY WARRANTY; without even the implied warranty of 104116076eSJosh Cartwright * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 114116076eSJosh Cartwright * GNU General Public License for more details. 124116076eSJosh Cartwright */ 134116076eSJosh Cartwright 144116076eSJosh Cartwright #include <linux/kernel.h> 154116076eSJosh Cartwright #include <linux/bitops.h> 164116076eSJosh Cartwright #include <linux/regmap.h> 174116076eSJosh Cartwright #include <linux/export.h> 184116076eSJosh Cartwright 194116076eSJosh Cartwright #include "clk-regmap-divider.h" 204116076eSJosh Cartwright 214116076eSJosh Cartwright static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw) 224116076eSJosh Cartwright { 234116076eSJosh Cartwright return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr); 244116076eSJosh Cartwright } 254116076eSJosh Cartwright 26f933d383SAbhishek Sahu static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, 27f933d383SAbhishek Sahu unsigned long *prate) 28f933d383SAbhishek Sahu { 29f933d383SAbhishek Sahu struct clk_regmap_div *divider = to_clk_regmap_div(hw); 30f933d383SAbhishek Sahu struct clk_regmap *clkr = ÷r->clkr; 31*f5edaefeSJerome Brunet u32 val; 32f933d383SAbhishek Sahu 33*f5edaefeSJerome Brunet regmap_read(clkr->regmap, divider->reg, &val); 34*f5edaefeSJerome Brunet val >>= divider->shift; 35*f5edaefeSJerome Brunet val &= BIT(divider->width) - 1; 36f933d383SAbhishek Sahu 37*f5edaefeSJerome Brunet return divider_ro_round_rate(hw, rate, prate, NULL, divider->width, 38*f5edaefeSJerome Brunet CLK_DIVIDER_ROUND_CLOSEST, val); 39f933d383SAbhishek Sahu } 40f933d383SAbhishek Sahu 414116076eSJosh Cartwright static long div_round_rate(struct clk_hw *hw, unsigned long rate, 424116076eSJosh Cartwright unsigned long *prate) 434116076eSJosh Cartwright { 444116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 454116076eSJosh Cartwright 464116076eSJosh Cartwright return divider_round_rate(hw, rate, prate, NULL, divider->width, 474116076eSJosh Cartwright CLK_DIVIDER_ROUND_CLOSEST); 484116076eSJosh Cartwright } 494116076eSJosh Cartwright 504116076eSJosh Cartwright static int div_set_rate(struct clk_hw *hw, unsigned long rate, 514116076eSJosh Cartwright unsigned long parent_rate) 524116076eSJosh Cartwright { 534116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 544116076eSJosh Cartwright struct clk_regmap *clkr = ÷r->clkr; 554116076eSJosh Cartwright u32 div; 564116076eSJosh Cartwright 574116076eSJosh Cartwright div = divider_get_val(rate, parent_rate, NULL, divider->width, 584116076eSJosh Cartwright CLK_DIVIDER_ROUND_CLOSEST); 594116076eSJosh Cartwright 604116076eSJosh Cartwright return regmap_update_bits(clkr->regmap, divider->reg, 614116076eSJosh Cartwright (BIT(divider->width) - 1) << divider->shift, 624116076eSJosh Cartwright div << divider->shift); 634116076eSJosh Cartwright } 644116076eSJosh Cartwright 654116076eSJosh Cartwright static unsigned long div_recalc_rate(struct clk_hw *hw, 664116076eSJosh Cartwright unsigned long parent_rate) 674116076eSJosh Cartwright { 684116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 694116076eSJosh Cartwright struct clk_regmap *clkr = ÷r->clkr; 704116076eSJosh Cartwright u32 div; 714116076eSJosh Cartwright 724116076eSJosh Cartwright regmap_read(clkr->regmap, divider->reg, &div); 734116076eSJosh Cartwright div >>= divider->shift; 744116076eSJosh Cartwright div &= BIT(divider->width) - 1; 754116076eSJosh Cartwright 764116076eSJosh Cartwright return divider_recalc_rate(hw, parent_rate, div, NULL, 7712a26c29SJerome Brunet CLK_DIVIDER_ROUND_CLOSEST, divider->width); 784116076eSJosh Cartwright } 794116076eSJosh Cartwright 804116076eSJosh Cartwright const struct clk_ops clk_regmap_div_ops = { 814116076eSJosh Cartwright .round_rate = div_round_rate, 824116076eSJosh Cartwright .set_rate = div_set_rate, 834116076eSJosh Cartwright .recalc_rate = div_recalc_rate, 844116076eSJosh Cartwright }; 854116076eSJosh Cartwright EXPORT_SYMBOL_GPL(clk_regmap_div_ops); 86f933d383SAbhishek Sahu 87f933d383SAbhishek Sahu const struct clk_ops clk_regmap_div_ro_ops = { 88f933d383SAbhishek Sahu .round_rate = div_round_ro_rate, 89f933d383SAbhishek Sahu .recalc_rate = div_recalc_rate, 90f933d383SAbhishek Sahu }; 91f933d383SAbhishek Sahu EXPORT_SYMBOL_GPL(clk_regmap_div_ro_ops); 92