linux/drivers/clk/sprd/div.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Spreadtrum divider clock driver
   4//
   5// Copyright (C) 2017 Spreadtrum, Inc.
   6// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
   7
   8#include <linux/clk-provider.h>
   9
  10#include "div.h"
  11
  12long sprd_div_helper_round_rate(struct sprd_clk_common *common,
  13                                const struct sprd_div_internal *div,
  14                                unsigned long rate,
  15                                unsigned long *parent_rate)
  16{
  17        return divider_round_rate(&common->hw, rate, parent_rate,
  18                                  NULL, div->width, 0);
  19}
  20EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate);
  21
  22static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate,
  23                                unsigned long *parent_rate)
  24{
  25        struct sprd_div *cd = hw_to_sprd_div(hw);
  26
  27        return sprd_div_helper_round_rate(&cd->common, &cd->div,
  28                                          rate, parent_rate);
  29}
  30
  31unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common,
  32                                          const struct sprd_div_internal *div,
  33                                          unsigned long parent_rate)
  34{
  35        unsigned long val;
  36        unsigned int reg;
  37
  38        regmap_read(common->regmap, common->reg, &reg);
  39        val = reg >> div->shift;
  40        val &= (1 << div->width) - 1;
  41
  42        return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0,
  43                                   div->width);
  44}
  45EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate);
  46
  47static unsigned long sprd_div_recalc_rate(struct clk_hw *hw,
  48                                          unsigned long parent_rate)
  49{
  50        struct sprd_div *cd = hw_to_sprd_div(hw);
  51
  52        return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate);
  53}
  54
  55int sprd_div_helper_set_rate(const struct sprd_clk_common *common,
  56                             const struct sprd_div_internal *div,
  57                             unsigned long rate,
  58                             unsigned long parent_rate)
  59{
  60        unsigned long val;
  61        unsigned int reg;
  62
  63        val = divider_get_val(rate, parent_rate, NULL,
  64                              div->width, 0);
  65
  66        regmap_read(common->regmap, common->reg, &reg);
  67        reg &= ~GENMASK(div->width + div->shift - 1, div->shift);
  68
  69        regmap_write(common->regmap, common->reg,
  70                          reg | (val << div->shift));
  71
  72        return 0;
  73
  74}
  75EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate);
  76
  77static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate,
  78                             unsigned long parent_rate)
  79{
  80        struct sprd_div *cd = hw_to_sprd_div(hw);
  81
  82        return sprd_div_helper_set_rate(&cd->common, &cd->div,
  83                                        rate, parent_rate);
  84}
  85
  86const struct clk_ops sprd_div_ops = {
  87        .recalc_rate = sprd_div_recalc_rate,
  88        .round_rate = sprd_div_round_rate,
  89        .set_rate = sprd_div_set_rate,
  90};
  91EXPORT_SYMBOL_GPL(sprd_div_ops);
  92