root/drivers/clk/socfpga/clk-periph-s10.c

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

DEFINITIONS

This source file includes following definitions.
  1. clk_peri_c_clk_recalc_rate
  2. clk_peri_cnt_clk_recalc_rate
  3. clk_periclk_get_parent
  4. s10_register_periph
  5. s10_register_cnt_periph

   1 // SPDX-License-Identifier:     GPL-2.0
   2 /*
   3  * Copyright (C) 2017, Intel Corporation
   4  */
   5 #include <linux/slab.h>
   6 #include <linux/clk-provider.h>
   7 #include <linux/io.h>
   8 
   9 #include "stratix10-clk.h"
  10 #include "clk.h"
  11 
  12 #define CLK_MGR_FREE_SHIFT              16
  13 #define CLK_MGR_FREE_MASK               0x7
  14 #define SWCTRLBTCLKSEN_SHIFT            8
  15 
  16 #define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
  17 
  18 static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
  19                                              unsigned long parent_rate)
  20 {
  21         struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
  22         unsigned long div = 1;
  23         u32 val;
  24 
  25         val = readl(socfpgaclk->hw.reg);
  26         val &= GENMASK(SWCTRLBTCLKSEN_SHIFT - 1, 0);
  27         parent_rate /= val;
  28 
  29         return parent_rate / div;
  30 }
  31 
  32 static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
  33                                              unsigned long parent_rate)
  34 {
  35         struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
  36         unsigned long div = 1;
  37 
  38         if (socfpgaclk->fixed_div) {
  39                 div = socfpgaclk->fixed_div;
  40         } else {
  41                 if (socfpgaclk->hw.reg)
  42                         div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1);
  43         }
  44 
  45         return parent_rate / div;
  46 }
  47 
  48 static u8 clk_periclk_get_parent(struct clk_hw *hwclk)
  49 {
  50         struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
  51         u32 clk_src, mask;
  52         u8 parent;
  53 
  54         if (socfpgaclk->bypass_reg) {
  55                 mask = (0x1 << socfpgaclk->bypass_shift);
  56                 parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
  57                            socfpgaclk->bypass_shift);
  58         } else {
  59                 clk_src = readl(socfpgaclk->hw.reg);
  60                 parent = (clk_src >> CLK_MGR_FREE_SHIFT) &
  61                         CLK_MGR_FREE_MASK;
  62         }
  63         return parent;
  64 }
  65 
  66 static const struct clk_ops peri_c_clk_ops = {
  67         .recalc_rate = clk_peri_c_clk_recalc_rate,
  68         .get_parent = clk_periclk_get_parent,
  69 };
  70 
  71 static const struct clk_ops peri_cnt_clk_ops = {
  72         .recalc_rate = clk_peri_cnt_clk_recalc_rate,
  73         .get_parent = clk_periclk_get_parent,
  74 };
  75 
  76 struct clk *s10_register_periph(const char *name, const char *parent_name,
  77                                 const char * const *parent_names,
  78                                 u8 num_parents, unsigned long flags,
  79                                 void __iomem *reg, unsigned long offset)
  80 {
  81         struct clk *clk;
  82         struct socfpga_periph_clk *periph_clk;
  83         struct clk_init_data init;
  84 
  85         periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
  86         if (WARN_ON(!periph_clk))
  87                 return NULL;
  88 
  89         periph_clk->hw.reg = reg + offset;
  90 
  91         init.name = name;
  92         init.ops = &peri_c_clk_ops;
  93         init.flags = flags;
  94 
  95         init.num_parents = num_parents;
  96         init.parent_names = parent_names ? parent_names : &parent_name;
  97 
  98         periph_clk->hw.hw.init = &init;
  99 
 100         clk = clk_register(NULL, &periph_clk->hw.hw);
 101         if (WARN_ON(IS_ERR(clk))) {
 102                 kfree(periph_clk);
 103                 return NULL;
 104         }
 105         return clk;
 106 }
 107 
 108 struct clk *s10_register_cnt_periph(const char *name, const char *parent_name,
 109                                     const char * const *parent_names,
 110                                     u8 num_parents, unsigned long flags,
 111                                     void __iomem *regbase, unsigned long offset,
 112                                     u8 fixed_divider, unsigned long bypass_reg,
 113                                     unsigned long bypass_shift)
 114 {
 115         struct clk *clk;
 116         struct socfpga_periph_clk *periph_clk;
 117         struct clk_init_data init;
 118 
 119         periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
 120         if (WARN_ON(!periph_clk))
 121                 return NULL;
 122 
 123         if (offset)
 124                 periph_clk->hw.reg = regbase + offset;
 125         else
 126                 periph_clk->hw.reg = NULL;
 127 
 128         if (bypass_reg)
 129                 periph_clk->bypass_reg = regbase + bypass_reg;
 130         else
 131                 periph_clk->bypass_reg = NULL;
 132         periph_clk->bypass_shift = bypass_shift;
 133         periph_clk->fixed_div = fixed_divider;
 134 
 135         init.name = name;
 136         init.ops = &peri_cnt_clk_ops;
 137         init.flags = flags;
 138 
 139         init.num_parents = num_parents;
 140         init.parent_names = parent_names ? parent_names : &parent_name;
 141 
 142         periph_clk->hw.hw.init = &init;
 143 
 144         clk = clk_register(NULL, &periph_clk->hw.hw);
 145         if (WARN_ON(IS_ERR(clk))) {
 146                 kfree(periph_clk);
 147                 return NULL;
 148         }
 149         return clk;
 150 }

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