root/drivers/clk/imx/clk-pfd.c

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

DEFINITIONS

This source file includes following definitions.
  1. clk_pfd_enable
  2. clk_pfd_disable
  3. clk_pfd_recalc_rate
  4. clk_pfd_round_rate
  5. clk_pfd_set_rate
  6. clk_pfd_is_enabled
  7. imx_clk_hw_pfd

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2012 Freescale Semiconductor, Inc.
   4  * Copyright 2012 Linaro Ltd.
   5  */
   6 
   7 #include <linux/clk-provider.h>
   8 #include <linux/io.h>
   9 #include <linux/slab.h>
  10 #include <linux/err.h>
  11 #include "clk.h"
  12 
  13 /**
  14  * struct clk_pfd - IMX PFD clock
  15  * @clk_hw:     clock source
  16  * @reg:        PFD register address
  17  * @idx:        the index of PFD encoded in the register
  18  *
  19  * PFD clock found on i.MX6 series.  Each register for PFD has 4 clk_pfd
  20  * data encoded, and member idx is used to specify the one.  And each
  21  * register has SET, CLR and TOG registers at offset 0x4 0x8 and 0xc.
  22  */
  23 struct clk_pfd {
  24         struct clk_hw   hw;
  25         void __iomem    *reg;
  26         u8              idx;
  27 };
  28 
  29 #define to_clk_pfd(_hw) container_of(_hw, struct clk_pfd, hw)
  30 
  31 #define SET     0x4
  32 #define CLR     0x8
  33 #define OTG     0xc
  34 
  35 static int clk_pfd_enable(struct clk_hw *hw)
  36 {
  37         struct clk_pfd *pfd = to_clk_pfd(hw);
  38 
  39         writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
  40 
  41         return 0;
  42 }
  43 
  44 static void clk_pfd_disable(struct clk_hw *hw)
  45 {
  46         struct clk_pfd *pfd = to_clk_pfd(hw);
  47 
  48         writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
  49 }
  50 
  51 static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw,
  52                                          unsigned long parent_rate)
  53 {
  54         struct clk_pfd *pfd = to_clk_pfd(hw);
  55         u64 tmp = parent_rate;
  56         u8 frac = (readl_relaxed(pfd->reg) >> (pfd->idx * 8)) & 0x3f;
  57 
  58         tmp *= 18;
  59         do_div(tmp, frac);
  60 
  61         return tmp;
  62 }
  63 
  64 static long clk_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
  65                                unsigned long *prate)
  66 {
  67         u64 tmp = *prate;
  68         u8 frac;
  69 
  70         tmp = tmp * 18 + rate / 2;
  71         do_div(tmp, rate);
  72         frac = tmp;
  73         if (frac < 12)
  74                 frac = 12;
  75         else if (frac > 35)
  76                 frac = 35;
  77         tmp = *prate;
  78         tmp *= 18;
  79         do_div(tmp, frac);
  80 
  81         return tmp;
  82 }
  83 
  84 static int clk_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
  85                 unsigned long parent_rate)
  86 {
  87         struct clk_pfd *pfd = to_clk_pfd(hw);
  88         u64 tmp = parent_rate;
  89         u8 frac;
  90 
  91         tmp = tmp * 18 + rate / 2;
  92         do_div(tmp, rate);
  93         frac = tmp;
  94         if (frac < 12)
  95                 frac = 12;
  96         else if (frac > 35)
  97                 frac = 35;
  98 
  99         writel_relaxed(0x3f << (pfd->idx * 8), pfd->reg + CLR);
 100         writel_relaxed(frac << (pfd->idx * 8), pfd->reg + SET);
 101 
 102         return 0;
 103 }
 104 
 105 static int clk_pfd_is_enabled(struct clk_hw *hw)
 106 {
 107         struct clk_pfd *pfd = to_clk_pfd(hw);
 108 
 109         if (readl_relaxed(pfd->reg) & (1 << ((pfd->idx + 1) * 8 - 1)))
 110                 return 0;
 111 
 112         return 1;
 113 }
 114 
 115 static const struct clk_ops clk_pfd_ops = {
 116         .enable         = clk_pfd_enable,
 117         .disable        = clk_pfd_disable,
 118         .recalc_rate    = clk_pfd_recalc_rate,
 119         .round_rate     = clk_pfd_round_rate,
 120         .set_rate       = clk_pfd_set_rate,
 121         .is_enabled     = clk_pfd_is_enabled,
 122 };
 123 
 124 struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
 125                         void __iomem *reg, u8 idx)
 126 {
 127         struct clk_pfd *pfd;
 128         struct clk_hw *hw;
 129         struct clk_init_data init;
 130         int ret;
 131 
 132         pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
 133         if (!pfd)
 134                 return ERR_PTR(-ENOMEM);
 135 
 136         pfd->reg = reg;
 137         pfd->idx = idx;
 138 
 139         init.name = name;
 140         init.ops = &clk_pfd_ops;
 141         init.flags = 0;
 142         init.parent_names = &parent_name;
 143         init.num_parents = 1;
 144 
 145         pfd->hw.init = &init;
 146         hw = &pfd->hw;
 147 
 148         ret = clk_hw_register(NULL, hw);
 149         if (ret) {
 150                 kfree(pfd);
 151                 return ERR_PTR(ret);
 152         }
 153 
 154         return hw;
 155 }

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