linux/drivers/clk/sunxi-ng/ccu_frac.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2016 Maxime Ripard
   4 * Maxime Ripard <maxime.ripard@free-electrons.com>
   5 */
   6
   7#include <linux/clk-provider.h>
   8#include <linux/io.h>
   9#include <linux/spinlock.h>
  10
  11#include "ccu_frac.h"
  12
  13bool ccu_frac_helper_is_enabled(struct ccu_common *common,
  14                                struct ccu_frac_internal *cf)
  15{
  16        if (!(common->features & CCU_FEATURE_FRACTIONAL))
  17                return false;
  18
  19        return !(readl(common->base + common->reg) & cf->enable);
  20}
  21
  22void ccu_frac_helper_enable(struct ccu_common *common,
  23                            struct ccu_frac_internal *cf)
  24{
  25        unsigned long flags;
  26        u32 reg;
  27
  28        if (!(common->features & CCU_FEATURE_FRACTIONAL))
  29                return;
  30
  31        spin_lock_irqsave(common->lock, flags);
  32        reg = readl(common->base + common->reg);
  33        writel(reg & ~cf->enable, common->base + common->reg);
  34        spin_unlock_irqrestore(common->lock, flags);
  35}
  36
  37void ccu_frac_helper_disable(struct ccu_common *common,
  38                             struct ccu_frac_internal *cf)
  39{
  40        unsigned long flags;
  41        u32 reg;
  42
  43        if (!(common->features & CCU_FEATURE_FRACTIONAL))
  44                return;
  45
  46        spin_lock_irqsave(common->lock, flags);
  47        reg = readl(common->base + common->reg);
  48        writel(reg | cf->enable, common->base + common->reg);
  49        spin_unlock_irqrestore(common->lock, flags);
  50}
  51
  52bool ccu_frac_helper_has_rate(struct ccu_common *common,
  53                              struct ccu_frac_internal *cf,
  54                              unsigned long rate)
  55{
  56        if (!(common->features & CCU_FEATURE_FRACTIONAL))
  57                return false;
  58
  59        return (cf->rates[0] == rate) || (cf->rates[1] == rate);
  60}
  61
  62unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
  63                                        struct ccu_frac_internal *cf)
  64{
  65        u32 reg;
  66
  67        pr_debug("%s: Read fractional\n", clk_hw_get_name(&common->hw));
  68
  69        if (!(common->features & CCU_FEATURE_FRACTIONAL))
  70                return 0;
  71
  72        pr_debug("%s: clock is fractional (rates %lu and %lu)\n",
  73                 clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
  74
  75        reg = readl(common->base + common->reg);
  76
  77        pr_debug("%s: clock reg is 0x%x (select is 0x%x)\n",
  78                 clk_hw_get_name(&common->hw), reg, cf->select);
  79
  80        return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
  81}
  82
  83int ccu_frac_helper_set_rate(struct ccu_common *common,
  84                             struct ccu_frac_internal *cf,
  85                             unsigned long rate, u32 lock)
  86{
  87        unsigned long flags;
  88        u32 reg, sel;
  89
  90        if (!(common->features & CCU_FEATURE_FRACTIONAL))
  91                return -EINVAL;
  92
  93        if (cf->rates[0] == rate)
  94                sel = 0;
  95        else if (cf->rates[1] == rate)
  96                sel = cf->select;
  97        else
  98                return -EINVAL;
  99
 100        spin_lock_irqsave(common->lock, flags);
 101        reg = readl(common->base + common->reg);
 102        reg &= ~cf->select;
 103        writel(reg | sel, common->base + common->reg);
 104        spin_unlock_irqrestore(common->lock, flags);
 105
 106        ccu_helper_wait_for_lock(common, lock);
 107
 108        return 0;
 109}
 110