root/drivers/clk/h8300/clk-h8s2678.c

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

DEFINITIONS

This source file includes following definitions.
  1. pll_recalc_rate
  2. pll_round_rate
  3. pll_set_rate
  4. h8s2678_pll_clk_setup

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * H8S2678 clock driver
   4  *
   5  * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
   6  */
   7 
   8 #include <linux/clk-provider.h>
   9 #include <linux/device.h>
  10 #include <linux/io.h>
  11 #include <linux/err.h>
  12 #include <linux/of_address.h>
  13 #include <linux/slab.h>
  14 
  15 static DEFINE_SPINLOCK(clklock);
  16 
  17 #define MAX_FREQ 33333333
  18 #define MIN_FREQ  8000000
  19 
  20 struct pll_clock {
  21         struct clk_hw hw;
  22         void __iomem *sckcr;
  23         void __iomem *pllcr;
  24 };
  25 
  26 #define to_pll_clock(_hw) container_of(_hw, struct pll_clock, hw)
  27 
  28 static unsigned long pll_recalc_rate(struct clk_hw *hw,
  29                 unsigned long parent_rate)
  30 {
  31         struct pll_clock *pll_clock = to_pll_clock(hw);
  32         int mul = 1 << (readb(pll_clock->pllcr) & 3);
  33 
  34         return parent_rate * mul;
  35 }
  36 
  37 static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
  38                                 unsigned long *prate)
  39 {
  40         int i, m = -1;
  41         long offset[3];
  42 
  43         if (rate > MAX_FREQ)
  44                 rate = MAX_FREQ;
  45         if (rate < MIN_FREQ)
  46                 rate = MIN_FREQ;
  47 
  48         for (i = 0; i < 3; i++)
  49                 offset[i] = abs(rate - (*prate * (1 << i)));
  50         for (i = 0; i < 3; i++)
  51                 if (m < 0)
  52                         m = i;
  53                 else
  54                         m = (offset[i] < offset[m])?i:m;
  55 
  56         return *prate * (1 << m);
  57 }
  58 
  59 static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
  60                         unsigned long parent_rate)
  61 {
  62         int pll;
  63         unsigned char val;
  64         unsigned long flags;
  65         struct pll_clock *pll_clock = to_pll_clock(hw);
  66 
  67         pll = ((rate / parent_rate) / 2) & 0x03;
  68         spin_lock_irqsave(&clklock, flags);
  69         val = readb(pll_clock->sckcr);
  70         val |= 0x08;
  71         writeb(val, pll_clock->sckcr);
  72         val = readb(pll_clock->pllcr);
  73         val &= ~0x03;
  74         val |= pll;
  75         writeb(val, pll_clock->pllcr);
  76         spin_unlock_irqrestore(&clklock, flags);
  77         return 0;
  78 }
  79 
  80 static const struct clk_ops pll_ops = {
  81         .recalc_rate = pll_recalc_rate,
  82         .round_rate = pll_round_rate,
  83         .set_rate = pll_set_rate,
  84 };
  85 
  86 static void __init h8s2678_pll_clk_setup(struct device_node *node)
  87 {
  88         unsigned int num_parents;
  89         const char *clk_name = node->name;
  90         const char *parent_name;
  91         struct pll_clock *pll_clock;
  92         struct clk_init_data init;
  93         int ret;
  94 
  95         num_parents = of_clk_get_parent_count(node);
  96         if (!num_parents) {
  97                 pr_err("%s: no parent found\n", clk_name);
  98                 return;
  99         }
 100 
 101 
 102         pll_clock = kzalloc(sizeof(*pll_clock), GFP_KERNEL);
 103         if (!pll_clock)
 104                 return;
 105 
 106         pll_clock->sckcr = of_iomap(node, 0);
 107         if (pll_clock->sckcr == NULL) {
 108                 pr_err("%s: failed to map divide register\n", clk_name);
 109                 goto free_clock;
 110         }
 111 
 112         pll_clock->pllcr = of_iomap(node, 1);
 113         if (pll_clock->pllcr == NULL) {
 114                 pr_err("%s: failed to map multiply register\n", clk_name);
 115                 goto unmap_sckcr;
 116         }
 117 
 118         parent_name = of_clk_get_parent_name(node, 0);
 119         init.name = clk_name;
 120         init.ops = &pll_ops;
 121         init.flags = 0;
 122         init.parent_names = &parent_name;
 123         init.num_parents = 1;
 124         pll_clock->hw.init = &init;
 125 
 126         ret = clk_hw_register(NULL, &pll_clock->hw);
 127         if (ret) {
 128                 pr_err("%s: failed to register %s div clock (%d)\n",
 129                        __func__, clk_name, ret);
 130                 goto unmap_pllcr;
 131         }
 132 
 133         of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clock->hw);
 134         return;
 135 
 136 unmap_pllcr:
 137         iounmap(pll_clock->pllcr);
 138 unmap_sckcr:
 139         iounmap(pll_clock->sckcr);
 140 free_clock:
 141         kfree(pll_clock);
 142 }
 143 
 144 CLK_OF_DECLARE(h8s2678_div_clk, "renesas,h8s2678-pll-clock",
 145                h8s2678_pll_clk_setup);

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