1*4116076eSJosh Cartwright /* 2*4116076eSJosh Cartwright * Copyright (c) 2014, The Linux Foundation. All rights reserved. 3*4116076eSJosh Cartwright * 4*4116076eSJosh Cartwright * This software is licensed under the terms of the GNU General Public 5*4116076eSJosh Cartwright * License version 2, as published by the Free Software Foundation, and 6*4116076eSJosh Cartwright * may be copied, distributed, and modified under those terms. 7*4116076eSJosh Cartwright * 8*4116076eSJosh Cartwright * This program is distributed in the hope that it will be useful, 9*4116076eSJosh Cartwright * but WITHOUT ANY WARRANTY; without even the implied warranty of 10*4116076eSJosh Cartwright * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11*4116076eSJosh Cartwright * GNU General Public License for more details. 12*4116076eSJosh Cartwright */ 13*4116076eSJosh Cartwright 14*4116076eSJosh Cartwright #include <linux/kernel.h> 15*4116076eSJosh Cartwright #include <linux/bitops.h> 16*4116076eSJosh Cartwright #include <linux/regmap.h> 17*4116076eSJosh Cartwright #include <linux/export.h> 18*4116076eSJosh Cartwright 19*4116076eSJosh Cartwright #include "clk-regmap-divider.h" 20*4116076eSJosh Cartwright 21*4116076eSJosh Cartwright static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw) 22*4116076eSJosh Cartwright { 23*4116076eSJosh Cartwright return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr); 24*4116076eSJosh Cartwright } 25*4116076eSJosh Cartwright 26*4116076eSJosh Cartwright static long div_round_rate(struct clk_hw *hw, unsigned long rate, 27*4116076eSJosh Cartwright unsigned long *prate) 28*4116076eSJosh Cartwright { 29*4116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 30*4116076eSJosh Cartwright 31*4116076eSJosh Cartwright return divider_round_rate(hw, rate, prate, NULL, divider->width, 32*4116076eSJosh Cartwright CLK_DIVIDER_ROUND_CLOSEST); 33*4116076eSJosh Cartwright } 34*4116076eSJosh Cartwright 35*4116076eSJosh Cartwright static int div_set_rate(struct clk_hw *hw, unsigned long rate, 36*4116076eSJosh Cartwright unsigned long parent_rate) 37*4116076eSJosh Cartwright { 38*4116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 39*4116076eSJosh Cartwright struct clk_regmap *clkr = ÷r->clkr; 40*4116076eSJosh Cartwright u32 div; 41*4116076eSJosh Cartwright 42*4116076eSJosh Cartwright div = divider_get_val(rate, parent_rate, NULL, divider->width, 43*4116076eSJosh Cartwright CLK_DIVIDER_ROUND_CLOSEST); 44*4116076eSJosh Cartwright 45*4116076eSJosh Cartwright return regmap_update_bits(clkr->regmap, divider->reg, 46*4116076eSJosh Cartwright (BIT(divider->width) - 1) << divider->shift, 47*4116076eSJosh Cartwright div << divider->shift); 48*4116076eSJosh Cartwright } 49*4116076eSJosh Cartwright 50*4116076eSJosh Cartwright static unsigned long div_recalc_rate(struct clk_hw *hw, 51*4116076eSJosh Cartwright unsigned long parent_rate) 52*4116076eSJosh Cartwright { 53*4116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 54*4116076eSJosh Cartwright struct clk_regmap *clkr = ÷r->clkr; 55*4116076eSJosh Cartwright u32 div; 56*4116076eSJosh Cartwright 57*4116076eSJosh Cartwright regmap_read(clkr->regmap, divider->reg, &div); 58*4116076eSJosh Cartwright div >>= divider->shift; 59*4116076eSJosh Cartwright div &= BIT(divider->width) - 1; 60*4116076eSJosh Cartwright 61*4116076eSJosh Cartwright return divider_recalc_rate(hw, parent_rate, div, NULL, 62*4116076eSJosh Cartwright CLK_DIVIDER_ROUND_CLOSEST); 63*4116076eSJosh Cartwright } 64*4116076eSJosh Cartwright 65*4116076eSJosh Cartwright const struct clk_ops clk_regmap_div_ops = { 66*4116076eSJosh Cartwright .round_rate = div_round_rate, 67*4116076eSJosh Cartwright .set_rate = div_set_rate, 68*4116076eSJosh Cartwright .recalc_rate = div_recalc_rate, 69*4116076eSJosh Cartwright }; 70*4116076eSJosh Cartwright EXPORT_SYMBOL_GPL(clk_regmap_div_ops); 71