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