linux/drivers/clk/qcom/clk-regmap-divider.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/bitops.h>
   8#include <linux/regmap.h>
   9#include <linux/export.h>
  10
  11#include "clk-regmap-divider.h"
  12
  13static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw)
  14{
  15        return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr);
  16}
  17
  18static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate,
  19                              unsigned long *prate)
  20{
  21        struct clk_regmap_div *divider = to_clk_regmap_div(hw);
  22        struct clk_regmap *clkr = &divider->clkr;
  23        u32 val;
  24
  25        regmap_read(clkr->regmap, divider->reg, &val);
  26        val >>= divider->shift;
  27        val &= BIT(divider->width) - 1;
  28
  29        return divider_ro_round_rate(hw, rate, prate, NULL, divider->width,
  30                                     CLK_DIVIDER_ROUND_CLOSEST, val);
  31}
  32
  33static long div_round_rate(struct clk_hw *hw, unsigned long rate,
  34                           unsigned long *prate)
  35{
  36        struct clk_regmap_div *divider = to_clk_regmap_div(hw);
  37
  38        return divider_round_rate(hw, rate, prate, NULL, divider->width,
  39                                  CLK_DIVIDER_ROUND_CLOSEST);
  40}
  41
  42static int div_set_rate(struct clk_hw *hw, unsigned long rate,
  43                        unsigned long parent_rate)
  44{
  45        struct clk_regmap_div *divider = to_clk_regmap_div(hw);
  46        struct clk_regmap *clkr = &divider->clkr;
  47        u32 div;
  48
  49        div = divider_get_val(rate, parent_rate, NULL, divider->width,
  50                              CLK_DIVIDER_ROUND_CLOSEST);
  51
  52        return regmap_update_bits(clkr->regmap, divider->reg,
  53                                  (BIT(divider->width) - 1) << divider->shift,
  54                                  div << divider->shift);
  55}
  56
  57static unsigned long div_recalc_rate(struct clk_hw *hw,
  58                                     unsigned long parent_rate)
  59{
  60        struct clk_regmap_div *divider = to_clk_regmap_div(hw);
  61        struct clk_regmap *clkr = &divider->clkr;
  62        u32 div;
  63
  64        regmap_read(clkr->regmap, divider->reg, &div);
  65        div >>= divider->shift;
  66        div &= BIT(divider->width) - 1;
  67
  68        return divider_recalc_rate(hw, parent_rate, div, NULL,
  69                                   CLK_DIVIDER_ROUND_CLOSEST, divider->width);
  70}
  71
  72const struct clk_ops clk_regmap_div_ops = {
  73        .round_rate = div_round_rate,
  74        .set_rate = div_set_rate,
  75        .recalc_rate = div_recalc_rate,
  76};
  77EXPORT_SYMBOL_GPL(clk_regmap_div_ops);
  78
  79const struct clk_ops clk_regmap_div_ro_ops = {
  80        .round_rate = div_round_ro_rate,
  81        .recalc_rate = div_recalc_rate,
  82};
  83EXPORT_SYMBOL_GPL(clk_regmap_div_ro_ops);
  84