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