root/drivers/clk/hisilicon/clk-hisi-phase.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hisi_phase_regval_to_degrees
  2. hisi_clk_get_phase
  3. hisi_phase_degrees_to_regval
  4. hisi_clk_set_phase
  5. clk_register_hisi_phase

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2017 HiSilicon Technologies Co., Ltd.
   4  *
   5  * Simple HiSilicon phase clock implementation.
   6  */
   7 
   8 #include <linux/err.h>
   9 #include <linux/io.h>
  10 #include <linux/module.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/slab.h>
  13 
  14 #include "clk.h"
  15 
  16 struct clk_hisi_phase {
  17         struct clk_hw   hw;
  18         void __iomem    *reg;
  19         u32             *phase_degrees;
  20         u32             *phase_regvals;
  21         u8              phase_num;
  22         u32             mask;
  23         u8              shift;
  24         u8              flags;
  25         spinlock_t      *lock;
  26 };
  27 
  28 #define to_clk_hisi_phase(_hw) container_of(_hw, struct clk_hisi_phase, hw)
  29 
  30 static int hisi_phase_regval_to_degrees(struct clk_hisi_phase *phase,
  31                                         u32 regval)
  32 {
  33         int i;
  34 
  35         for (i = 0; i < phase->phase_num; i++)
  36                 if (phase->phase_regvals[i] == regval)
  37                         return phase->phase_degrees[i];
  38 
  39         return -EINVAL;
  40 }
  41 
  42 static int hisi_clk_get_phase(struct clk_hw *hw)
  43 {
  44         struct clk_hisi_phase *phase = to_clk_hisi_phase(hw);
  45         u32 regval;
  46 
  47         regval = readl(phase->reg);
  48         regval = (regval & phase->mask) >> phase->shift;
  49 
  50         return hisi_phase_regval_to_degrees(phase, regval);
  51 }
  52 
  53 static int hisi_phase_degrees_to_regval(struct clk_hisi_phase *phase,
  54                                         int degrees)
  55 {
  56         int i;
  57 
  58         for (i = 0; i < phase->phase_num; i++)
  59                 if (phase->phase_degrees[i] == degrees)
  60                         return phase->phase_regvals[i];
  61 
  62         return -EINVAL;
  63 }
  64 
  65 static int hisi_clk_set_phase(struct clk_hw *hw, int degrees)
  66 {
  67         struct clk_hisi_phase *phase = to_clk_hisi_phase(hw);
  68         unsigned long flags = 0;
  69         int regval;
  70         u32 val;
  71 
  72         regval = hisi_phase_degrees_to_regval(phase, degrees);
  73         if (regval < 0)
  74                 return regval;
  75 
  76         spin_lock_irqsave(phase->lock, flags);
  77 
  78         val = readl(phase->reg);
  79         val &= ~phase->mask;
  80         val |= regval << phase->shift;
  81         writel(val, phase->reg);
  82 
  83         spin_unlock_irqrestore(phase->lock, flags);
  84 
  85         return 0;
  86 }
  87 
  88 static const struct clk_ops clk_phase_ops = {
  89         .get_phase = hisi_clk_get_phase,
  90         .set_phase = hisi_clk_set_phase,
  91 };
  92 
  93 struct clk *clk_register_hisi_phase(struct device *dev,
  94                 const struct hisi_phase_clock *clks,
  95                 void __iomem *base, spinlock_t *lock)
  96 {
  97         struct clk_hisi_phase *phase;
  98         struct clk_init_data init;
  99 
 100         phase = devm_kzalloc(dev, sizeof(struct clk_hisi_phase), GFP_KERNEL);
 101         if (!phase)
 102                 return ERR_PTR(-ENOMEM);
 103 
 104         init.name = clks->name;
 105         init.ops = &clk_phase_ops;
 106         init.flags = clks->flags;
 107         init.parent_names = clks->parent_names ? &clks->parent_names : NULL;
 108         init.num_parents = clks->parent_names ? 1 : 0;
 109 
 110         phase->reg = base + clks->offset;
 111         phase->shift = clks->shift;
 112         phase->mask = (BIT(clks->width) - 1) << clks->shift;
 113         phase->lock = lock;
 114         phase->phase_degrees = clks->phase_degrees;
 115         phase->phase_regvals = clks->phase_regvals;
 116         phase->phase_num = clks->phase_num;
 117         phase->hw.init = &init;
 118 
 119         return devm_clk_register(dev, &phase->hw);
 120 }
 121 EXPORT_SYMBOL_GPL(clk_register_hisi_phase);

/* [<][>][^][v][top][bottom][index][help] */